2008年5月18日日曜日

[.NET]画像処理グレースケール化(2)

GDD Blog: [.NET]画像処理グレースケール化(1)」で約700msかかっていた処理ですが、P/InvokeやUnsafeを使わなくてもLockBitsを使いBitmapの内部データにアクセスすることにより、高速化が可能です。
処理の内容としては以下のとおり。
  • LockBitsを使い、bitmapの内部データをシステム メモリにロックします
  • そのデータを、Byte[]にコピーします
  • 3byteずつを1pixelのカラーデータとし、その平均をセットしなおします(これは[.NET]画像処理グレースケール化(1)と同じ処理)

コードはこんな感じ。



Bitmap bmp = new Bitmap(ctlPicture.Image);

//bitmapをメモリ上にロックします
Rectangle rect = new Rectangle(00bmp.Widthbmp.Height);
BitmapData bmpData = bmp.LockBits(rectImageLockMode.ReadWrite,
                                          PixelFormat.Format24bppRgb);

// RGB値をbyte列にコピーする
IntPtr ptr = bmpData.Scan0;
int stride = bmpData.Stride;
int size = stride * bmp.Height;
byte[] rgbValues = new byte[size];

System.Runtime.InteropServices.Marshal.Copy(ptrrgbValues0size);

//3byteずつ進む
for (int j = 0j < sizej = j + 3)
{
    byte val = (byte)Math.Round((double)(rgbValues[j + 0] + rgbValues[j + 1] + rgbValues[j + 2]) / 3);
    rgbValues[j] = val;     //b
    rgbValues[j + 1] = val//g
    rgbValues[j + 2] = val//r
}

// byte列をbitmapに復元し、メモリのロックを開放する
System.Runtime.InteropServices.Marshal.Copy(rgbValues0ptrsize);
bmp.UnlockBits(bmpData);

ctlPicture.Image = bmp;


このコードにより、同じ環境でも処理速度が30ms程度になります。パフォーマンスが約23倍になりました。

2 件のコメント:

KOBA789 さんのコメント...

ソース中に、
rgbValues[j] = val; //r
rgbValues[j + 1] = val; //g
rgbValues[j + 2] = val; //b

とありますが、メモリ上ではBGRの順で格納されているため、
rgbValues[j + 2] = val; //R
rgbValues[j + 1] = val; //G
rgbValues[j] = val; //B

となるはずです。

GENZO さんのコメント...

kobahideさん

確かにおっしゃるとおりBGRの順ですね。というわけでコメントを修正しました。

コメントありがとうございました。