Существует ли эффективный способ скорректировать контраст изображения в C#?
Я видел эту статью, которая рекомендует делать операцию на пиксель. Не быстрый.
Я уже использую матрицы цветов в местах и нахожу, что они быстры. Существует ли способ скорректировать контраст с помощью них? (Отметьте: Этот парень понимает его превратно.)
Я также использую EmguCV. Я замечаю, что OpenCV (который переносит Emgu), кажется, имеет контрастную функцию - там какой-либо способ получить доступ к этому через Emgu? В данный момент все, что я могу сделать в Emgu, нормализуют гистограмму, которая изменяет контраст, но не с любым уровнем контроля с моей стороны.
Кто-либо получил какие-либо идеи?
Если код в этом примере работает для вас, вы можете ускорить его увеличиваются массово (на порядки) с помощью Bitmap.LockBits
, который возвращает объект BitmapData
, который позволяет получить доступ к данным пикселей Bitmap через указатели. В Интернете и на 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: Вот версия LockBits для метод AdjustContrast (с некоторыми другими улучшениями скорости):
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;
}
ПРИМЕЧАНИЕ: для этого кода требуется с использованием System.Drawing.Imaging;
в операторах using вашего класса, и для этого требуется, чтобы в проекте была отмечена опция разрешить небезопасный код
(на вкладке «Свойства сборки» для проекта).
Одна из причин, по которой GetPixel и SetPixel настолько медленны при попиксельных операциях, заключается в том, что накладные расходы на вызов самого метода начинают становиться огромным фактором. Обычно мой пример кода здесь будет рассматриваться как кандидат на рефакторинг, поскольку вы можете написать свои собственные методы SetPixel и GetPixel, которые используют существующий объект BitmapData, но время обработки математики внутри функций будет очень маленьким по сравнению с накладными расходами метода. каждого звонка. Вот почему я также удалил вызовы Clamp
в исходном методе.
Еще один способ ускорить это - просто сделать ее «деструктивной» функцией и изменить переданный параметр Bitmap вместо создания копии и возврата измененной копии.