【问题标题】:The colour of pixels of the image are incorrect图像像素颜色不正确
【发布时间】:2011-12-24 13:48:59
【问题描述】:

我正在尝试使用一个名为 SAD(平方差之和)的比较函数来比较 2 个图像,我从每个图像中取出一个块,然后将像素转换为灰度并进行比较。 但问题是,如果我比较两个相同的块,sad 的结果不是 0(所以存在差异)。我检查了多个消息框,然后我看到程序返回的像素颜色不正确:例如,黑色像素=255 而不是 0。

这里是我的比较函数的代码:

 public double SAD(bloc Bc, bloc Br)
    {
        double sad = 0;
        {
            BitmapData bmp = image1.LockBits(new Rectangle(Bc.x, Bc.y, taille_bloc, taille_bloc), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmp2 = image2.LockBits(new Rectangle(Br.x, Br.y, taille_bloc, taille_bloc), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            IntPtr ptr2 = bmp2.Scan0;
            IntPtr ptr = bmp.Scan0;
            int bytes = bmp.Width * bmp.Height * 3;
            double gris1, gris2;
            byte[] rgb = new byte[bytes];
            byte[] rgb2 = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgb, 0, bytes);
            System.Runtime.InteropServices.Marshal.Copy(ptr2, rgb2, 0, bytes);
            for (int i = 0; i < rgb.Length; i += 3)
            {

                 gris1 = rgb[i] * 0.2989 + rgb[i+1] * 0.5870 + rgb[i+2] * 0.1140;
                 gris2 = rgb2[i] * 0.2989 + rgb2[i + 1] * 0.5870 + rgb2[i + 2] *  0.1140;

                sad = sad + Math.Abs(gris2 - gris1);

            }
            image2.UnlockBits(bmp2);

            image1.UnlockBits(bmp);
        }

        return sad;

    }

如果我的解释不清楚,请告诉我,以便我重新表述

非常感谢您的帮助:)

【问题讨论】:

  • 你确定图片是一样的吗?如果您正在比较相同的图像,您应该在相同的计算中得到相同的结果。也许将通用部分抽象为一个函数并为每个图像/像素调用它?
  • 您能否提供一个简短的、自包含的、可编译的示例(请参阅sscce.org),以便我们可以快速运行它并尽力帮助您。您提供的那个包含缺少的类型和变量。
  • 首先,我不认为这是计算平方差的总和。看起来它正在计算差异的总和。
  • 其次,由于您正在计算差异,因此您可能不需要应用人眼颜色感知的校正因子。
  • 第三,你确定要转灰度吗?我希望您明白,理论上这可能会将两张图像分类为相同的,即使它们的颜色可能不同。在任何情况下,即使需要转换为灰度,您也应该将其隔离在一个完全不同的函数中,您将对其进行测试以确保其正常工作,从而最大限度地减少我们在代码中可能出错的事情看着。

标签: c# imaging


【解决方案1】:

一个可能的问题是您的字节数计算错误。你有:

int bytes = bmp.Width * bmp.Height * 3;

但是位图会被填充,通常是 4 字节边界。你需要使用

int bytes = bmp.Stride * bmp.Height;

Stride 是表示一条扫描线所需的字节数。对于 24 位图像,这将等于 3 * bmp.Width 加上填充所需的字节数(可能为零)。

然后,要对数组进行索引,您逐行进行,并忽略填充字节。您必须在每行的开头初始化索引。

for (int row = 0; row < bmp.Height; ++row)
{
    int i = row * bmp.Stride;
    for (int p = 0; p < bmp.Width; ++p)
    {
        // do comparisons with rgb[i], rgb[i+1], rgb[i+2]
        i += 3;
    }
}

【讨论】:

  • 感谢您的回答,如果我使用 bmp.Stride,我将如何访问我的 RGB 值? (在我的代码中,我在每次迭代中前进 3,如果我不知道我的表中有多少列,我将不知道 RGB 值的存储位置)
  • 对不起,我之前在这里发表的评论有误,我删除了它。您需要对每一行 (y) 进行循环,而不是对位图数据的每个字节进行循环,并且在该循环中,您需要对每一列 (x) 进行另一个循环。像素的位置在 rgb[(y * bmp.Stride) + (x * 3) + c] 其中 c = 0、1 或 2 代表 R、G 或 B。当然,除非您的位图使用 4 个字节每个像素,在这种情况下,您需要进行相应的调整。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-18
  • 1970-01-01
  • 2011-09-22
  • 2013-05-07
  • 1970-01-01
相关资源
最近更新 更多