边缘检测与Lockbits c#
本文关键字:Lockbits 边缘检测 | 更新日期: 2023-09-27 18:15:11
我编写了一个实现边缘检测算法的程序,但这需要很长时间来处理。我读过关于使用锁位和不安全状态而不是getpixel和setpixel,但我仍然不明白如何使用它。
这是我的示例代码:
private Bitmap SobelEdgeDetect(Bitmap original)
{
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);
else
bb.SetPixel(i, j, Color.Transparent);
}
}
return bb;
}
我正在使用fastbitmap类,我像这样实现:
private Bitmap SobelEdgeDetectTwo(Bitmap original)
{
int width = original.Width;
int height = original.Height;
Bitmap result = new Bitmap(width,height);
FastBitmap b = new FastBitmap(original);
FastBitmap bb = new FastBitmap(result);
b.LockBitmap();
bb.LockBitmap();
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++)
{
var pixel = b.GetPixel(i,j);
allPixR[i, j] = pixel.Red;
allPixG[i, j] = pixel.Green;
allPixB[i, j] = pixel.Blue;
}
}
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 < width - 1; i++)
{
for (int j = 1; j < 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)
{
PixelData p = new PixelData(Color.Black);
bb.SetPixel(i, j, p);
}
else
{
PixelData p = new PixelData(Color.Transparent);
bb.SetPixel(i, j, p);
}
}
}
b.UnlockBitmap();
bb.UnlockBitmap();
return result;
}
然而,图像根本没有改变。你能告诉我我的代码哪部分是错的吗?
使用FastBitmap这样的类是最简单的。只需添加FastBitmap并在该类上使用GetPixel()而不是在Bitmap上,其余的可以是相同的。
像这样:
Bitmap dstBmp = new Bitmap(width, height, original.PixelFormat);
FastBitmap fastBitmap = new FastBitmap(dstBmp);
fastBitmap.LockBitmap();
//...
var pixel = fastBitmap.GetPixel(x,y);
//...
fastBitmap.UnlockBitmap();
好,让我们看看我们能做什么-快速谷歌找到了这个,它可以简单地适应你的功能像这样
private Bitmap SobelEdgeDetect(Bitmap original)
{
int width = original.Width;
int height = original.Height;
int BitsPerPixel = Image.GetPixelFormatSize(original.PixelFormat);
int OneColorBits = BitsPerPixel / 8;
BitmapData bmpData = original.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, original.PixelFormat);
int position;
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 } };
byte Threshold = 128;
Bitmap dstBmp = new Bitmap(width, height, original.PixelFormat);
BitmapData dstData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, dstBmp.PixelFormat);
unsafe
{
byte* ptr = (byte*)bmpData.Scan0.ToPointer();
byte* dst = (byte*)dstData.Scan0.ToPointer();
for (int i = 1; i < height - 1; i++)
{
for (int j = 1; j < width - 1; j++)
{
int NewX = 0, NewY = 0;
for (int ii = 0; ii < 3; ii++)
{
for (int jj = 0; jj < 3; jj++)
{
int I = i + ii - 1;
int J = j + jj - 1;
byte Current = *(ptr + (I * width + J) * OneColorBits);
NewX += gx[ii, jj] * Current;
NewY += gy[ii, jj] * Current;
}
}
position = ((i * width + j) * OneColorBits);
if (NewX * NewX + NewY * NewY > Threshold * Threshold)
dst[position] = dst[position + 1] = dst[position + 2] = 255;
else
dst[position] = dst[position + 1] = dst[position + 2] = 0;
}
}
}
original.UnlockBits(bmpData);
dstBmp.UnlockBits(dstData);
return dstBmp;
}
这不是完整的复制/粘贴解决方案,但您应该能够看到原作者如何使用LockBits
以您需要的方式访问像素数据。剩下的就看你了;-)
您需要在您的项目属性中设置unsafe
选项,正如我在回答您之前的问题时所解释的那样。