none
Efficiently make a cropped bitmap image from frame buffer bytes. RRS feed

  • Question

  • I am developing an application that takes live video input and maps it onto a WPF Image (this is working just fine); the problem is that I need only a cropped region of the video to display.

    From the library I'm using, I can get the framebuffer (int32ptr to raw data) plus the other necessary information, like image height, width, and format.

    The following works perfectly to generate a full frame:

     Dim source As BitmapSource = BitmapSource.Create(
                        av_props.vidProps.nWidth,
                        Math.Abs(av_props.vidProps.nHeight),
                        96, 96,
                        PixelFormats.Bgr32, Nothing,
                        New IntPtr(framePointer), frameDataSize,
                        av_props.vidProps.nRowBytes
                    )

    Obviously: av_props is an object from the video library; framePointer and frameData size are what you expect them to be.  The above code works flawlessly.

    Now I want a cropped image, let's say a 200 by 200 section starting 100 from both the top and left.

    Dim rect As New Int32Rect(100, 100, 200, 200)
    Dim cutout As CroppedBitmap = New CroppedBitmap(source, rect)
    

    This also works perfectly.  The question comes down to one of efficiency.  Using a CroppedBitmap, it seems like it should be possible to skip the intermediate step of creating a full bitmap only to crop it.  The syntax would be something like:

    dim cropped as new CroppedBitmap()
    cropped.copy(rect, new Int32Ptr(frameBuffer), frameDataSize, av_props.vidProps.nRowBytes)

    The problem, of course, is "cropped" is not initialized - it doesn't know the pixel format, for example, so it can't even tell how many bytes per pixel.  These values are read-only; using "cropped.BeginInit()" does not allow you to set them.

    This will be running alongside another time-sensitive program, so I'm trying to be as efficient as possible.  I've been reading through the various BitmapSource sub-classes, and am not finding anything.

    BTW, the frame capture is in it's own thread, so I need to "freeze" the BitmapSource before I am allowed to apply it to a WPF Image.  BTW, I am a long time developer, but short time .Net developer, so most of this stuff is new to me, so forgive me if this should have an obvious answer.

    Thursday, July 20, 2017 1:12 AM

All replies

  • The problem, of course, is "cropped" is not initialized - it doesn't know the pixel format, for example, so it can't even tell how many bytes per pixel.  These values are read-only; using "cropped.BeginInit()" does not allow you to set them.

    If you subclass CroppedBitmap and create a custom constructor that does not require a source, then you have access to the CroppedBitmap base during initialisation (a Source object) and you could call .Create() on that instance, passing in the required parameters (which you would include in your custom constructor signature). Whether that improves the performance or not would have to be determined by experiment. I haven't used either of those classes, but it would look roughly like:

    Public Class MyCroppedBitmap(Int32, Int32, Double, Double, PixelFormat, BitmapPalette, IntPtr, Int32, Int32, Int32Rect)
        Inherits CroppedBitmap
        MyBase.Create(Int32, Int32, Double, Double, PixelFormat, BitmapPalette, IntPtr, Int32, Int32)
        SourceRect = Int32Rect
    End Class


    Thursday, July 20, 2017 1:47 AM