|
|||||
<このサンプルの概要> .NETのBitmap処理は遅いので高速化するサンプル(VB.NET)を作ってみました。 この方法で通常のBitmapで32秒掛かった処理が4秒で出来るようになりました。 このサンプルで使用しているBitmap高速化の方法は、 System.Runtime.InteropServices.Marshalを使用する方法です。 C#.NETでは、アンセーフコード(unsafe)を使用する方法も可能ですが、 VB.NETでは使用出来ないようです。 このサンプルのポイントとなるキーワードは以下の通りです。 (1)System.Drawing.Imaging.BitmapData.Scan0 (2)System.Drawing.Imaging.BitmapData.Stride (3)GetPixel (4)SetPixel C#.NETのサンプルはこちらです。 Bitmap処理を高速化するサンプル(C#.NET) ★Bitmap処理を高速化するためのクラス(BitmapPlus.vb) ※System.Runtime.InteropServices.Marshalを使用する方法 Imports System.Drawing imports System.Drawing.Imaging Public Class BitmapPlus ''' <summary> ''' オリジナルのBitmapオブジェクト ''' </summary> Private _bmp As Bitmap = Nothing ''' <summary> ''' Bitmapに直接アクセスするためのオブジェクト ''' </summary> Private _img As BitmapData = Nothing ''' <summary> ''' コンストラクタ ''' </summary> ''' <param name="original"></param> Public Sub New(ByVal original As Bitmap) ' オリジナルのBitmapオブジェクトを保存 _bmp = original End Sub ''' <summary> ''' Bitmap処理の高速化開始 ''' </summary> Public Sub BeginAccess() ' Bitmapに直接アクセスするためのオブジェクト取得(LockBits) _img = _bmp.LockBits(New Rectangle(0, 0, _bmp.Width, _bmp.Height), _ System.Drawing.Imaging.ImageLockMode.ReadWrite, _ System.Drawing.Imaging.PixelFormat.Format24bppRgb) End Sub ''' <summary> ''' Bitmap処理の高速化終了 ''' </summary> Public Sub EndAccess() If _img Is Nothing = False Then ' Bitmapに直接アクセスするためのオブジェクト開放(UnlockBits) _bmp.UnlockBits(_img) _img = Nothing End If End Sub ''' <summary> ''' BitmapのGetPixel同等 ''' </summary> ''' <param name="x">X座標</param> ''' <param name="y">Y座標</param> ''' <returns>Colorオブジェクト</returns> Public Function GetPixel(ByVal x As Integer, ByVal y As Integer) As Color If _img Is Nothing = True Then ' Bitmap処理の高速化を開始していない場合はBitmap標準のGetPixel Return _bmp.GetPixel(x, y) End If Dim adr As IntPtr = _img.Scan0 Dim pos As Integer = x * 3 + _img.Stride * y Dim b As Byte = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 0) Dim g As Byte = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 1) Dim r As Byte = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 2) Return Color.FromArgb(r, g, b) End Function '''// <summary> ''' BitmapのSetPixel同等 ''' </summary> ''' <param name="x">X座標</param> ''' <param name="y">Y座標</param> ''' <param name="col">Colorオブジェクト</param> Public Sub SetPixel(ByVal x As Integer, ByVal y As Integer, ByVal col As Color) If _img Is Nothing = True Then ' Bitmap処理の高速化を開始していない場合はBitmap標準のSetPixel _bmp.SetPixel(x, y, col) Return End If ' Bitmap処理の高速化を開始している場合はBitmapメモリへの直接アクセス Dim adr As IntPtr = _img.Scan0 Dim pos As Integer = x * 3 + _img.Stride * y System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 0, col.B) System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 1, col.G) System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 2, col.R) End Sub End Class ★テスト用フォーム(Form1.vb) Public Class Form1 Private Sub Button1_Click( _ ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click ' Bitmapオブジェクト生成 Dim bmp As Bitmap If PictureBox1.Image Is Nothing = True Then ' Bitmapを新規生成 bmp = New Bitmap(512, 512) Else ' BitmapをpictureBoxから取得 bmp = New Bitmap(PictureBox1.Image) End If ' Bitmap処理の高速化開始 Dim bmpP As BitmapPlus = New BitmapPlus(bmp) bmpP.BeginAccess() For i As Integer = 0 To bmp.Width - 1 For j As Integer = 0 To bmp.Height - 1 ' Bitmapの色取得 'Dim bmpCol As Color = bmp.GetPixel(i, j) Dim bmpCol As Color = bmpP.GetPixel(i, j) If bmpCol.R = 0 Then ' Bitmapの色設定 'bmp.SetPixel(i, j, Color.FromArgb(255, 255, 0, 0)) bmpP.SetPixel(i, j, Color.FromArgb(255, 255, 0, 0)) Else 'bmp.SetPixel(i, j, Color.FromArgb(255, 0, 0, 0)) bmpP.SetPixel(i, j, Color.FromArgb(255, 0, 0, 0)) End If Next Next ' Bitmap処理の高速化終了 bmpP.EndAccess() PictureBox1.Image = bmp End Sub End Class |