【问题标题】:Fastest Sobel Edge Detection C#最快的 Sobel 边缘检测 C#
【发布时间】:2013-05-21 10:29:14
【问题描述】:

我想做一个实现sobel边缘检测的程序。 这是我的代码:

private Bitmap SobelEdgeDetect(Bitmap ori)
{
        Bitmap b = original;
        Bitmap bb = original;
        int width = b.Width;
        int height = b.Height;
        int[,] gx = new int[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
        int[,] gy = new int[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };

        int[,] allPixR = new int[width, height];
        int[,] allPixG = new int[width, height];
        int[,] allPixB = new int[width, height];

        int limit = 128 * 128;

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                allPixR[i, j] = b.GetPixel(i, j).R;
                allPixG[i, j] = b.GetPixel(i, j).G;
                allPixB[i, j] = b.GetPixel(i, j).B;
            }
        }

        int new_rx = 0, new_ry = 0;
        int new_gx = 0, new_gy = 0;
        int new_bx = 0, new_by = 0;
        int rc, gc, bc;
        for (int i = 1; i < b.Width - 1; i++)
        {
            for (int j = 1; j < b.Height - 1; j++)
            {

                new_rx = 0;
                new_ry = 0;
                new_gx = 0;
                new_gy = 0;
                new_bx = 0;
                new_by = 0;
                rc = 0;
                gc = 0;
                bc = 0;

                for (int wi = -1; wi < 2; wi++)
                {
                    for (int hw = -1; hw < 2; hw++)
                    {
                        rc = allPixR[i + hw, j + wi];
                        new_rx += gx[wi + 1, hw + 1] * rc;
                        new_ry += gy[wi + 1, hw + 1] * rc;

                        gc = allPixG[i + hw, j + wi];
                        new_gx += gx[wi + 1, hw + 1] * gc;
                        new_gy += gy[wi + 1, hw + 1] * gc;

                        bc = allPixB[i + hw, j + wi];
                        new_bx += gx[wi + 1, hw + 1] * bc;
                        new_by += gy[wi + 1, hw + 1] * bc;
                    }
                }
                if (new_rx * new_rx + new_ry * new_ry > limit || new_gx * new_gx + new_gy * new_gy > limit || new_bx * new_bx + new_by * new_by > limit)
                    bb.SetPixel(i, j, Color.Black);

                //bb.SetPixel (i, j, Color.FromArgb(allPixR[i,j],allPixG[i,j],allPixB[i,j]));
                else
                    bb.SetPixel(i, j, Color.Transparent);
            }
        }
        return bb;

  }

我想使用 lockbits,这样我的程序可以运行得更快,但我实际上仍然不明白如何使用它。 谁能给出一些解释或示例代码?

【问题讨论】:

  • 您的原始代码具有 Sobel 算法,但由于 GetPixelSetPixel 而运行缓慢。现在您的代码应该在 both 位图(输入和输出)上使用LockBits,并通过(x,y) 访问像素,正如我在回答中所展示的那样。你现在非常接近 - 不要放弃。
  • 你能告诉我,我的代码的哪一部分应该交换为锁定位?我感到非常沮丧。谢谢

标签: c# image-processing graphics edge-detection


【解决方案1】:

您确实需要使用LockBits 而不是GetPixelSetPixel

所以你创建了一个包含所有像素数据的BitmapData 对象:

// lock the input bitmap's bits  
System.Drawing.Imaging.BitmapData bmpData =
    original.LockBits(new Rectangle(0, 0, original.Width, original.Height), 
    System.Drawing.Imaging.ImageLockMode.Read, original.PixelFormat);

那么,就可以得到第一条扫描线的地址(即第一行像素):

IntPtr ptr = bmpData.Scan0;

现在你有两个选择。如果您愿意将您的函数标记为unsafe,那么您可以使用指针算法直接访问像素,如下所示

byte* pPixels = (byte*)ptr.ToPointer();

它为您提供指向 RGB 像素的第一个字节的指针(假设为 24bpp)。然后,您可以使用指针算法访问(x,y) 处的单个像素。首先你确定每个像素有多少字节(如果你还不知道的话)

int nBytesPerPixel = Image.GetPixelFormatSize(original.PixelFormat) / 8;

然后计算你想要的像素的索引

byte* pPixelAtXY = pPixels + (y * bmpData.Stride) + (x * nBytesPerPixel);

这使您可以unsafe 访问Bitmap 中的像素,您可以对输入和输出位图执行此操作以获得最快的速度。请注意,要使用不安全代码,您需要mark your function as unsafeedit your project properties

如果您不想使用unsafe 代码,您仍然可以通过在处理之前将所有像素数据复制到byte 数组来加快处理速度,然后再将其复制回来。正如 MSDN 示例所示

// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;

// Declare an array to hold the bytes of the bitmap. 
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];

// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

// Set every third value to 255. A 24bpp bitmap will look red.   
for (int counter = 2; counter < rgbValues.Length; counter += 3)
    rgbValues[counter] = 255;

// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

无论您使用哪种方法,当您完成像素数据后,您必须使用UnlockBits释放它

original.UnlockBits(bmpData);

【讨论】:

  • 能否给个完整的源代码,我试过了,但我得到了任何错误。
  • @user1442032 如果您编辑问题以显示新代码,那么我们可以看到问题所在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 2021-06-02
  • 2020-04-06
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 2018-12-12
相关资源
最近更新 更多