.netでピクセル単位にイメージにアクセスするさい、Bitmap#GetPixel/Setがありますが、これがすこぶる遅いです。高速化のために、ポインタで直接アクセスしてピクセルを操作することにします。
ポイントは、int pos = x * 3 + this.bmpData.Stride * y;の部分かな。
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace ImageOperator
{
///
/// ビットマップ操作クラス
/// ビットマップのピクセル操作を高速化します。
/// 本クラスでは、メモリへの直接アクセスを行うことで高速化します。
///
public class UnsafeBitmapOperator
{
///
/// ビットマップデータ
///
protected Bitmap bmp = null;
///
/// ビットマップデータ
///
protected BitmapData bmpData = null;
///
/// コンストラクタ
///
/// 対象イメージ
public UnsafeBitmapOperator(Bitmap original)
{
// オリジナルのBitmapオブジェクトを保存
this.bmp = original;
}
///
/// 高速化開始
///
public void BeginAccess()
{
this.bmpData = this.bmp.LockBits(new Rectangle(0, 0, this.bmp.Width, this.bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
}
///
/// 高速化終了
///
public void EndAccess()
{
if (this.bmpData != null)
{
this.bmp.UnlockBits(this.bmpData);
this.bmpData = null;
}
}
///
/// ピクセル取得
///
/// X座標
/// Y座標
/// ピクセル
public Color GetPixel(int x, int y)
{
if (this.bmpData == null)
{
// 高速化していない場合、通常のピクセル取得
return this.bmp.GetPixel(x, y);
}
unsafe
{
// イメージの先頭ポインタ取得
byte* pBmp = (byte*)this.bmpData.Scan0;
int pos = x * 3 + this.bmpData.Stride * y;
byte b = pBmp[pos + 0];
byte g = pBmp[pos + 1];
byte r = pBmp[pos + 2];
return Color.FromArgb(r, g, b);
}
}
///
/// ピクセル設定
///
/// X座標
/// Y座標
/// ピクセル色
public void SetPixel(int x, int y, Color col)
{
if (this.bmpData == null)
{
// 高速化していない場合、通常のピクセル設定
this.bmp.SetPixel(x, y, col);
return;
}
unsafe
{
// イメージの先頭ポインタ取得
byte* pBmp = (byte*)this.bmpData.Scan0;
int pos = x * 3 + this.bmpData.Stride * y;
pBmp[pos + 0] = col.B;
pBmp[pos + 1] = col.G;
pBmp[pos + 2] = col.R;
}
}
}
}