我目前正在开展一个项目,在这个项目中,我需要编写软件来比较由同一区域组成的两个图像,并围绕差异绘制一个框.我在几个小时内用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的列表,每个人都会画一个方框.完成.