灰度图像的图像乘法

Image Multiplication of Gray Image

当我处理 2 个灰度图像的图像乘法时,我确实看到了颜色分量。无法弄清楚这里到底出了什么问题:

图片: 反射图像: 以上图像的图像乘法:

这是我的图像乘法函数:

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 代码:

问题好像还是一样。虽然我尝试使用强度值而不仅仅是颜色通道:下面是代码的变化:无法真正弄清楚这里发生了什么。

输出:

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;
    }

关于您的代码的一些注释:

您的图像格式已经是 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)有关,因为图像未正确写入。

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));
      

[edit1]

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

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