I have created a WPF application in .NET 4.6.1. to display video from the frame grabbing event for a machine vision camera.
In XAML there is an image control bound to a WriteableBitmap
<Image x:Name="CameraImage" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Source="{Binding CameraImage}"/>
In the code-behind:
public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null) { //Console.WriteLine(propertyName); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private WriteableBitmap cameraImage; private IntPtr cameraImagePtr; public WriteableBitmap CameraImage { get { return cameraImage; } set { cameraImage = value; cameraImagePtr = cameraImage.BackBuffer; NotifyPropertyChanged(); } }
The WriteableBitmap
is initialised as so:
CameraImage = new WriteableBitmap(2448, 2048, 0, 0, PixelFormats.Bgr24, null);
In the grab event generated by the camera we have:
// Occurs when an image has been acquired and is ready to be processed. private void OnImageGrabbed(Object sender, ImageGrabbedEventArgs e) { try { // Get the grab result. IGrabResult grabResult = e.GrabResult; // Check if the image can be displayed. if (grabResult.IsValid) { byte[] buffer = grabResult.PixelData as byte[]; converter.OutputPixelFormat = PixelType.BGR8packed; lock(cameraImage) { // Converts camera Bayer array image to BGR image and saves at cameraImagePtr converter.Convert(cameraImagePtr, 2448 * 2048 * 3, grabResult); } // Make WriteableBitmap dirty (on UI thread) so that the WPF Image control redraws Dispatcher.Invoke(new Action(() => { cameraImage.Lock(); cameraImage.AddDirtyRect(new Int32Rect(0, 0, cameraImage.PixelWidth, cameraImage.PixelHeight)); cameraImage.Unlock(); }), DispatcherPriority.Render); } } catch (Exception exception) { Console.WriteLine(exception.Message); throw exception; } finally { // Dispose the grab result if needed for returning it to the grab loop. e.DisposeGrabResultIfClone(); } }
Questions
-
I can’t just pass
cameraImage.BackBuffer
to the writing (Converter.convert()
) function, I have to docameraImagePtr = cameraImage.BackBuffer;
and then usecameraImagePtr
. Why is that? -
The fans on my laptop spin up when this is running – it seems like it is using a lot of CPU. Is there a more efficient way? From what I can tell I am not making extra copies of the frame.