I'm working with WriteableBitmap (PixelFormats.Bgr32). This is the format I need to save for the rest of the program to work.
Writable = new WriteableBitmap(inImage.XSize, inImage.YSize, dpi, dpi, PixelFormats.Bgr32, null);
The image from the device comes in grayscaled, (ushort[] Gray16). To use this image in my program I use the following code (inImage - received image, ImageData = ushort[]):
int[] pixels = Array.ConvertAll(inImage.ImageData, val => checked((int)val));
Writable.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
If I just use
Writable.WritePixels(new Int32Rect(0, 0, width, height), inImage.ImageData, width * 4, 0);
I get a message about insufficient buffer size. (System.ArgumentException: "Buffer size is not sufficient." )
Code
int[] pixels = Array.ConvertAll(inImage.ImageData, val => checked((int)val))
or
int[] pixels = new int[inImage.XSize * inImage.YSize];
for (int i = 0; i < inImage.ImageData.Length; i++)
{
pixels[i] = inImage.ImageData[i];
}
This seems to me to be a very long and slow and unoptimized process.
Is there any way to optimize the process and immediately write ushort[] array to WriteableBitmap (Bgr32) without converting it to int[] ?
EDIT***
I need this code to be able to work with images with a resolution of 4300x4300 with 45 FPS. Below is the full code how I load images (this code is called 45 times per second to load a new image)
public class ImageStruct
{
public ushort[] ImageData;
public int XSize;
public int YSize;
public int XDpi;
public int YDpi;
}
WriteableBitmap Writeable;
public void LoadFrame(ImageStruct inImage)
{
var width = inImage.XSize;
var height = inImage.YSize;
var destBpp = PixelFormats.Bgr32.BitsPerPixel / 8;
var uPixels = inImage.ImageData;
fluoroWritable = new WriteableBitmap(inImage.XSize, inImage.YSize, 96, 96, PixelFormats.Bgr32, null);
var iPixels = Array.ConvertAll(uPixels, val => checked((int)val));
fluoroWritable.WritePixels(new Int32Rect(0, 0, width, height), iPixels, width * 4, 0);
}
This code works well when FPS is ~10, If you increase the FPS, it starts to freeze. Profiling shows that it is the moment when I make from ushort[] => int[] takes the longest time.
I tried to use the code suggested in the answer below:
unsafe public void LoadFrameWithLock(ImageStruct inImage)
{
var width = inImage.XSize;
var height = inImage.YSize;
var destBpp = PixelFormats.Bgr32.BitsPerPixel / 8;
var uPixels = inImage.ImageData;
fluoroWritable = new WriteableBitmap(inImage.XSize, inImage.YSize, 96, 96, PixelFormats.Bgr32, null);
fluoroWritable.Lock();
int* outputIntValues = (int*)fluoroWritable.BackBuffer;
ushort[] inputShortValues = inImage.ImageData;
for (int i = 0; i < inputShortValues.Length; i++)
{
byte as8bpp = (byte)(inputShortValues[i] >> 8);
outputIntValues[i] = /*B*/ as8bpp | /*G*/ (as8bpp << 8) | /*R*/ (as8bpp << 16);
}
fluoroWritable.AddDirtyRect(new Int32Rect(0, 0, fluoroWritable.PixelWidth, fluoroWritable.PixelHeight));
fluoroWritable.Unlock();
}
But the FPS with this code is even lower and in addition the WPF application has a completely hanging interface. and images have no grayscale, but are completely black and white (white or black pixels).
I need the BGR32 format because this WritableBitmap (WPF Image object) is then overlaid with shader effects, and I can also get color images in another place.
Yes, instead of calling
WritePixelsuse theLockmethod so theBackBufferwill be available as a naked pointer (do not forget to callUnlockwhen you are finished).Please note though that as your source and target pixel formats are different (16bpp grayscale vs. 32bpp BGRx) simple casting of short values to int will not be correct. All 16 bit grayscale values must be converted to 8 bit RGB values:
The sample above needs to be inside of an
unsafescope because of the pointer and you must enable unsafe blocks for your project in your .csproj file.To make things simpler you can use my Drawing Libraries, which now has dedicated WPF support so the conversion will just be literally two lines. It does not need
unsafecontext and is actually faster than the example above because it uses parallel processing: