ホーム ] TIPS ウィンドウズ系 ] TIPS グラフィックス系 ] TIPS メルチメディア系 ] TIPS 理数系 ] TIPS 総覧 ]

上へ
G0001 色名一覧
G0002 アルファブレンド
G0003 カラーマップを作る
G0101 曲線の数値化
G0102 曲線長を測る
G0103 曲線の接線・法線
G0104 曲線のスムージング
G0201 図形の回転
G0202 領域の認識
G0301 文字の線形変換
G0302 文字の自由変形
G0303 文字の極座標変換
G0304 曲線に沿った文字列
G0305 飾文字-中抜き
G0306 飾文字-縁取り
G0307 飾文字-ドロップダウンシャドウ
G0501 画像の線形変換
G0502 画像の透明化
G0503 画像の任意形状切出し
G0504 画像の回転
G0505 画像の高速処理化

VB.NET2005 TIPS / グラフィックス系

G0505 画像の高速処理化

最終更新:2007/02/21 全面改訂

●解説

 ビットマップでは補間を伴うアフィン変換は既にネイティブに対応されていて十分高速である。これは、VBでもC#でも同じである。しかし、色変換(濃度変換)系統は、VBではSetPixel、GetPixelと言う恐ろしく遅い関数しかない。VB6に比べると随分高速になったが、それでもインタラクティブな処理(ユーザのリアルタイムなパラメータ変更に追従するような処理)には向いていない。C#で も同じである。基本的に、VB.NETとC#.NETはほぼ同じパフォーマンスと考えて良い。
 ここでは、ビットマップをメモリ上のデータ群として高速に処理する方法を紹介する。

●原理

 VB.NETもC#.NETもプログラマにメモリアドレス(ポインタ)の概念を忘れさせる方式を取っている。ところが、高速にメモリをアクセスするには、やはりポインタにより直接メモリを読み書きするしかない。実は、.NETでは以下のような手法が用意されている。

  1. ビットマップのイメージをメモリ上のデータとして見せる手段(BitmapDataオブジェクト)

  2. メモリをポインタで自由に読み書きできる手段(Marshal)

  3. 更に、メモリデータを配列化する手段を提供している。

である。アンマネージ型とマネージ型の変換となる(アセンブラの世界と同じアクセスで、筆者はこの方が馴染み良い)。これらを利用すれば高速にビットマップを処理できる。但し、ポインタはアンマネージなので、プログラマは最新の注意が必要となる。C#でも基本的にポインタを排除しているので、アンマネージ型処理となる。

●方法

1.ビットマップのイメージをメモリ上のデータとする方法

 ビットマップのLockBitsメソッドで指定の矩形領域をメモリ上のデータに割り付け、これをBitmapDataオブジェクトとする。BitmapDataのScan0プロパティが目的のメモリアドレスの先頭となる。

2.メモリ(ピクセルデータ)をポインタで自由に読み書きする方法

 Marshalクラスにて特定のデータ型で読み書きする関数でピクセルの要素(R、G、B)を直接アクセスする。

 ReadByte(ptr, Offset, data)
  WriteByte(ptr, Offset, data)

    ptr:ポインタ構造体
   Offset:ptrからのオフセット値
   data:バイトデータ

 などで、自由にピクセルデータを処理できる。メモリ上の画像の物理的な幅は、Stride(バイト単位)で分かる。

3.メモリデータを配列化する方法

 Marshal にはCopyメソッドがあり、メモリ上のポインターで指されたところから任意の語数を、ローカルな配列にコピーしたり、その配列をメモリ上のポインターへ戻したりできる。ローカルな配列では高速な処理が可能となる。

4.ビットマップを元に戻す

 ビットマップのUnlockBitsメソッドでLock状態を開放する。これをして置かないとマネージ側からアクセスできない。

●実例

○Marshal WriteByte

Imports System.Runtime.InteropServices.Marshal

Dim bP As IntPtr
bmp = New Bitmap(Sz, Sz, Drawing.Imaging.PixelFormat.Format24bppRgb)  '3バイト/ピクセル

Dim BD As Imaging.BitmapData
BD = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat)
bP = BD.Scan0
For j = 0 To Sz - 1
   For k = 0 To Sz - 1
      ofs = j * Sz * 3 + k * 3
      WriteByte(bP, ofs + 0, 11)
      WriteByte(bP, ofs + 1, 12)
      WriteByte(bP, ofs + 2, 13)
   Next
Next
bmp.UnlockBits(BD)    'メモリデータをビットマップに戻す

○Marshal 配列化

Imports System.Runtime.InteropServices.Marshal

Dim bP As IntPtr
bmp = New Bitmap(Sz, Sz, Drawing.Imaging.PixelFormat.Format24bppRgb)

Dim BD As Imaging.BitmapData
BD = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat)
bP = BD.Scan0
Dim p As Integer
Dim BC As Integer = Sz * Sz * 3
Dim BB(BC - 1) As Byte
Copy(bP, BB, 0, BC)             '指定されたポインタから自分の配列にコピーする
For j = 0 To Sz - 1
   For k = 0 To Sz - 1
      p = j * Sz * 3 + k * 3
      BB(p) = 11                    '後は自由に演算できる
      BB(p + 1) = 12
      BB(p + 2) = 13
   Next
Next
Copy(BB, 0, bP, BC)      '指定されたポインタへ、配列を戻す
bmp.UnlockBits(BD)     'メモリデータをビットマップに戻す