灰度图像的图像乘法

时间:2015-07-10 23:39:59

标签: c# image-processing

当我处理2张灰色图像的图像倍增时,我确实看到了颜色成分。无法弄清楚到底出了什么问题:

图像: enter image description here 反映图像: enter image description here 上图的图像乘法: enter image description here

这是我的Image Multiplicaiton函数:

public Bitmap MaskImage(Bitmap SrcBitmap1, Bitmap SrcBitmap2)
        {
            int width;
            int height;

            //Message = "Impossible.";

            if (SrcBitmap1.Width < SrcBitmap2.Width)
                width = SrcBitmap1.Width;
            else
                width = SrcBitmap2.Width;

            if (SrcBitmap1.Height < SrcBitmap2.Height)
                height = SrcBitmap1.Height;
            else
                height = SrcBitmap2.Height;

            Bitmap bitmap = new Bitmap(width, height);
            int clr1, clr2;

            try
            {
                BitmapData Src1Data = SrcBitmap1.LockBits(new Rectangle(0, 0, SrcBitmap1.Width, SrcBitmap1.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

                BitmapData Src2Data = SrcBitmap2.LockBits(new Rectangle(0, 0, SrcBitmap2.Width, SrcBitmap2.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

                BitmapData DestData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

                unsafe
                {
                    //Following is list of offset for different bit images
                    //8 bit : 1
                    //16 bit : 2
                    //24 bit : 3 and
                    //32 bit : 4
                    int xOffset = 1;

                    for (int col = 0; col < bitmap.Height - 1; col++)
                    {
                        byte* Src1Ptr = (byte*)Src1Data.Scan0 + col * Src1Data.Stride;
                        byte* Src2Ptr = (byte*)Src2Data.Scan0 + col * Src2Data.Stride;
                        byte* DestPtr = (byte*)DestData.Scan0 + col * DestData.Stride;

                        for (int row = 0; row < bitmap.Width - 1; row++)
                        {
                            clr1 = (Src1Ptr[row * xOffset] + Src1Ptr[row * xOffset + 1] + Src1Ptr[row * xOffset + 2]) / 3;
                            clr2 = (Src2Ptr[row * xOffset] + Src2Ptr[row * xOffset + 1] + Src2Ptr[row * xOffset + 2]) / 3;

                            clr1 *= clr2;

                            if (clr1 == 0)
                            {
                                DestPtr[row * xOffset] = (byte)(0);
                                DestPtr[row * xOffset + 1] = (byte)(0);
                                DestPtr[row * xOffset + 2] = (byte)(0);
                            }
                            else
                            {
                                DestPtr[row * xOffset] = (byte)(Src2Ptr[row * xOffset]);
                                DestPtr[row * xOffset + 1] = (byte)(Src2Ptr[row * xOffset + 1]);
                                DestPtr[row * xOffset + 2] = (byte)(Src2Ptr[row * xOffset + 2]);
                            }
                        }
                    }
                }

                bitmap.UnlockBits(DestData);
                SrcBitmap1.UnlockBits(Src1Data);
                SrcBitmap2.UnlockBits(Src2Data);

                SrcBitmap1.Dispose();
                SrcBitmap2.Dispose();
            }
            catch (Exception ex)
            {
                Console.Write(ex);
            }

            return bitmap;
        }

修改

基于Spektre代码:

问题似乎仍然是一样的。虽然我试图使用强度值而不仅仅是颜色通道:下面是代码的变化:不能真正弄清楚这里发生了什么。

输出: enter image description here

public Bitmap MaskImage(Bitmap SrcBitmap1, Bitmap SrcBitmap2)
    {
        int width;
        int height;

        //Message = "Impossible.";

        if (SrcBitmap1.Width < SrcBitmap2.Width)
            width = SrcBitmap1.Width;
        else
            width = SrcBitmap2.Width;

        if (SrcBitmap1.Height < SrcBitmap2.Height)
            height = SrcBitmap1.Height;
        else
            height = SrcBitmap2.Height;

        Bitmap bitmap = new Bitmap(width, height);

        try
        {
            BitmapData Src1Data = SrcBitmap1.LockBits(new Rectangle(0, 0, SrcBitmap1.Width, SrcBitmap1.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

            BitmapData Src2Data = SrcBitmap2.LockBits(new Rectangle(0, 0, SrcBitmap2.Width, SrcBitmap2.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

            BitmapData DestData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            unsafe
            {
                //Following is list of offset for different bit images
                //8 bit : 1
                //16 bit : 2
                //24 bit : 3 and
                //32 bit : 4
                int xOffset = 1;

                for (int col = 0; col < bitmap.Height - 1; col++)
                {
                    byte* Src1Ptr = (byte*)Src1Data.Scan0 + col * Src1Data.Stride;
                    byte* Src2Ptr = (byte*)Src2Data.Scan0 + col * Src2Data.Stride;
                    byte* DestPtr = (byte*)DestData.Scan0 + col * DestData.Stride;

                    for (int row = 0; row < bitmap.Width - 1; row++)
                    {
                        byte i1 = Src1Ptr[row * xOffset];
                        bbyte i2 = Src2Ptr[row * xOffset];
                        DestPtr[row * xOffset + 0] = (byte)((((ushort)(i1) * (ushort)(i2)) >> 8));
                        DestPtr[row * xOffset + 1] = (byte)((ushort)(((ushort)(i1) * (ushort)(i2)) >> 8));
                        DestPtr[row * xOffset + 2] = (byte)((ushort)(((ushort)(i1) * (ushort)(i2)) >> 8));
                    }
                }
            }

            bitmap.UnlockBits(DestData);
            SrcBitmap1.UnlockBits(Src1Data);
            SrcBitmap2.UnlockBits(Src2Data);

            SrcBitmap1.Dispose();
            SrcBitmap2.Dispose();
        }
        catch (Exception ex)
        {
            Console.Write(ex);
        }

        return bitmap;
    }

2 个答案:

答案 0 :(得分:1)

关于您的代码的一些注意事项:

您的图片格式已经是8bpp,因此这里没有RGB频道:

clr1 = (Src1Ptr[row * xOffset] + Src1Ptr[row * xOffset + 1] + Src1Ptr[row * xOffset + 2]) / 3;
clr2 = (Src2Ptr[row * xOffset] + Src2Ptr[row * xOffset + 1] + Src2Ptr[row * xOffset + 2]) / 3;

因此这里不需要+1和+2,并且除以3以使图像变灰。因为输入图像已经是灰度图像。

同样,在将值分配回目标图像时,这应该足够了:

DestPtr[row * xOffset] = (byte) //value of multiplied gray level

在您的示例中,您只需返回第二个图像的值。

由于图像没有正确写入,因此生成的图像为何着色与移位(偏移,+ 1和+2)有关。

答案 1 :(得分:0)

Joel Legaspi Enriquez是对的我只想添加

  • 你需要乘以强度而不是颜色
  • 在RGB中编码为颜色的灰度等级为R==G==B
  • 这就是为什么你只需要单个组件
  • 当您rgb1*rgb2乘以(3*8 + 3*8 bit result)
  • 这是一个很大的数字,RGB通道之间有很多溢出
  • 这是颜色从无处出现的原因

解决这个问题:

  1. 只增加强度

    • 所以只有一个频道与r,g,b
    • 中的哪一个无关
  2. 将输出范围归一化回原始位数

    • 所以每个频道通常是8位
    • 乘以后为16位
    • 所以只需将(1 ^ 8)除以256或向右移位8位
    • 然后将结果复制到所有频道

      BYTE i1=Src1Ptr[row * xOffset];
      BYTE i2=Src2Ptr[row * xOffset];
      DestPtr[row * xOffset+0] = BYTE(WORD((WORD(i1)*WORD(i2))>>8));
      DestPtr[row * xOffset+1] = BYTE(WORD((WORD(i1)*WORD(i2))>>8));
      DestPtr[row * xOffset+2] = BYTE(WORD((WORD(i1)*WORD(i2))>>8));
      
  3. [EDIT1]

    你的地址计算看起来很可疑

    • 我认为它是以某种方式封装在xOffset中并且没有进一步查看
    • 但是第二次看你将ti设置为1并且你没有在我能看到的任何地方应用y偏移
    • 我会像address = (x*Stride)+(y*Width*stride)
    • 那样计算像素(x,y)的地址
    • 可能是我错误地看了你的代码,但看起来像是
    • 您还混合了colrow
    • 位图存储为行(行)而不是列
    • 所以应该交换for
    • 外部循环应为y(行)和内部x(col)