0

I need some help on how to convert 'System.Drawing.Image' to 'System.Windows.Media.ImageSource'

In the bellow code, var responseImage = System.Drawing.Image.FromStream(responseStream); is a System.Drawing.Image but the imageControl variable im trying to display the image to is a System.Windows.Controls.Image

My first attempt was this:


// Create a concurrent queue to store response images
                    var responseQueue = new ConcurrentQueue<System.Windows.Controls.Image>();

                    // Set up the event handler to add response images to the queue
                    ws.OnMessage += (sender, e) =>
                    {
                        var responseBytes = e.RawData;
                        using (var responseStream = new MemoryStream(responseBytes))
                        {
                            var responseImage = new System.Drawing.Bitmap(responseStream);
                            var bitmapImage = new BitmapImage();
                            bitmapImage.BeginInit();
                            MemoryStream ms = new MemoryStream();
                            responseImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                            ms.Seek(0, SeekOrigin.Begin);
                            bitmapImage.StreamSource = ms;
                            bitmapImage.EndInit();
                            var NresponseImage = new System.Windows.Controls.Image();
                            NresponseImage.Source = bitmapImage;
                            responseQueue.Enqueue(NresponseImage);
                        }
                    };

But it returned the following error:

System.InvalidOperationException: 'The calling thread must be STA, because many UI components require this.'

My second attempt which included putting the image control in a dispatcher invoke:

// Create a concurrent queue to store response images
                    var responseQueue = new ConcurrentQueue<System.Windows.Controls.Image>();

                    ws.OnMessage += (sender, e) =>
                    {
                        var responseBytes = e.RawData;
                        using (var responseStream = new MemoryStream(responseBytes))
                        {
                            var responseImage = new System.Drawing.Bitmap(responseStream);
                            var bitmapImage = new BitmapImage();
                            bitmapImage.BeginInit();
                            MemoryStream ms = new MemoryStream();
                            responseImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                            ms.Seek(0, SeekOrigin.Begin);
                            bitmapImage.StreamSource = ms;
                            bitmapImage.EndInit();
                            System.Windows.Application.Current.Dispatcher.Invoke(() =>
                            {
                                var NresponseImage = new System.Windows.Controls.Image();
                                NresponseImage.Source = bitmapImage;
                                responseQueue.Enqueue(NresponseImage);
                            });
                        }
                    };

But this returned the following error:

System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'

Here is the Method in question:

private void CaptureCameraCallback(int camInd, System.Windows.Controls.Image imageControl)
    {
        // Create a new WebSocket connection
        using (var ws = new WebSocketSharp.WebSocket("ws://localhost:8000/ws"))
        {
            // Connect to the WebSocket server
            ws.Connect();

            // Create a new video capture object
            using (var capture = new VideoCapture(camInd))
            {
                // Create a concurrent queue to store response images
                var responseQueue = new ConcurrentQueue<System.Windows.Controls.Image>();

                // Set up the event handler to add response images to the queue
                ws.OnMessage += (sender, e) =>
                {
                    var responseBytes = e.RawData;
                    using (var responseStream = new MemoryStream(responseBytes))
                    {
                        var responseImage = new System.Drawing.Bitmap(responseStream);
                        var bitmapImage = new BitmapImage();
                        bitmapImage.BeginInit();
                        MemoryStream ms = new MemoryStream();
                        responseImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                        ms.Seek(0, SeekOrigin.Begin);
                        bitmapImage.StreamSource = ms;
                        bitmapImage.EndInit();

                        // Use the Dispatcher to add the image to the queue on the UI thread
                        System.Windows.Application.Current.Dispatcher.Invoke(() =>
                        {
                            var NresponseImage = new System.Windows.Controls.Image
                            {
                                Source = bitmapImage
                            };
                            responseQueue.Enqueue(NresponseImage);
                        });
                    }
                };

                // Start a loop to capture frames and send them to the Flask API.
                while (true)
                {
                    // Create a new Mat object to store the frame
                    using (var frame = new Mat())
                    {
                        // Read the next frame from the camera.
                        capture.Read(frame);

                        // Check if the frame is not empty.
                        if (!frame.Empty())
                        {
                            // Encode the frame as a JPEG image
                            var buffer = new byte[frame.Width * frame.Height * frame.ElemSize()];
                            Cv2.ImEncode(".jpg", frame, out buffer);

                            // Send the image to the server
                            ws.Send(buffer);

                            if (responseQueue.TryDequeue(out var responseImage))
                            {
                                // Convert System.Drawing.Image to System.Windows.Media.ImageSource
                                //var bitmap = new Bitmap(responseImage);

                                // Load the image from the file in the same directory as the executable
                                //var uri = new Uri(System.IO.Path.GetFullPath("C:/Users/nico_/Downloads/cat.jpeg"));
                                //var bitmapSource = new BitmapImage(uri);

                                // Display the image on the UI thread
                                Dispatcher.Invoke(() =>
                                {
                                    imageControl.Source = responseImage.Source;
                                });
                            }
                        }
                        else
                        {
                            // If the frame is empty, log an error and continue to the next frame.
                            Debug.WriteLine("Unable to capture Frame");
                            continue;
                        }
                    }
                }
            }
        }
    }

I hope someone can help with this dilemma.

Thanks!

0 Answers0