比较图像和标记差异c#

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

>创建了一个Pixel类,用于存储每个像素的x,y坐标,以及一个PixelRectangle类,用于存储像素列表以及width,height,x和y属性.
>循环遍历每个图像的每个像素,比较每个相应像素的颜色.如果颜色不同,我会创建一个新的像素对象,其中包含该像素的x,y坐标,并将其添加到pixelDifference列表中.
>接下来,我编写了一个方法,以递归方式检查pixelDifference列表中的每个像素,以创建仅包含彼此紧邻的像素的PixelRectangle对象. (很确定这个坏孩子造成了大部分破坏,因为它给了我一个堆栈溢出错误.)
>然后,我根据存储在PixelRectangle对象列表中的像素计算出矩形的x,y坐标和尺寸,并在原始图像上绘制一个矩形,以显示差异的位置.

我的问题是:我是否以正确的方式解决这个问题?四叉树是否对此项目有任何价值?如果你能给我一些关于如何通常实现这样的基本步骤,我将不胜感激.提前致谢.

>戴夫

最佳答案 看起来你想要实现blob检测.我的建议不是重新发明轮子,只需使用openCVSharp或emgu来做到这一点. google’blob detection’& OpenCV的

如果你想在这里自己做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位置的简单max / min来完成.单次通过图像应该非常快.

c)如果你有许多不同的领域发生变化 – 计算“连通组件”.这是一组彼此连接的像素.当然,这仅适用于二进制图像(即打开或关闭,或者在我们的情况下为0和255).你可以在c#中实现这个,我以前做过这个.但我不会在这里为你做这件事.它有点牵扯.算法在那里.再次opencv或谷歌connected components.

一旦你有一个CC的列表,每个人都会画一个方框.完成.

点赞