C#|Bitmap処理の高速化

Bitmapをピクセル単位で加工しようとする場合には Bitmap.GetPixel()メソッドとBitmap.SetPixel()メソッドが利用出来るが、 これらの処理時間が問題になる場合には以下のクラスで高速に処理出来る。
ビットマップデータをメモリ上に展開し、メモリにポインタでアクセスして値を直接書き換えることで速度の改善を図っている。
とても速い。

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

class TurboArgbPixelFilter {
    /// <summary>
    /// 画像のすべてのピクセルをループして指定した処理をする。
    /// </summary>
    /// <param name="bmp">処理対象の画像。PixelFormat.Format32bppArgbのみ対応。</param>
    /// <param name="proc">ピクセルごとに行う処理。1ピクセルごとに呼び出される。</param>
    public static void FastFiltering(
        Bitmap bmp, PixelProc proc) {

        if(bmp.PixelFormat != PixelFormat.Format32bppArgb) {
            throw new ArgumentException(
                "bmpのPixelFormatはFormat32bppArgbのみ有効です。", "bmp");
        }

        BitmapData bmpData = bmp.LockBits(
            new Rectangle(Point.Empty, bmp.Size),
            ImageLockMode.ReadWrite,
            PixelFormat.Format32bppArgb);

        unsafe {
            byte* pixel = (byte*)bmpData.Scan0;
            int dataLength = bmpData.Stride * bmpData.Height;

            for(int i = 0; i < dataLength; i += 4) {
                proc(
                    ref *(pixel++),
                    ref *(pixel++),
                    ref *(pixel++),
                    ref *(pixel++));
            }
        }

        bmp.UnlockBits(bmpData);
    }

    /// <summary>
    /// ImageからPixelFormat32pbbArgbのBitmapを作成して返します。
    /// </summary>
    /// <returns>PixelFormat32pbbArgbのBitmap</returns>
    public static Bitmap GetRegularizedBitmap(Image img) {
        Bitmap bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb);

        using(Graphics g = Graphics.FromImage(bmp)) {
            g.DrawImage(img, 0, 0, img.Width, img.Height);
        }

        return bmp;
    }

    public delegate void PixelProc(ref byte b, ref byte g, ref byte r, ref byte a);
}

 

以下の様に使用する。
以下のコードは、画像を読み込んで不透明度を半分にし、ピクチャボックスの背景に設定している。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
    public partial class Form1 :Form {
        public Form1() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {
            Bitmap bmp = TurboArgbPixelFilter.
                GetRegularizedBitmap(
                    Image.FromFile(@"C:\nagato_ha_ore_no_yome.bmp"));

            TurboArgbPixelFilter.
                FastFiltering(bmp,proc);
            this.pictureBox1.Image = bmp;
        }

        private void proc(ref byte b, ref byte g, ref byte r, ref byte a) {
            a >>= 1;
        }
    }
}

 

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください