Ответ 1
Лучший способ сделать это - прямой доступ к пикселям с растровыми данными.
Просто добавьте некоторые детали времени:
Выполнение Negate на 8-мегапиксельном изображении (на 2.4 Ghz Core 2 Duo):
- SetPixel (~ 22 секунды) - менее 220 раз
- Цветовая матрица, метод Матаджона ниже (~ 750 миллисекунд) - в 7 раз медленнее
- Непосредственно доступ к данным растрового изображения (~ 100 миллисекунд) - Самый быстрый
Итак, если у вас не может быть небезопасный код, тогда Color Matrix намного лучше, чем SetPixel.
public static void Negate(Bitmap image)
{
const int RED_PIXEL = 2;
const int GREEN_PIXEL = 1;
const int BLUE_PIXEL = 0;
BitmapData bmData = currentImage.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);
try
{
int stride = bmData.Stride;
int bytesPerPixel = (currentImage.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4);
unsafe
{
byte* pixel = (byte*)(void*)bmData.Scan0;
int yMax = image.Height;
int xMax = image.Width;
for (int y = 0; y < yMax; y++)
{
int yPos = y * stride;
for (int x = areaSize.X; x < xMax; x++)
{
int pos = yPos + (x * bytesPerPixel);
pixel[pos + RED_PIXEL] = (byte)(255 - pixel[pos + RED_PIXEL]);
pixel[pos + GREEN_PIXEL] = (byte)(255 - pixel[pos + GREEN_PIXEL]);
pixel[pos + BLUE_PIXEL] = (byte)(255 - pixel[pos + BLUE_PIXEL]);
}
}
}
}
finally
{
image.UnlockBits(bmData);
}
}
Если вам интересно, вот код для цветовой матрицы:
public static void Negate(Bitmap image)
{
Bitmap clone = (Bitmap) image.Clone();
using (Graphics g = Graphics.FromImage(image))
{
// negation ColorMatrix
ColorMatrix colorMatrix = new ColorMatrix(
new float[][]
{
new float[] {-1, 0, 0, 0, 0},
new float[] {0, -1, 0, 0, 0},
new float[] {0, 0, -1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
});
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(clone, new Rectangle(0, 0, clone.Width, clone.Height),
0, 0, clone.Width, clone.Height, GraphicsUnit.Pixel, attributes);
}
}