【问题标题】:Use GPU in Visual Stduio C# for image comparison在 Visual Studio C# 中使用 GPU 进行图像比较
【发布时间】:2018-09-19 10:37:02
【问题描述】:

我是图像处理的新手。我有一部分图像,我必须通过比较像素在整个图像中进行搜索。我需要获取完整图像中存在的小图像的坐标。

所以,我在做

for int i = 0 to Complete_Image.Lenght
 for int j = 0 to Complete_Image.Height
  for int x = 0 to Small_Image.Lenght
   for int y = 0 to Small_Image.Height
    if Complete_Image[i+j+x][i+j+y] == Small_Image[x][y]
     Message "image found at coordinate x, y"
     Break

它是一种简单的像素匹配算法,通过比较像素在完整图像中找到图像的某一部分。

这非常耗时。例如,如果我必须在 1000 X 1000 图像中找到 50X50 图像的坐标,则需要进行 1000 X 1000 X 50 X 50 像素的颜色比较。

所以:

  • 有没有更好的方法在 C# 中进行图像比较?
  • 我可以使用 AMD Radeon 460 GPU 并行地做这个比较吗?或者至少部分算法使用了 GPU 能力?

【问题讨论】:

  • 即使没有 GPU,您也可以达到闪电般的速度。通过使用一些智能、固定内存、指针访问和并行处理。不管gpu与否,你如何做这将加快它的速度。你当前的算法时间复杂度大,效率低
  • 两张图像的像素多久完全匹配?您确定这是您想要的搜索类型吗?
  • 只有一个完全匹配。我有一部分屏幕截图,我必须在完整的屏幕截图中找到它并获取它的坐标。只有一个完全匹配。是否有更好的算法和/或 GPU 处理?
  • 显然 gpu 会更快,这取决于你想走多快,对于 5000*3000 图像寻找 300*300 图像,我在 10 分之一秒内得到它,在非 gpu 中没有并行.,与原始算法相反,其运行时间约为 10 秒。但是我只是在调整一个并行版本,所以我应该能够再次更快地获得它

标签: c# visual-studio opencl gpu


【解决方案1】:

反正我已经没时间了,也许以后可以完成并行版本。

前提是被动遍历子图像,如果找到全线像素匹配,则执行子循环来比较整个子图像

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CheckSubImage(int* m0, int* s0, Rectangle mR, Rectangle sR, int x, int y, out Point? result)
{

   result = null;
   for (int sX = 0, mX = x; sX < sR.Width && mX < mR.Right; sX++, mX++)
      for (int sY = 0, mY = y; sY < sR.Height && mY < mR.Bottom; sY++, mY++)
         if (*(m0 + mX + mY * mR.Width) != *(s0 + sX + sY * sR.Width))
            return false;

   result = new Point(x, y);
   return true;
}

protected override Point? GetPoint(string main, string sub)
{
   using (Bitmap m = new Bitmap(main), s = new Bitmap(sub))
   {
      Rectangle mR = new Rectangle(Point.Empty, m.Size), sR = new Rectangle(Point.Empty, s.Size);

      var mD = m.LockBits(mR, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
      var sD = s.LockBits(sR, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);

      int* m0 = (int*)mD.Scan0, s0 = (int*)sD.Scan0;

      for (var x = mR.Left; x < mR.Right; x++)
         for (var y = mR.Top; y < mR.Bottom; y++)
            if (*(m0 + x + y * mR.Width) == *s0)
               if (CheckSubImage(m0, s0, mR, sR, x, y, out var result))
                  return result;

      m.UnlockBits(mD);
      s.UnlockBits(sD);
   }

   return null;
}

用法

var result = GetPoint(@"D:\TestImages\Main.bmp", @"D:\TestImages\1159-980.bmp");

结果比您使用的简单 4 循环方法快大约 100 倍。

注意,这使用了 unsafe 关键字,因此您必须将项目设置为允许不安全。

免责声明:这也可以进行更多优化,也可以并行完成,显然在 gpu 上会更快。关键是它的算法与处理器无关

【讨论】:

  • 感谢您的代码。我会试试看。我现有的代码在 1600 X 900 的屏幕截图中查找 50 X 50 的图像时占用了过多的 CPU。因此,我必须找到更好的算法或使用 GPU 来实现 4-Loop 方法。
【解决方案2】:

是的,您可以使用 C# 中的 GPU

cmsoft 在这里有他们的库的教程

您需要在 OpenCL 中编写一些指令

您可能还需要检查您是否有用于 opencl 的 driver/runtime (or for AMD)

代码主要是样板文件。很直接。您可能会花费更多时间来安装依赖项而不是编写代码。

【讨论】:

    【解决方案3】:

    这种方法称为相关性,可以通过 FFT 进行优化。 相关性可以通过内核的旋转简单地转换为卷积。因此,如果 Complete_Image 和 Small_Image 都填充了足够的零并且 Small_Image 旋转了 180 度,那么两个图像的 FFT 乘积的 IFFT 可以以 O(n log n) 的顺序计算整个相关图像。其中 n 是图像的大小(长度高度)。主要相关问题的阶数接近 nn。

    【讨论】:

      猜你喜欢
      • 2016-02-18
      • 2011-03-29
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      • 2015-08-22
      相关资源
      最近更新 更多