两副图片的差异比较的C#实现
早上看到stg609 写的《Dot Net下实现屏幕图像差异获取v2.0》文章,想起自己以前写过的一个《大家来找茬》的游戏辅助工具(就是作弊器了,嘿嘿),当时也是用到了判断比较两副图片的差异功能。现将当时写的差异比较代码发上来,给大家参考参考。
当时用的简单实现方法就是:将两副图片同时按一定大小的小块“切分开”,再分别比较这些小块,如果某个块里出现有一个不同的象素点,那就认为此块所在的位置是有差异的否则认为是相同的,当比较完所有小块后,两副图之间的不同之处的位置也就出来了。因为要进行所有小块比较,所以最坏的情况下是要扫描比较图片的所有象素点(两副图完全一样的情况时),最理想的情况就是只扫描比较所有小块的第一点(两副图完全不一样的情况时)。
这种方法的判断精确性是根据“块”大小来决定的,也就是如果你将“块”设得过大,判断的“精确性”就越低(因为只要块里有一点不相同,就认为此块位置是有差异的),如将“块”设置得过小,则判断的“精确性”就越高,但需要时间也有可能会越多!
如有下面的两副图:(以下图借用了stg609 的《Dot Net下实现屏幕图像差异获取v1.0》文章里的截图,呵)
(第一幅图片) (第二幅图片)
将上面两幅图按20*20(px)大小“切分”:
(第一幅图片) (第二幅图片)
两副图都分别“切分”成多个20*20的小块,程序再分别对这些小块进行判断,如果“扫描”到小块里的某个象素点是不相同的则记录此块的坐标位置并退出当前块的扫描,继续扫描下一个小块,直到所有小块“扫描”完成。
在程序处理时为提高速度,利用了Bitmap的LockBits方法,直接对图片的内存数据操作,并且“切分”图片的小块时,并不真正的“切图”,而是利用“内存指针”进行数据定位操作。如下面代码:
{
byte* p1 = (byte*)bd1.Scan0 + h * bd1.Stride;
byte* p2 = (byte*)bd2.Scan0 + h * bd2.Stride;
w = 0;
while (w < bd1.Width && w < bd2.Width)
{
//按块大小进行扫描
for (int i = 0; i < block.Width; i++)
{
int wi = w + i;
if (wi >= bd1.Width || wi >= bd2.Width) break;
for (int j = 0; j < block.Height; j++)
{
int hj = h + j;
if (hj >= bd1.Height || hj >= bd2.Height) break;
ICColor* pc1 = (ICColor*)(p1 + wi * 3 + bd1.Stride * j);
ICColor* pc2 = (ICColor*)(p2 + wi * 3 + bd2.Stride * j);
if (pc1->R != pc2->R || pc1->G != pc2->G || pc1->B != pc2->B)
{
//当前块有某个象素点颜色值不相同.也就是有差异.
int bw = Math.Min(block.Width, bd1.Width - w);
int bh = Math.Min(block.Height, bd1.Height - h);
rects.Add(new Rectangle(w, h, bw, bh));
goto E;
}
}
}
E:
w += block.Width;
}
h += block.Height;
}
示例项目代码下载:
/Files/kingthy/ImageComparer.zip
上面两幅图的差异比较后的截图:(两图中蓝色与红色框框内的小块就是表明有差异的小块)