不安全的图像操作导致程序退出
Unsafe Image manipulation causing program exit
我正在尝试使用 unsafe
代码进行一些基本的图像处理。然后我用 bmp.GetPixel
访问一个像素,这导致程序 "stop working"。我不知道如何调试它。
我在 Treshold 方法中没有做我应该做的事情吗?
var imageFilename = @"foo.jpg";
var im = (Bitmap)Bitmap.FromFile(imageFilename);
Threshold(im, 2);
// this line causes it to stop working without an exception
im.GetPixel(0,0);
static void Threshold(Bitmap bmp, int thresh)
{
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
unsafe
{
byte* p = (byte*)(void*)bmData.Scan0.ToPointer();
int h = bmp.Height;
int w = bmp.Width;
int ws = bmData.Stride;
for (int i = 0; i < h; i++)
{
byte* row = &p[i * ws];
for (int j = 0; j < w * 3; j += 3)
{
row[j] = (byte)((row[j] > (byte)thresh) ? 255 : 0);
row[j + 1] = (byte)((row[j + 1] > (byte)thresh) ? 255 : 0);
row[j + 2] = (byte)((row[j + 2] > (byte)thresh) ? 255 : 0);
}
}
}
bmp.UnlockBits(bmData);
}
更新:出于某种原因,我发现使用不同的像素格式PixelFormat.Format24bppRgb
解决了问题。为什么?输入图像为灰度。
问题具体在于图像格式。灰度图像是每像素 8 位或 16 位(取决于图像),而不是每像素 24 位;您正在读取(更不利的是,写入)图像后的内存位置 - 不安全代码不检查数组边界,因此不会引发异常。
比如16位灰度,重写内循环:
for (int j = 0; j < w * 2; j += 2)
{
row[j] = (byte)((row[j] > (byte)thresh) ? 255 : 0);
row[j + 1] = (byte)((row[j + 1] > (byte)thresh) ? 255 : 0);
}
程序 "stops working" 在不安全代码运行后尝试处理图像时,由于内存损坏 - 您写入了不属于图像的内存。
你也可以在bmp.PixelFormat
的基础上调整你的循环,并操作适量的比特;这样您的代码将适用于多种图像格式。
的更多信息
我正在尝试使用 unsafe
代码进行一些基本的图像处理。然后我用 bmp.GetPixel
访问一个像素,这导致程序 "stop working"。我不知道如何调试它。
我在 Treshold 方法中没有做我应该做的事情吗?
var imageFilename = @"foo.jpg";
var im = (Bitmap)Bitmap.FromFile(imageFilename);
Threshold(im, 2);
// this line causes it to stop working without an exception
im.GetPixel(0,0);
static void Threshold(Bitmap bmp, int thresh)
{
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
unsafe
{
byte* p = (byte*)(void*)bmData.Scan0.ToPointer();
int h = bmp.Height;
int w = bmp.Width;
int ws = bmData.Stride;
for (int i = 0; i < h; i++)
{
byte* row = &p[i * ws];
for (int j = 0; j < w * 3; j += 3)
{
row[j] = (byte)((row[j] > (byte)thresh) ? 255 : 0);
row[j + 1] = (byte)((row[j + 1] > (byte)thresh) ? 255 : 0);
row[j + 2] = (byte)((row[j + 2] > (byte)thresh) ? 255 : 0);
}
}
}
bmp.UnlockBits(bmData);
}
更新:出于某种原因,我发现使用不同的像素格式PixelFormat.Format24bppRgb
解决了问题。为什么?输入图像为灰度。
问题具体在于图像格式。灰度图像是每像素 8 位或 16 位(取决于图像),而不是每像素 24 位;您正在读取(更不利的是,写入)图像后的内存位置 - 不安全代码不检查数组边界,因此不会引发异常。
比如16位灰度,重写内循环:
for (int j = 0; j < w * 2; j += 2)
{
row[j] = (byte)((row[j] > (byte)thresh) ? 255 : 0);
row[j + 1] = (byte)((row[j + 1] > (byte)thresh) ? 255 : 0);
}
程序 "stops working" 在不安全代码运行后尝试处理图像时,由于内存损坏 - 您写入了不属于图像的内存。
你也可以在bmp.PixelFormat
的基础上调整你的循环,并操作适量的比特;这样您的代码将适用于多种图像格式。