簡單實現方法就是:將兩副圖片同時按一定大小的小塊“切分開”,再分別比較這些小塊,如果某個塊裡出現有一個不同的象素點,那就認為此塊所在的位置是有差異的否則認為是相同的,當比較完所有小塊後,兩副圖之間的不同之處的位置也就出來了。因為要進行所有小塊比較,所以最壞的情況下是要掃描比較圖片的所有象素點(兩副圖完全一樣的情況時),最理想的情況就是只掃描比較所有小塊的第一點(兩副圖完全不一樣的情況時)。
這種方法的判斷精確性是根據“塊”大小來決定的,也就是如果你將“塊”設得過大,判斷的“精確性”就越低(因為只要塊裡有一點不相同,就認為此塊位置是有差異的),如將“塊”設定得過小,則判斷的“精確性”就越高,但需要時間也有可能會越多!
如有下面的兩副圖:(以借用了stg609 的《Dot Net下實現螢幕映像差異擷取v1.0》文章裡的,呵)
(第一幅圖片) (第二幅圖片)
將上面兩幅圖按20*20(px)大小“切分”:
(第一幅圖片) (第二幅圖片)
兩副圖都分別“切分”成多個20*20的小塊,程式再分別對這些小塊進行判斷,如果“掃描”到小塊裡的某個象素點是不相同的則記錄此塊的座標位置並退出當前塊的掃描,繼續掃描下一個小塊,直到所有小塊“掃描”完成。
在程式處理時為提高速度,利用了Bitmap的LockBits方法,直接對圖片的記憶體資料操作,並且“切分”圖片的小塊時,並不真正的“切圖”,而是利用“記憶體指標”進行資料定位操作。如下面代碼:
代碼
while (h < bd1.Height && h < bd2.Height)
{
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
上面兩幅圖的差異比較後的:(兩圖中藍色與紅色框框內的小塊就是表明有差異的小塊)