一定時間毎に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!"); }
参考にしたページ