|
Bitmap処理を高速化するサンプル(C#.NET)

|
<このサンプルの概要>
.NETのBitmap処理は遅いので高速化するサンプルを作ってみました。unsafeを使用するためC#.NETで作成し、
プロジェクトのプロパティでアンセーフコードの許可を設定しています。VB.NETでunsafeは使用出来ないため
別の方法を使う必要があります。通常のBitmap処理で32秒掛かった処理が4秒で出来るようになりました。
このサンプルのポイントとなるキーワードは以下の通りです。
(1)unsafe
(2)LockBits
(3)UnlockBits
(4)System.Drawing.Imaging.BitmapData.Scan0
(5)System.Drawing.Imaging.BitmapData.Stride
(6)GetPixel
(7)SetPixel
★Bitmap処理を高速化するためのクラス(BitmapPlus.cs)
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace BitmapPlus
{
/// <summary>
/// Bitmap処理を高速化するためのクラス
/// </summary>
class BitmapPlus
{
/// <summary>
/// オリジナルのBitmapオブジェクト
/// </summary>
private Bitmap _bmp = null;
/// <summary>
/// Bitmapに直接アクセスするためのオブジェクト
/// </summary>
private BitmapData _img = null;
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="original"></param>
public BitmapPlus(Bitmap original)
{
// オリジナルのBitmapオブジェクトを保存
_bmp = original;
}
/// <summary>
/// Bitmap処理の高速化開始
/// </summary>
public void BeginAccess()
{
// Bitmapに直接アクセスするためのオブジェクト取得(LockBits)
_img = _bmp.LockBits(new Rectangle(0, 0, _bmp.Width, _bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
}
/// <summary>
/// Bitmap処理の高速化終了
/// </summary>
public void EndAccess()
{
if (_img != null)
{
// Bitmapに直接アクセスするためのオブジェクト開放(UnlockBits)
_bmp.UnlockBits(_img);
_img = null;
}
}
/// <summary>
/// BitmapのGetPixel同等
/// </summary>
/// <param name="x">X座標</param>
/// <param name="y">Y座標</param>
/// <returns>Colorオブジェクト</returns>
public Color GetPixel(int x, int y)
{
if (_img == null)
{
// Bitmap処理の高速化を開始していない場合はBitmap標準のGetPixel
return _bmp.GetPixel(x, y);
}
unsafe
{
// Bitmap処理の高速化を開始している場合はBitmapメモリへの直接アクセス
byte* adr = (byte*)_img.Scan0;
int pos = x * 3 + _img.Stride * y;
byte b = adr[pos + 0];
byte g = adr[pos + 1];
byte r = adr[pos + 2];
return Color.FromArgb(r, g, b);
}
}
/// <summary>
/// BitmapのSetPixel同等
/// </summary>
/// <param name="x">X座標</param>
/// <param name="y">Y座標</param>
/// <param name="col">Colorオブジェクト</param>
public void SetPixel(int x, int y, Color col)
{
if (_img == null)
{
// Bitmap処理の高速化を開始していない場合はBitmap標準のSetPixel
_bmp.SetPixel(x, y, col);
return;
}
unsafe
{
// Bitmap処理の高速化を開始している場合はBitmapメモリへの直接アクセス
byte* adr = (byte*)_img.Scan0;
int pos = x * 3 + _img.Stride * y;
adr[pos + 0] = col.B;
adr[pos + 1] = col.G;
adr[pos + 2] = col.R;
}
}
}
}
★テスト用フォーム(Form1.cs)
namespace BitmapPlus
{
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
// Bitmapオブジェクト生成
Bitmap bmp;
if (pictureBox1.Image == null)
{
// Bitmapを新規生成
bmp = new Bitmap(512,512);
}
else
{
// BitmapをpictureBoxから取得
bmp = new Bitmap(pictureBox1.Image);
}
// Bitmap処理の高速化開始
BitmapPlus bmpP = new BitmapPlus(bmp);
bmpP.BeginAccess();
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
// Bitmapの色取得
//Color bmpCol = bmp.GetPixel(i, j);
Color bmpCol = bmpP.GetPixel(i, j);
if (bmpCol.R == (byte)0)
{
// Bitmapの色設定
//bmp.SetPixel(i, j, Color.FromArgb(255, 255, 0, 0));
bmpP.SetPixel(i, j, Color.FromArgb(255, 255, 0, 0));
}
else
{
// Bitmapの色設定
//bmp.SetPixel(i, j, Color.FromArgb(255, 0, 0, 0));
bmpP.SetPixel(i, j, Color.FromArgb(255, 0, 0, 0));
}
}
}
// Bitmap処理の高速化終了
bmpP.EndAccess();
pictureBox1.Image = bmp;
}
}
}