質問
C#の画像のコントラストを調整する効率的な方法はありますか?
私は見た この記事 ピクセルあたりの操作を行うことを支持しています。速くない。
私はすでに場所でカラーマトリックスを使用しており、それらが迅速であることがわかります。それらを使用してコントラストを調整する方法はありますか? (ノート: この男 それを間違えます。)
EMGUCVも使用しています。私はそのopencv(EMGUラップ)に気づきます コントラスト関数があるようです - EMGUを介してこれにアクセスする方法はありますか?現時点では、EMGUでできることは、ヒストグラムを正規化することだけです。これはコントラストを変化させますが、私の側の程度の制御はありません。
誰かがアイデアを持っていますか?
解決
そのサンプルのコードがあなたのために機能する場合、あなたはそれを使用して大量に(桁違いに)スピードアップすることができます Bitmap.LockBits
, 、aを返します BitmapData
ポインターを介してビットマップのピクセルデータにアクセスできるオブジェクト。ロックビットの使用方法を示すWebとStackoverflowには多数のサンプルがあります。
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: これは、AdustContrastメソッドのロックビットバージョンです(他のいくつかの速度改善があります):
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;
あなたのクラスで 'ステートメントを使用しています、そしてそれはプロジェクトが allow unsafe code
オプションを確認する(プロジェクトの[ビルドプロパティ]タブで)。
GetPixelとSetPixelがピクセルごとの操作で非常に遅い理由の1つは、メソッドコール自体のオーバーヘッドが巨大な要因になり始めることです。通常、ここの私のコードサンプルは、既存のBitMapDataオブジェクトを使用する独自のSetPixelメソッドとGetPixelメソッドを記述できるため、リファクタリングの候補と見なされますが、関数内の数学の処理時間は、オーバーヘッドのメソッドに対して非常に小さくなります。各呼び出しの。これが私が削除した理由です Clamp
元の方法でも呼び出します。
これをスピードアップするもう1つの方法は、単に「破壊的な」関数になり、コピーを作成して変更されたコピーを返す代わりに、渡されたビットマップパラメーターを変更することです。
他のヒント
@musigenesis、
私が書いている画像エディターにこの方法を使用したことに注意したかっただけです。うまく機能しますが、この方法がこの行でAccessViolationExceptionをトリガーすることもあります。
byte B = row[columnOffset];
ビットデプスの標準化がなかったためだということに気づいたので、画像が32ビット色の場合、このエラーが発生していました。だから私はこの線を変更しました:
BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat);
に:
BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
これが私の問題を根絶したように思われるので、これが役立つことを願っています。
投稿をありがとう。
ジブ
私は少し遅れていますが、これらはそのような変換に最適化され、自分でピクセルを操作するよりもはるかに簡単なので、カラーマトリックスの実装を使用します。 http://www.geekpedia.com/tutorial202_using-the-colormatrix-in-csharp.html