そのサンプルのコードが機能する場合は、ポインターを介してビットマップのピクセル データにアクセスできるオブジェクトBitmap.LockBits
を返すを使用して、コードを大幅に (桁違いに) 高速化できます。BitmapData
Web および StackOverflow には、LockBits の使用方法を示す多数のサンプルがあります。
Bitmap.SetPixel()
とBitmap.GetPixel()
は人類に知られている最も遅い方法であり、どちらも人類に知られてColor
いる最も遅いクラスであるクラスを利用しています。不注意な開発者への警告として名前を付ける必要がBitmap.GetPixelAndByGodYoullBeSorryYouDid()
ありました。Bitmap.SetPixelWhileGettingCoffee
更新: そのサンプルのコードを変更する場合は、次のチャンクに注意してください。
System.Drawing.Bitmap TempBitmap = Image;
System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width,
TempBitmap.Height);
System.Drawing.Graphics NewGraphics =
System.Drawing.Graphics.FromImage(NewBitmap);
NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0,
TempBitmap.Width, TempBitmap.Height),
new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height),
System.Drawing.GraphicsUnit.Pixel);
NewGraphics.Dispose();
これで置き換えることができます:
Bitmap NewBitmap = (Bitmap)Image.Clone();
更新 2: これは、AdjustContrast メソッドの LockBits バージョンです (その他のいくつかの速度改善を含む)。
public static Bitmap AdjustContrast(Bitmap Image, float Value)
{
Value = (100.0f + Value) / 100.0f;
Value *= Value;
Bitmap NewBitmap = (Bitmap)Image.Clone();
BitmapData data = NewBitmap.LockBits(
new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height),
ImageLockMode.ReadWrite,
NewBitmap.PixelFormat);
int Height = NewBitmap.Height;
int Width = NewBitmap.Width;
unsafe
{
for (int y = 0; y < Height; ++y)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
int columnOffset = 0;
for (int x = 0; x < Width; ++x)
{
byte B = row[columnOffset];
byte G = row[columnOffset + 1];
byte R = row[columnOffset + 2];
float Red = R / 255.0f;
float Green = G / 255.0f;
float Blue = B / 255.0f;
Red = (((Red - 0.5f) * Value) + 0.5f) * 255.0f;
Green = (((Green - 0.5f) * Value) + 0.5f) * 255.0f;
Blue = (((Blue - 0.5f) * Value) + 0.5f) * 255.0f;
int iR = (int)Red;
iR = iR > 255 ? 255 : iR;
iR = iR < 0 ? 0 : iR;
int iG = (int)Green;
iG = iG > 255 ? 255 : iG;
iG = iG < 0 ? 0 : iG;
int iB = (int)Blue;
iB = iB > 255 ? 255 : iB;
iB = iB < 0 ? 0 : iB;
row[columnOffset] = (byte)iB;
row[columnOffset + 1] = (byte)iG;
row[columnOffset + 2] = (byte)iR;
columnOffset += 4;
}
}
}
NewBitmap.UnlockBits(data);
return NewBitmap;
}
注: このコードではusing System.Drawing.Imaging;
、クラスの using ステートメントが必要であり、プロジェクトのallow unsafe code
オプションが (プロジェクトの [ビルド プロパティ] タブで) チェックされている必要があります。
GetPixel と SetPixel がピクセルごとの操作で非常に遅い理由の 1 つは、メソッド呼び出し自体のオーバーヘッドが大きな要因になり始めていることです。既存の BitmapData オブジェクトを使用する独自の SetPixel および GetPixel メソッドを記述できるため、通常、ここに示すコード サンプルはリファクタリングの候補と見なされますが、関数内の計算の処理時間はメソッドのオーバーヘッドに比べて非常に小さくなります。各コールの。Clamp
これが、元のメソッドの呼び出しも削除した理由です。
これを高速化するもう 1 つの方法は、コピーを作成して変更されたコピーを返す代わりに、単に「破壊的な」関数にして、渡された Bitmap パラメータを変更することです。