0

So i try to use ONNX file for local object detection, work great in UWP and WPF with local saved image.

Now, the problem is, to use my detection algorithm with 3D live camera.

My detection algorithm expect a (Windows.Media.)VideoFrame, and my camera give me an (System.Windows.Media.Imaging.)WriteableBitmap.

So here what i have donne already :

Convert my WriteableBitmap to Bitmap :

    private System.Drawing.Bitmap BitmapFromWriteableBitmap(System.Windows.Media.Imaging.WriteableBitmap writeBmp)
    {
        System.Drawing.Bitmap bmp;
        using (MemoryStream outStream = new MemoryStream())
        {
            System.Windows.Media.Imaging.BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)writeBmp));
            enc.Save(outStream);
            bmp = new System.Drawing.Bitmap(outStream);
        }
        return bmp;
    }

Now i want to tranform my Bitmap to SoftwareBitmap (for creating a VideoFrame with VideoFrame.CreateWithSoftwareBitmap)

    Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
    Stream strm;
    private async Task<SoftwareBitmap> SoftWareBitmapFromBitmap(Bitmap bitmap)
    {
        SoftwareBitmap softwareBitmap2;

        strm = stream.AsStream();

        bitmap.Save(strm, ImageFormat.Png);

        Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);

        softwareBitmap2 = await decoder.GetSoftwareBitmapAsync();

        return softwareBitmap2;
    }

But in this last function i got an error in :

bitmap.Save(strm, ImageFormat.Bmp);

I got the "A generic error occurred in GDI+."

I have try to lock/unlock the bitmap, i have try different ImageFormat, if i change to 'ImageFormat.MemoryBmp' i got an "Value cannot be null".

Thank you.

  • 1
    Why use GDI? Use a WPF encoder to save WPF's WritableBitmap into a (memory) stream https://stackoverflow.com/a/42272557/403671 and load a UWP's SoftwareBitmap back from that stream using a UWP decoder https://stackoverflow.com/a/46703617/403671 – Simon Mourier Feb 11 '21 at 08:13
  • You already have that MemoryStream. Just pass it directly to the Windows.Graphics.Imaging.BitmapDecoder. The intermediate Bitmap is useless. – Clemens Feb 11 '21 at 09:58

1 Answers1

0

I dont know how to quotes or thumb up answer and sorry for that.

That work great just with : outStream.AsRandomAccessStream()

Here the final function :

        public async Task<System.Windows.Shapes.Rectangle> GetPositionDetection(WriteableBitmap wrtBitmap, double imageWidth, double imageHeight)
    {
        try
        {

            MemoryStream outStream = new MemoryStream();
            System.Windows.Media.Imaging.BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)wrtBitmap));
            enc.Save(outStream);

            Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();

            Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(outStream.AsRandomAccessStream());
            SoftwareBitmap tmp2 = await decoder.GetSoftwareBitmapAsync();

            VideoFrame inputImage = VideoFrame.CreateWithSoftwareBitmap(tmp2);

            IList<PredictionModel> ResultsList = await objDetec.PredictImageAsync(inputImage);

            if (ResultsList.Count == 0)
            {
                Console.WriteLine("Object not detected");
                return null;
            }
            else
            {
                var itm = ResultsList.First(x => x.Probability == ResultsList.Max(y => y.Probability));
                System.Windows.Shapes.Rectangle rct = new System.Windows.Shapes.Rectangle();
                rct.Stroke = System.Windows.Media.Brushes.Red;// new SolidColorBrush(Windows.UI.Colors.Red);
                rct.StrokeThickness = 2;
                rct.Width = imageWidth * (MappingEchellefloat(0, 1, 0, 100, itm.BoundingBox.Width) / 100);
                rct.Height = imageHeight * (MappingEchellefloat(0, 1, 0, 100, itm.BoundingBox.Height) / 100);

                Console.WriteLine("Object returned : " + ResultsList.Count);


                return rct;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }

Thank you for your help.

  • It is better if you could mark your answer so that other people who has the same question could refer to this case. – YanGu Feb 26 '21 at 01:33