C#,带有伪像的Lockbits图像处理,更改像素格式

时间:2018-08-14 07:23:56

标签: c# parallel-processing task-parallel-library lockbits

我正在实现自己的功能以对指纹图像进行二值化处理。在我的方法中,我尝试第一次使用LockBits

您能解释一下,为什么我的图像上出现很多伪像吗?范例:

enter image description here

在左边的图片上,我通过Get/SetPixel对图像进行了二值化,并且工作正常,但是为什么我在右边的图像上却无法获得同样好的效果(很多红点)?我是否忘记或不了解某事?

private Bitmap Binarization(Bitmap tempBmp)
    {

        int threshold = otsuValue(tempBmp); //calculating threshold with Otsu method

        unsafe
        {
            BitmapData bmpData = tempBmp.LockBits(new System.Drawing.Rectangle(0, 0, tempBmp.Width, tempBmp.Height), ImageLockMode.ReadWrite, tempBmp.PixelFormat);
            byte* ptr = (byte*)bmpData.Scan0;


            int height = tempBmp.Height;
            int width = bmpData.Width * 4;
            Parallel.For(0, height, y =>
            {
                byte* offset = ptr + (y * bmpData.Stride); //set row
                for (int x = 0; x < width; x = x + 4)
                {
                    //changing pixel value 
                    offset[x] = offset[x] > threshold ? Byte.MaxValue : Byte.MinValue;
                    offset[x+1] = offset[x+1] > threshold ? Byte.MaxValue : Byte.MinValue;
                    offset[x+2] = offset[x+2] > threshold ? Byte.MaxValue : Byte.MinValue;
                    offset[x+3] = offset[x+3] > threshold ? Byte.MaxValue : Byte.MinValue;

                }
            });

            tempBmp.UnlockBits(bmpData);
        }

        return tempBmp;
    }

相同的历史记录,当我想从图像中剪切一些字节,但是问题看起来更加复杂。

enter image description here

为什么它甚至没有进入良好的“如果”状态?

private Bitmap Binarization(Bitmap tempBmp)
    {

        int threshold = otsuValue(tempBmp);

        unsafe
        {
            BitmapData bmpData = tempBmp.LockBits(new System.Drawing.Rectangle(0, 0, tempBmp.Width, tempBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); 
            //Format8bpp, not pixel format from image
            byte* ptr = (byte*)bmpData.Scan0;


            int height = tempBmp.Height;
            int width = bmpData.Width; //i cut "* 4" here because of one channel image
            Parallel.For(0, height, y =>
            {
                byte* offset = ptr + (y * bmpData.Stride); //set row
                for (int x = 0; x < width; x++)
                {
                    //changing pixel values
                    offset[x] = offset[x] > threshold ? Byte.MaxValue : Byte.MinValue;

                }
            });

            tempBmp.UnlockBits(bmpData);
        }

        return tempBmp;
    }

感谢您提出改善我功能的建议。

2 个答案:

答案 0 :(得分:0)

1)您使用的算法不能保证黑白结果。

您正在分别测试 RGB通道,因此,如果R > thresholdG or B < threshold会打开,而G and/or B不会等。

实际上,真正的问题是为什么不出现更多的工件。必须与源图像有关。

解决方案:添加所有三个渠道,并与阈值* 3进行比较;然后将所有设置为相同的黑色或白色值!

2)还有另一个问题:您从某处复制的代码盲目地假定该图像的速度为32 bpp。但是,尽管您发布的图像是png,但它仍然只有24 bpp。因此,您的代码将完成各种有趣的事情。

更新并更正了示例:

        ..
        int pixWidth = tempBmp.PixelFormat == IMG.PixelFormat.Format24bppRgb ? 3 : 
                       tempBmp.PixelFormat == IMG.PixelFormat.Format32bppArgb ? 4 : 4;


        byte* ptr = (byte*)bmpData.Scan0;

        threshold3 = threshold * 3;
        int height = tempBmp.Height;
        int width = bmpData.Width * pixWidth;
        Parallel.For(0, height, y =>
        {
            byte* offset = ptr + (y * bmpData.Stride); //set row
            for (int x = 0; x < width; x = x + pixWidth)
            {
                //changing pixel value 
                int v = (offset[x] + offset[x + 1] + offset[x + 2]) > threshold3 ? 
                        Byte.MaxValue : Byte.MinValue;;
                offset[x] = (byte)v ;
                offset[x+1] = (byte)v;
                offset[x+2] = (byte)v;
                if (pixWidth == 4) offset[x+3] = 255;

            }
        });

答案 1 :(得分:0)

对于这个问题,我有如下解决方案:

public static bool Offset(Bitmap b_mapa, int threshold)
        {
            int threshold3 = threshold * 3;
            int red, green, blue;
            BitmapData bmData = b_mapa.LockBits(new Rectangle(0, 0, b_mapa.Width, b_mapa.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;
            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                int nOffset = stride - b_mapa.Width * 3;
                for (int y = 0; y < b_mapa.Height; ++y)
                {
                    for (int x = 0; x < b_mapa.Width; ++x)
                    {
                        blue = p[0];
                        green = p[1];
                        red = p[2];
                        int v = ((int)(blue + green + red) > threshold3 ? (int)255 : (int)0);
                        p[0] = p[1] = p[2] = (byte)v;
                        p += 3;
                    }
                    p += nOffset;
                }
            }
            b_mapa.UnlockBits(bmData);
            return true;
        }

此函数使用名为b_mapa的共享资源,并且我们的函数应根据处理结果返回布尔值。我在这里不使用并行功能,因为当我们使用LockBits时,我们直接使用内存,而不使用可以快1000倍且没有点并行化的嵌入式功能。如果滤波器是卷积的,则并行化可用于更快一点的代码。顺便说一句,当我加载图像时,我将它们转换为位图,位图更简单,以后可以做所有事情,而不必考虑我有多少位用于颜色表示。

如您所见,在位图数组中,BGR不是RGB,只是为了让您知道,因为许多错误会导致错误并弄乱了颜色。