Rok
Rok

Reputation: 705

Blue and red channels swapped during conversion from bitmap to bitmapsource

I need to copy a bitmap that I receive from a camera into a BitmapSource in order to show it in a WPF application. Image arrives in PixelFormat.Format24bppRgb with a negative stride. I got this working by following code

//NOTE: image is in PixelFormat.Format24bppRgb
var bitmap = imageBuffer.Bitmap;
Image = new WriteableBitmap(bitmap.Width, bitmap.Height, 96, 96, PixelFormats.Rgb24, null);

var bitmapData = bitmap.LockBits(
    new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
    System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
var rowSize = bitmapData.Stride < 0 ? -bitmapData.Stride : bitmapData.Stride;
var bitmapPtr = bitmapData.Scan0;
var bitmapLine = new Int32Rect(0, 0, bitmap.Width, 1);

for (int line = 0; line < bitmap.Height; line++)
{
    Image.WritePixels(bitmapLine, bitmapPtr, rowSize, rowSize, 0, line);
    bitmapPtr += bitmapData.Stride;
}
bitmap.UnlockBits(bitmapData);

The problem I am running into is that that blue and red channels seem to be swapped. I could resolve the issue by creating the BitmapSource as Bgr24 but since in application I need to also do some image processing prior to conversion I would prefer to have things in a correct format prior to that. Am I doing something wrong in the conversion or is this some GDI peculiarity?

Note that if I apply the camera bitmap directly to a WinForms picture box, the image is displayed correctly. Also WriteableBitmap is only recreated for the sake of code brevity.

Upvotes: 2

Views: 1747

Answers (2)

Rok
Rok

Reputation: 705

The correct conversion from System.Drawing.Imaging.PixelFormat.Format24bppRgb to System.Windows.Media.PixelFormat is PixelFormats.Bgr24.

Negative stride has nothing to do with with the pixel format, it only describes vertical rotation of the image - top down for positive and bottom up for negative. If the stride had any effect on the pixel format, then the code below would have stored the images with reversed stride with blue and red channel swapped. This is not the case and the only effect seen is that one image is vertically rotated.

var wholeImage = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
bitmapData = bitmap.LockBits(wholeImage, ImageLockMode.ReadOnly, bitmap.PixelFormat);
var reverseStride = -bitmapData.Stride;
var reversedStartPtr = bitmapData.Scan0 + bitmapData.Stride * (bitmapData.Height - 1);

var reverseStrideBitmap = new Bitmap(bitmapData.Width, bitmapData.Height, 
                              reverseStride, bitmapData.PixelFormat, reversedStartPtr);

bitmap.Save("original.png");
reverseStrideBitmap.Save("reversedStride.png");

Upvotes: 0

Gusman
Gusman

Reputation: 15151

If the image format you receive is RGB but the stride is negative, then the image format is BGR as it's being read backwards.

Negative stride means it's an image bottom-up instead of top-down, usually the draw operations of Graphics would handle these things for you, but the Image class WritePixels doesn't allow to specify a negative stride, so you must reverse the pixel format (BGR)

Upvotes: 2

Related Questions