如何创建从像素字节数组的BitmapImage(现场视频显示) [英] How to create a BitmapImage from a pixel byte array (live video display)

查看:219
本文介绍了如何创建从像素字节数组的BitmapImage(现场视频显示)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在一个WPF控件显示实时图像。 。我正在寻找这样做使用WPF的最快方法



我从相机中使用的DLL API(拍摄图像的AVT )。



图像writen由DLL和相机用起来一个I​​ntPtr回调称为图像结构的 TFRAME (如下所述)。像素数据存储在ImageBuffer的propertie用是InPtr为字节数组。



我知道如何创建从像素字节数组位图,但不是的BitmapImage 。因此可以建立一个位图,然后从它创建一个BitmapImagem。
这里有一个办法从内存位图创建的BitmapImage。但我想从数据源(TFRAME)创建的BitmapImage 直接。我该怎么做?



我知道的BitmapImage有CopyPixels方法,但它LAKS一个的setPixels的。

 公共结构TFRAME 
{
公众的IntPtr AncillaryBuffer;
公共UINT AncillaryBufferSize;
公共UINT AncillarySize;
公共tBayerPattern BayerPattern;
公共UINT位深度;
公共tFrameCtx语境;
公共tImageFormat格式;
公共UINT FrameCount;
公共UINT高度;
公众的IntPtr ImageBuffer的;
公共UINT ImageBufferSize;
公共UINT IMAGESIZE;
公共UINT RegionX;
公共UINT RegionY;
公共TERR状态;
公共UINT TimestampHi;
公共UINT TimestampLo;
公共UINT宽度;
}

下面是我如何创建一个像素字节数组的位图。这一点在软件的WinForm的版本中使用。

 私人无效CreateBitmap(TFRAME帧)
{
//此示例是一个8bpp拍摄的图像
的PixelFormat pxFormat = PixelFormat.Format8bppIndexed;

// STRIDE
//[http://stackoverflow.com/questions/1983781/why-does-bitmapsource-create-throw-an-argumentexception/1983886#1983886][3 ]
//浮动bitsPerPixel = System.Drawing.Image.GetPixelFormatSize(格式);
INT bitsPerPixel =((int)的pxFormat>→8)及0xFF的;
//用于存储每行图像数据(只有有效数据)的位数
INT validBitsPerLine =((int)的frame.Width)* bitsPerPixel;
// 4字节,每INT32(32位)
INT跨距=((validBitsPerLine + 31)/ 32)* 4;

BMP位图=新位图((INT)frame.Width,(INT)frame.Height,步幅,pxFormat,frame.ImageBuffer);
}






编辑1:



感谢dr.mo,现在我能够与〜3%的CPU使用率,以显示60帧图像的1024×1024!
我做的是什么:

  // @ UI线程
公共WriteableBitmap的WBM =新的WriteableBitmap的(1024,1024,(双)96,(双)96,System.Windows.Media.PixelFormats.Gray8,NULL);
this.wbBackBuffer = this.wbm.BackBuffer;

//这可以通过在UI线程或在线程抓住每一个图像的计时器被调用,CPU使用率几乎是相同的。
无效UpdateDisplayImage()
{
wbm.Lock();
wbm.AddDirtyRect(新Int32Rect(0,0,wbm.PixelWidth,wbm.PixelHeight));
wbm.Unlock();
}

// @抢螺纹
//更新与新相机的图像数据的后备缓冲。
UpdateBackBuffer(...);

///<总结>
/// [http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx]
///< /总结>
公共无效UpdateBackBuffer(IntPtr的pData所,诠释W,INT小时,INT CH)
{
//不能接取从外部UI线程
//CopyMemory(wbm.BackBuffer WBM中,pdata,(UINT)(W * H * CH));
//我不知道是否安全写信给它缓冲这样的:
CopyMemory的(this.wbBackBuffer中,pdata,(UINT)(W * H * CH));
}


解决方案

这应该做的伎俩。这是超级快。

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;使用System.Threading.Tasks
;使用System.Windows
;使用System.Windows.Controls的
;
使用System.Windows.Data;使用System.Windows.Documents
;
使用System.Windows.Input;使用System.Windows.Media
;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;使用System.Windows.Shapes
;

使用System.Drawing中;使用System.Runtime.InteropServices
;
:使用System.IO;
使用System.ComponentModel;


公共类MakeBitmapSource
{
函数[DllImport(KERNEL32.DLL,入口点=RtlMoveMemory)]
公共静态外部无效CopyMemory的( IntPtr的目标,IntPtr的来源,UINT长度);



公共静态的BitmapSource FromNativePointer(IntPtr的pData所,诠释W,INT小时,INT CH)
{
格式的PixelFormat = PixelFormats.Default;

如果(CH == 1)格式= PixelFormats.Gray8; //灰度图像0-255
如果(CH == 3)格式= PixelFormats.Bgr24; // RGB
如果(CH == 4)格式= PixelFormats.Bgr32; // RGB +阿尔法


WriteableBitmap的WBM =新WriteableBitmap的(W,H,96,96,格式,空);
CopyMemory的(wbm.BackBuffer中,pdata,(UINT)(W * H * CH));

wbm.Lock();
wbm.AddDirtyRect(新Int32Rect(0,0,wbm.PixelWidth,wbm.PixelHeight));
wbm.Unlock();

返回WBM;
}

公共静态的BitmapSource FromArray(字节[]数据,INT W,INT小时,INT CH)
{
格式的PixelFormat = PixelFormats.Default;

如果(CH == 1)格式= PixelFormats.Gray8; //灰度图像0-255
如果(CH == 3)格式= PixelFormats.Bgr24; // RGB
如果(CH == 4)格式= PixelFormats.Bgr32; // RGB +阿尔法


WriteableBitmap的WBM =新WriteableBitmap的(W,H,96,96,格式,空);
wbm.WritePixels(新Int32Rect(0,0,W,H),数据,CH *瓦特,0);

返回WBM;
}
}


I need to display live images on a WPF control. I'm looking for the fastest way to do this using WPF.

I'm capturing images from a camera using its dll API (AVT).

The image is writen by the dll and the camera rises a callback with an IntPtr to a Image struct called tFrame (described below). The pixel data is stored at the ImageBuffer propertie with is an InPtr to a byte array.

I know how to create a Bitmap from the pixel byte array, but not a BitmapImage. So it is possible to create a Bitmap and then create a BitmapImagem from it. Here there is a way to create a BitmapImage from a Bitmap on the memory. But I want to create the BitmapImage directly from the data source (tFrame). How can I do that?

I know that BitmapImage have a CopyPixels method, but it laks of a SetPixels.

public struct tFrame
{
    public IntPtr AncillaryBuffer;
    public uint AncillaryBufferSize;
    public uint AncillarySize;
    public tBayerPattern BayerPattern;
    public uint BitDepth;
    public tFrameCtx Context;
    public tImageFormat Format;
    public uint FrameCount;
    public uint Height;
    public IntPtr ImageBuffer;
    public uint ImageBufferSize;
    public uint ImageSize;
    public uint RegionX;
    public uint RegionY;
    public tErr Status;
    public uint TimestampHi;
    public uint TimestampLo;
    public uint Width;
}

Here is how I create a Bitmap from a pixel byte array. This was used at the WinForm version of the software.

private void CreateBitmap(tFrame frame)
{
    //This sample is for a 8bpp captured image
    PixelFormat pxFormat = PixelFormat.Format8bppIndexed;

    //STRIDE
    //[http://stackoverflow.com/questions/1983781/why-does-bitmapsource-create-throw-an-argumentexception/1983886#1983886][3]
    //float bitsPerPixel = System.Drawing.Image.GetPixelFormatSize(format);
    int bitsPerPixel = ((int)pxFormat >> 8) & 0xFF;
    //Number of bits used to store the image data per line (only the valid data)
    int validBitsPerLine = ((int)frame.Width) * bitsPerPixel;
    //4 bytes for every int32 (32 bits)
    int stride = ((validBitsPerLine + 31) / 32) * 4;

    Bitmap bmp = new Bitmap((int)frame.Width, (int)frame.Height, stride, pxFormat, frame.ImageBuffer);
}


EDIT 1:

Thanks to dr.mo, now I'm able to display 60 FPS 1024x1024 images with ~3% CPU usage! What I'm doing is:

//@ UI Thread
public WriteableBitmap wbm = new WriteableBitmap(1024, 1024, (double)96, (double)96, System.Windows.Media.PixelFormats.Gray8, null);
this.wbBackBuffer = this.wbm.BackBuffer;

//This can be called by a timer in the UI thread or at the grab Thread for every image, the CPU usage is almost the same.
void UpdateDisplayImage()
{
wbm.Lock();
wbm.AddDirtyRect(new Int32Rect(0, 0, wbm.PixelWidth, wbm.PixelHeight));
wbm.Unlock();
}

//@ Grab Thread
//Update the backbuffer with new camera image data.
UpdateBackBuffer(...);

/// <summary>
/// [http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx]
/// </summary>
public void UpdateBackBuffer(IntPtr pData, int w, int h, int ch)
{
    //Can not acess wbm from outside UI thread
    //CopyMemory(wbm.BackBuffer, pData, (uint)(w * h * ch));
    //I dont know if it is safe to write to it buffer like this:
    CopyMemory(this.wbBackBuffer, pData, (uint)(w * h * ch));
}

解决方案

This should do the trick. it's super fast.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.ComponentModel;


public class MakeBitmapSource
{
    [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
    public static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);



    public static BitmapSource FromNativePointer(IntPtr pData, int w, int h, int ch)
    {
        PixelFormat format = PixelFormats.Default;

        if (ch == 1) format = PixelFormats.Gray8; //grey scale image 0-255
        if (ch == 3) format = PixelFormats.Bgr24; //RGB
        if (ch == 4) format = PixelFormats.Bgr32; //RGB + alpha


        WriteableBitmap wbm = new WriteableBitmap(w, h, 96, 96, format, null);
        CopyMemory(wbm.BackBuffer, pData, (uint)(w * h * ch));

        wbm.Lock();
        wbm.AddDirtyRect(new Int32Rect(0, 0, wbm.PixelWidth, wbm.PixelHeight));
        wbm.Unlock();

        return wbm;
    }

    public static BitmapSource FromArray(byte[] data, int w, int h, int ch)
    {
        PixelFormat format = PixelFormats.Default;

        if (ch == 1) format = PixelFormats.Gray8; //grey scale image 0-255
        if (ch == 3) format = PixelFormats.Bgr24; //RGB
        if (ch == 4) format = PixelFormats.Bgr32; //RGB + alpha


        WriteableBitmap wbm = new WriteableBitmap(w, h, 96, 96, format, null);
        wbm.WritePixels(new Int32Rect(0, 0, w, h), data, ch * w, 0);

        return wbm;
    }
}

这篇关于如何创建从像素字节数组的BitmapImage(现场视频显示)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆