読者です 読者をやめる 読者になる 読者になる

kur.jp

バイオリンと自転車をこよなく愛するkurのチラシの裏。たまには技術的なことを書いたりするかも知れません。

C#でBitmapの比較

一定時間毎にWebブラウザのウィンドウをキャプチャして,変更の有無を検出するコードを書いていたんだけど,ちょっと引っかかってしまったのでメモ.

最初,BitmapクラスにはGetHashCodeというメンバ関数があるから,ハッシュを取得してそれを比較すれば良いだろう,と簡単に考えていた.ところが,GetHashCodeというのはオブジェクトのハッシュを返す関数であり,画像データのハッシュを返すわけではない.つまり,この関数の返り値を比較しても,画像の内容が等しいか否かを判断することが出来ない.

じゃぁ,1pixelごと比較すれば良いのかと考えたのだけれども,BitmapクラスのGetPixelメソッドって,メチャクチャ遅い.そこで,Bitmapの中身をbyte配列に代入して,そのMD5をとることでハッシュ値を取得し,それを比較することで画像の変更の有無を検出することにした.

以下,具体的なコード.これだけの事なんだけど,思ったよりも時間を取ってしまった・・・.

Bitmap CurrentImg = GetScreenCaputureOf(Firefox);
BitmapData bmpdata = CurrentImg.LockBits(new Rectangle(0, 0, CurrentImg.Width, CurrentImg.Height), ImageLockMode.ReadWrite, CurrentImg.PixelFormat);
IntPtr ptr = bmpdata.Scan0;
int bytes = bmpdata.Stride * CurrentImg.Height;
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
byte[] CurrentHash = new MD5CryptoServiceProvider().ComputeHash(rgbValues);

bool bEqual = false; if (PrevHash!=null && PrevHash.Length == CurrentHash.Length) { int i = 0; while ((i < PrevHash.Length) && (PrevHash[i] == CurrentHash[i])) { i += 1; } if (i == PrevHash.Length) { bEqual = true; } }

PrevHash = (byte[])CurrentHash.Clone(); if (!bEqual) { Console.WriteLine("Image Changed!"); }

参考にしたページ