がりらぼ

WindowsRuntimeの応援ブログ

画像をピクセル単位で操作する

.Netでは標準ではイメージをピクセル単位で操作するクラスは用意されてないので外部ライブラリを利用するか自分で作る必要があります。

今回はカメラからの画像を操作することとします。

PhotoCamera camera=new PhotoCamera();
camera.CaptureImage();

これでカメラの画像をキャプチャします。

double pixelSize = camera.PreviewResolution.Width * camera.PreviewResolution.Height;
            var pixelData = new int[(int)pixelSize];
            camera.GetPreviewBufferArgb32(pixelData);
            var bmp = new WriteableBitmap((int)camera.PreviewResolution.Width, (int)camera.PreviewResolution.Height);
            pixelData.CopyTo(bmp.Pixels, 0);

これでbmpにカメラから取得したビットマップ画像が入るわけですが、
WindowsPhoneでビットマップをピクセル単位で処理するにはWriteableBitmapクラスが便利です。

WriteableBitmapでは、イメージの幅と、イメージの高さ、そして、1次元配列に格納されたピクセル列が取得できます。

bgra32というフォーマットで格納されているので非常に取り出しにくいです。

そこで、こちらのサイトを参考にし、バイト単位で取り出すこととします。

//アルファ値を取り出すときは、24bitシフト演算し、8bitでAND演算し、取り出します。
(pixels[i] >> 24) & 0xff
//赤を取り出すには16bitシフトします。
(pixels[i] >> 16) & 0xff
//緑を取り出すには8bitシフトします。
(pixels[i] >> 8) & 0xff)
//青はシフトせずにそのまま8bit取り出します
pixels[i] & 0xff

逆に、色情報をbgra32に格納するには逆にシフトして、OR演算します。

int i=(a << 24 | r << 16 | g << 8 | b)

あとはピクセルが何色かを判定してモノクロにしたり、反転させたりしたらピクセル単位で操作できますね。


【おまけ】
intの1次元配列じゃ難しいよ!って人のために、1次元配列を二次元配列に変換して、より画像として操作しやすいようにするには、

 int[,] pixels = new int[pixelWidth, pixelHeight];
            for (int i = 0; i < pixelHeight; i++)
            {
                for (int j = 0; j < pixelWidth; j++)
                {
                    this.pixels[j, i] = _pixels[i * pixelWidth + j];
                }
            }

こうやって二次元配列に変換します

逆に二次元配列から1次元配列に格納するには、

 int[] p = new int[pixelWidth * pixelHeight];
            for (int i = 0; i < pixelHeight; i++)
            {
                for (int j = 0; j < pixelWidth; j++)
                {
                    p[i * pixelWidth + j] = pixels[j, i];
                }
            }

こんな感じですね。

ちなみにできた1次元配列をWriteableBitmapクラスに格納するには

//ビットマップの領域確保
var bmp = new WriteableBitmap((int)bitmap.PixelWidth, (int)bitmap.PixelHeight);
//pixelsは1次元配列のピクセル列
pixels.CopyTo(bmp.Pixels,0);

こんな感じ