WPF 使用内存映射显示相机传回的图像数据

1.相机数据封装

这里以大恒的水星相机为例,下图是相机回调委托定义:

1).定义相机数据实体

cs 复制代码
public class ImageData
{
    public IntPtr GrayPixel { get; set; }
    
    public int Width { get; set; }

    public int Height { get; set; }
}

其中GrayPixel 表示相机图像数据,是指向字节数组的指针;Width和Height分别表示图像的宽度和高度;

2).填充相机数据实体

cs 复制代码
 //IFrameData data  
//data是大恒相机回调方法的参数
var w = data.GetWidth();
var h = data.GetHeight();
//定义字节数组接受相机数据
byte[]  imgbuffer = new byte[w * h];
//赋值
Marshal.Copy(data.GetBuffer(), imgbuffer, 0, (int)(imgw * imgh));
var imageData = new ImageData()
{
    //获得一个数组的第某个元素的内存地址
    GrayPixel = Marshal.UnsafeAddrOfPinnedArrayElement(imgbuffer, 0),
    Width = (int)w ,
    Height =(int)h 
};

2.利用映射内存生成位图数据

cs 复制代码
 /// <summary>
 /// 图像source
 /// </summary>
 private InteropBitmap iBitmap;

 /// <summary>
 /// 图像数据
 /// </summary>
 private IntPtr iBitmapData;

 /// <summary>
 /// 映射文件句柄
 /// </summary>
 private IntPtr bitmapSection;

//Alpha通道数据指针
private IntPtr oneChannelAlpha;
/// <summary>
/// 控件对象
/// </summary>
internal Image imageHost;

/// <summary>
/// 生成映射文件然后转换为WPF支持的位图
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
private void CreateInteropBitmap(int width, int height)
{
    if (iBitmapData != IntPtr.Zero)
    {
        UnmapViewOfFile(iBitmapData);
        iBitmapData = IntPtr.Zero;
    }
    if (bitmapSection != IntPtr.Zero)
    {
        CloseHandle(bitmapSection);
        bitmapSection = IntPtr.Zero;
    }
    //目前仅仅是灰度图像,这里把容量*4,为待会儿转换为bgra做准备
    var imageSize = (uint)(width * height * 4);
    // 获取文件映像对象句柄
    bitmapSection = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04, 0, imageSize, null);
    //非托管资源gc获取不到数据
    //GCHandle handle = GCHandle.FromIntPtr(bitmapSection);
    // 将内存映射文件映射到进程的虚拟地址中,iBitmapData 现在指向可读写的内存区域
    iBitmapData = MapViewOfFile(bitmapSection, 0xF001F, 0, 0, imageSize);
    //从非托管内存获取位图,把共享内存中的数组转换为图片
    iBitmap = Imaging.CreateBitmapSourceFromMemorySection(bitmapSection, width, height, PixelFormats.Pbgra32, width * 4, 0) as InteropBitmap;
}



 #region DllImport
 [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
 internal static extern unsafe IntPtr memcpy(IntPtr dst, IntPtr src, int count);

 [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
 internal static extern void memset(IntPtr dst, int filler, int count);

 [DllImport("Simd.dll", EntryPoint = "SimdInterleaveBgra", PreserveSig = false)]
 internal static extern void SimdInterleaveBgra(IntPtr b, uint bStride, IntPtr g, uint gStride, IntPtr r, uint rStride, IntPtr a, uint aStride, uint width, uint height, IntPtr bgra, uint bgraStride);

 [DllImport("Simd.dll", EntryPoint = "SimdBayerToBgra", PreserveSig = false)]
 internal static extern void SimdBayerToBgra(IntPtr bayer, uint width, uint height, uint bayerStride, SimdPixelFormatType format, IntPtr bgra, uint bgraStride, byte alpha);

 [DllImport("Simd.dll", EntryPoint = "SimdDeinterleaveBgr", PreserveSig = false)]
 internal static extern void SimdDeinterleaveBgr(IntPtr bgr, uint bgrStride, uint width, uint height, IntPtr b, uint bStride, IntPtr g, uint gStride, IntPtr r, uint rStride);

 [DllImport("Simd.dll")]
 private static extern IntPtr SimdAllocate(uint size, uint align);

 [DllImport("Simd.dll")]
 private static extern void SimdFree(IntPtr ptr);

 // some ideas/code borowed from CL NUI sample CLNUIImage.cs
 [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
 private static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
 [DllImport("kernel32.dll")]
 private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);
 [DllImport("kernel32.dll")]
 private static extern bool UnmapViewOfFile(IntPtr hMap);
 [DllImport("kernel32.dll")]
 private static extern bool CloseHandle(IntPtr hHandle);
cs 复制代码
 //映射文件和位图处理
 CreateInteropBitmap(width, height);
 if (oneChannelAlpha != IntPtr.Zero)
 {
     Marshal.FreeHGlobal(oneChannelAlpha);
 }
 //申请内存
 oneChannelAlpha = Marshal.AllocHGlobal(width * height);
 //给每个字节赋值255
 memset(oneChannelAlpha, 255, width * height);
 //iBitmapData 在CreateInteropBitmap方法中已经指向了bgra图像数据
 var pixelData = iBitmapData;
 //将 8 位蓝色、绿色、红色和 Alpha 平面图像交错合并为一个 32 位 BGRA 交错图像。
 //imageData是图像数据实体里面的指针:GrayPixel 
 SimdInterleaveBgra(imageData, (uint)width, imageData, (uint)width, imageData, (uint)width, oneChannelAlpha, (uint)width, (uint)width, (uint)height, pixelData , (uint)width * 4);

 if (imageHost.Source != iBitmap)
 {
     imageHost.Source = iBitmap;
 }
 //触发图像绘制
 iBitmap.Invalidate();

tips:

调用dll的小知识:

以CreateFileMapping为例,原型:

因为调用的时候指定了Unicode,所以在C#中才可以使用CreateFileMapping而不是CreateFileMappingW。

C#引用时方法参数也是根据原型中定义的枚举设置的:

感觉图像处理的话C++要比C#方便一点。

引用:

InteropBitmap指定内存,绑定WPF的Imag控件时刷新问题。 - 亲福 - 博客园

WPF 通过共享内存播放视频 - 昨夜飘风 - 博客园

相关推荐
棱镜研途16 小时前
EI会议分享 | 2026年图像处理与模式识别国际会议(IC-IPPR 2026)【SPIE出版】
图像处理·人工智能·深度学习·目标检测·计算机·计算机视觉·视觉检测
crackpot·16 小时前
图像处理01
图像处理·人工智能
我就想睡到自然醒2 天前
【论文翻译】CA注意力机制原文翻译 Coordinate Attention for Efficient Mobile Network Design
图像处理·人工智能·计算机视觉·目标跟踪·图像分类
熊猫_豆豆3 天前
Python 基于Dlib和OpenCV实现人脸融合算法+代码
图像处理·python·算法·人脸融合
no_work3 天前
万能图像处理小助手1.1_傅里叶变化_椒盐噪声_直方图均衡等图片批量处理
图像处理·人工智能·python
yhdata4 天前
车载图像处理芯片发展按下“快进键”:至2032年市场规模将逼近27.29亿元,产业动能强劲
图像处理·人工智能
这张生成的图像能检测吗4 天前
(论文速读)Fusion-Mamba:用Mamba重新定义跨模态目标检测
图像处理·目标检测·计算机视觉·图像增强·多模态融合
找个特立不独行的名4 天前
cv::Mat详解
图像处理
AEIC学术交流中心4 天前
【快速EI检索 | IEEE出版】第六届信号图像处理与通信国际学术会议(ICSIPC 2026)
图像处理·人工智能
sali-tec4 天前
C# 基于OpenCv的视觉工作流-章40-特征找图
图像处理·人工智能·opencv·算法·计算机视觉