不安全的图像操作导致程序退出

时间:2017-02-27 07:40:32

标签: c# unsafe

我正在尝试使用unsafe代码进行一些基本的图像处理。然后我使用bmp.GetPixel访问一个像素,这导致程序“停止工作”。我不知道如何调试它。

我在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解决了这个问题。为什么?输入图像为灰度。

1 个答案:

答案 0 :(得分:0)

问题特别是图像格式。灰度图像是每像素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);
    }

由于内存损坏,在不安全代码运行后尝试使用图像时,程序“停止工作” - 您写入了不属于图像的内存。

您还可以根据bmp.PixelFormat调整循环,并操作适当的位数;这样,您的代码将适用于多种图像格式。

有关bits per pixel

的更多信息