Если вам нужно более быстрое действие на изображении, вы можете использовать Marshall.Copy метод с Parallel.For
Почему не используется метод GetPixel ? Потому что каждый раз, когда вы звоните, все ваше изображение загружается в память. GetPixel получит один пиксель и разгрузит все изображение. И на каждой итерации ВСЕ изображение загружается в память (например, если вы работаете с изображением размером 500x500 пикселей, GetPixel будет загружать в память 500x500 раз целых пикселей). Когда вы работаете с изображениями в C # (CV), работайте с необработанными bytes
из памяти.
Я покажу, как использовать с Lockbits
в Бинаризация , потому что это легко объяснить.
int pixelBPP = Image.GetPixelFormatSize(resultBmp.PixelFormat) / 8;
unsafe
{
BitmapData bmpData = resultBmp.LockBits(new Rectangle(0, 0, resultBmp.Width, resultBmp.Height), ImageLockMode.ReadWrite, resultBmp.PixelFormat);
byte* ptr = (byte*)bmpData.Scan0; //addres of first line
int height = resultBmp.Height;
int width = resultBmp.Width * pixelBPP;
Parallel.For(0, height, y =>
{
byte* offset = ptr + (y * bmpData.Stride); //set row
for(int x = 0; x < width; x = x + pixelBPP)
{
byte value = (offset[x] + offset[x + 1] + offset[x + 2]) / 3 > threshold ? Byte.MaxValue : Byte.MinValue;
offset[x] = value;
offset[x + 1] = value;
offset[x + 2] = value;
if (pixelBPP == 4)
{
offset[x + 3] = 255;
}
}
});
resultBmp.UnlockBits(bmpData);
}
Теперь, пример с Marshall.copy
:
BitmapData bmpData = resultBmp.LockBits(new Rectangle(0, 0, resultBmp.Width, resultBmp.Height),
ImageLockMode.ReadWrite,
resultBmp.PixelFormat
);
int bytes = bmpData.Stride * resultBmp.Height;
byte[] pixels = new byte[bytes];
Marshal.Copy(bmpData.Scan0, pixels, 0, bytes); //loading bytes to memory
int height = resultBmp.Height;
int width = resultBmp.Width;
Parallel.For(0, height - 1, y => //seting 2s and 3s
{
int offset = y * stride; //row
for (int x = 0; x < width - 1; x++)
{
int positionOfPixel = x + offset + pixelFormat; //remember about pixel format!
//do what you want with pixel
}
}
});
Marshal.Copy(pixels, 0, bmpData.Scan0, bytes); //copying bytes to bitmap
resultBmp.UnlockBits(bmpData);
Помните, что при работе с RAW bytes
очень важно помнить о PixelFormat
. Если вы работаете с RGBA
изображением, вам нужно настроить каждый канал. (например offset + x + pixelFormat
). Я показал это в Binarization
примере, как обработать изображение RGBA с необработанными данными. Если lockbits
не достаточно быстро, используйте Marshall.Copy