比较图像并标记差异c#

比较图像并标记差异c#,c#,.net,image,comparison,pixel,C#,.net,Image,Comparison,Pixel,我目前正在从事一个项目,在这个项目中,我需要编写一个软件来比较由相同区域组成的两幅图像,并在差异周围画一个方框。我在几个小时内用c#net编写了这个程序,但很快就意识到它运行起来非常昂贵。以下是我在中实现它的步骤 创建了存储每个像素的x、y坐标的像素类和存储像素列表以及宽度、高度、x和y属性的像素矩形类 循环通过每个图像的每个像素,比较每个对应像素的颜色。如果颜色不同,我就用像素的x,y坐标创建一个新的像素对象,并将其添加到像素差异列表中 接下来,我编写了一个方法,递归检查pixelDiffer

我目前正在从事一个项目,在这个项目中,我需要编写一个软件来比较由相同区域组成的两幅图像,并在差异周围画一个方框。我在几个小时内用c#net编写了这个程序,但很快就意识到它运行起来非常昂贵。以下是我在中实现它的步骤

  • 创建了存储每个像素的x、y坐标的像素类和存储像素列表以及宽度、高度、x和y属性的像素矩形类

  • 循环通过每个图像的每个像素,比较每个对应像素的颜色。如果颜色不同,我就用像素的x,y坐标创建一个新的像素对象,并将其添加到像素差异列表中

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

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

  • 我的问题是:我这样做对吗?四叉树对这个项目有价值吗?如果你能给我一些基本的步骤,告诉我通常是如何做到这一点的,我将不胜感激。提前谢谢

    • 戴夫

    您的做法非常正确。如果步骤3实现正确,那么它不应该导致StackOverflow异常,所以我将仔细研究该方法

    最有可能发生的情况是,对PixelDifference的每个成员的递归检查正在无限运行。确保跟踪已检查的像素。检查像素后,在检查相邻像素时不再需要考虑它。在检查任何相邻像素之前,请确保它本身未被检查


    作为跟踪已检查像素的替代方法,您可以在检查后从PixelDifference中删除项目。当然,这可能需要改变实现算法的方式,因为在检查列表时从列表中删除元素可能会带来一系列全新的问题

    看起来您想要实现blob检测。我的建议是不要重新发明轮子,而只是使用openCVSharp或emgu来实现。谷歌“斑点检测”和opencv

    如果你想在这里亲自动手,我的2美分价值:

    首先,让我们澄清一下你想做什么。实际上有两件事是不同的:

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

  • 在由1测量的“不同”区域周围绘制一个方框。这里的问题是什么是“区域”,什么是“不同的”

  • 我对每一步的建议是:

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

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

    //
    ///计算两个图像之间的差异并存储第三个图像
    ///输入图像必须具有相同的尺寸和颜色深度
    /// 
    ///第一图像
    ///第二图像
    ///如果相同,则输出0;如果不同,则输出255
    ///图像宽度
    ///图像高度
    ///输入图像的颜色通道数
    不安全的void计算差异(字节[]imageA、字节[]imageB、字节[]imageDiff、int-width、int-height、int-channels、int-threshold)
    {
    int ch=通道;
    固定(字节*piA=imageB,piB=imageB,piD=imageDiff)
    {
    if(ch>1)//这是彩色图像(假设RGB ch==3和RGBA==4)
    {
    对于(int r=0;r阈值)
    {
    pD[c]=255;
    }
    其他的
    {
    pD[c]=0;
    }
    }
    }
    }
    else//单灰度通道
    {
    对于(int r=0;r阈值)
    {
    pD[c]=255;
    }
    其他的
    {
    pD[c]=0;
    
      /// <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;
                            }
                        }
                    }
                }
            }
        }
    
    Image<Gray, Byte> A;
    Image<Gray, Byte> B;
    
    A - B
    
    B - A
    
    (A - B) + (B - A)
    
    CvInvoke.cvDFT(A.Convert<Gray, Single>().Ptr, DFTA.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_FORWARD, -1);
    CvInvoke.cvDFT(B.Convert<Gray, Single>().Ptr, DFTB.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_FORWARD, -1);
    
    CvInvoke.cvDFT((DFTB - DFTA).Convert<Gray, Single>().Ptr, AB.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_INVERSE, -1);
    CvInvoke.cvDFT((DFTA - DFTB).Ptr, BA.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_INVERSE, -1);