public static List<float> ParallelExtractCHW(this Bitmap image)
{
// We use local variables to avoid contention on the image object through the multiple threads.
int channelStride = image.Width * image.Height;
int imageWidth = image.Width;
int imageHeight = image.Height;
var features = new byte[imageWidth * imageHeight * 3];
var bitmapData = image.LockBits(new Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.ReadOnly, image.PixelFormat);
IntPtr ptr = bitmapData.Scan0;
int bytes = Math.Abs(bitmapData.Stride) * bitmapData.Height;
byte[] rgbValues = new byte[bytes];
int stride = bitmapData.Stride;
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// The mapping depends on the pixel format
// The mapPixel lambda will return the right color channel for the desired pixel
Func<int, int, int, int> mapPixel = GetPixelMapper(image.PixelFormat, stride);
// Averaged over a large number of images, these loops here execute fastest
// when doing Parallel.For only over c, but not over h and w.
Parallel.For(0, 3, (int c) =>
{
for (int h = 0; h < imageHeight; h++)
{
for (int w = 0; w < imageWidth; w++)
{
features[channelStride * c + imageWidth * h + w] = rgbValues[mapPixel(h, w, c)];
}
}
});
image.UnlockBits(bitmapData);
return features.Select(b => (float)b).ToList();
}