c# - 比较图像和标记差异 c#

标签 c# .net image comparison pixel

我目前正在进行一个项目,我需要编写一个软件来比较由同一区域组成的两张图像,并在差异处画一个方框。我在几个小时内用 c# .net 编写了该程序,但很快意识到它的运行成本非常高。以下是我实现它的步骤。

  1. 创建了一个存储每个像素的 x、y 坐标的 Pixel 类和一个存储像素列表以及宽度、高度、x 和 y 属性的 PixelRectangle 类。

  2. 遍历每个图像的每个像素,比较每个对应像素的颜色。如果颜色不同,我会使用该像素的 x,y 坐标创建一个新的像素对象,并将其添加到 pixelDifference 列表中。

  3. 接下来,我编写了一个方法来递归检查 pixelDifference 列表中的每个像素,以创建仅包含彼此直接相邻的像素的 PixelRectangle 对象。 (很确定这个坏男孩造成了大部分破坏,因为它给了我一个堆栈溢出错误。)

  4. 然后我根据存储在 PixelRectangle 对象列表中的像素计算出矩形的 x、y 坐标和尺寸,并在原始图像上绘制一个矩形以显示差异所在。

我的问题是:我这样做的方式是否正确?四叉树对这个项目有任何值(value)吗?如果你能告诉我通常如何实现这样的事情的基本步骤,我将不胜感激。提前致谢。

  • 戴夫。

最佳答案

您似乎想要实现 Blob 检测。我的建议是不要重新发明轮子,只使用 openCVSharp 或 emgu 来做到这一点。谷歌“ Blob 检测”和 opencv

如果你想在这里自己做,我的 2 美分值(value):

首先,让我们弄清楚你想做什么。实际上是两件独立的事情:

  1. 计算两个图像之间的差异(我假设它们是 相同的尺寸)

  2. 在按 1 衡量的“不同”的“区域”周围画一个方框。这里的问题是什么是“区域”,什么被认为是“不同的”。

我对每一步的建议:

(我的假设是两个图像都是灰度。如果不是,则计算每个像素的颜色总和以获得灰度值)

1) 循环遍历两个图像中的所有像素并减去它们。为绝对差异设置一个阈值以确定它们的差异是否足以表示场景中的实际变化(如果图像来自相机,则与传感器噪声等相反)。然后将结果存储在第三张图像中。 0 没有区别。 255 的区别。如果做得对,这应该非常快。但是,在 C# 中,您必须使用指针才能获得不错的性能。这里有一个如何执行此操作的示例(注意:代码未经测试!!):

  /// <summary>
    /// computes difference between two images and stores result in a third image
    /// input images must be of same dimension and colour depth
    /// </summary>
    /// <param name="imageA">first image</param>
    /// <param name="imageB">second image</param>
    /// <param name="imageDiff">output 0 if same, 255 if different</param>
    /// <param name="width">width of images</param>
    /// <param name="height">height of images</param>
    /// <param name="channels">number of colour channels for the input images</param>
    unsafe void ComputeDiffernece(byte[] imageA, byte[] imageB, byte[] imageDiff, int width, int height, int channels, int threshold)
    {
        int ch = channels;

        fixed (byte* piA = imageB, piB = imageB, piD = imageDiff)
        {

            if (ch > 1) // this a colour image (assuming for RGB ch == 3 and RGBA  == 4)
            {
                for (int r = 0; r < height; r++)
                {
                    byte* pA = piA + r * width * ch;
                    byte* pB = piB + r * width * ch;
                    byte* pD = piD + r * width; //this has only one channels!

                    for (int c = 0; c < width; c++)
                    {
                        //assuming three colour channels. if channels is larger ignore extra (as it's likely alpha)
                        int LA = pA[c * ch] + pA[c * ch + 1] + pA[c * ch + 2];
                        int LB = pB[c * ch] + pB[c * ch + 1] + pB[c * ch + 2];

                        if (Math.Abs(LA - LB) > threshold)
                        {
                            pD[c] = 255;
                        }
                        else
                        {
                            pD[c] = 0;
                        }

                    }
                }
            }
            else //single grey scale channels
            {
                for (int r = 0; r < height; r++)
                {
                    byte* pA = piA + r * width;
                    byte* pB = piB + r * width;
                    byte* pD = piD + r * width; //this has only one channels!

                    for (int c = 0; c < width; c++)
                    {
                        if (Math.Abs(pA[c] - pB[c]) > threshold)
                        {
                            pD[c] = 255;
                        }
                        else
                        {
                            pD[c] = 0;
                        }
                    }
                }
            }
        }
    }

2)

不确定这里所说的区域是什么意思。几种解决方案取决于你的意思。从最简单到最难。

a) 将输出中的每个差异像素涂成红色

b) 假设您只有一个差异区域(不太可能)计算输出图像中所有 255 个像素的边界框。这可以通过对所有 255 个像素的 x 和 y 位置使用简单的最大/最小值来完成。单次通过图像,应该非常快。

c) 如果您有很多不同的区域发生变化 - 计算“连通分量”。那是一组相互连接的像素。当然,这只适用于二进制图像(即打开或关闭,或者在我们的例子中是 0 和 255)。你可以在 C# 中实现它,我之前已经这样做过。但我不会在这里为你做这个。这有点复杂。算法在那里。再次 opencv 或 google connected components .

获得 CC 列表后,在每个 CC 周围画一个框。完成。

关于c# - 比较图像和标记差异 c#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17603579/

相关文章:

c# - 动态创建 IList 类型的新实例

c# - 使用 Caliburn.Micro 的分层导航模型

java - 背景图片位置错误

c# - 获取附加到 Windows CE 设备的 USB 驱动器名称

c# - 继承和静态属性

c# - 将 native 移动开发与 Xamarin 相结合

asp.net - 在 MySQL 中存储图片 - 聪明吗?

image - 如何从扫描的pdf中提取图像

c# - System.IO.Directory.GetFiles 空

c# - 如何使用第三方 API 处理网络掉线和超时错误