首页 > 其他分享 >在WPF中使用WriteableBitmap对接工业相机及常用操作

在WPF中使用WriteableBitmap对接工业相机及常用操作

时间:2024-07-13 21:31:22浏览次数:16  
标签:WBitmap 像素 相机 Bitmap 图像 缓冲区 WPF WriteableBitmap

写作背景

写这篇文章主要是因为工业相机(海康、大恒等)提供的.NET开发文档和示例程序都是用WinForm项目来说明举例的,而在WPF项目中对图像的使用和处理与在WinForm项目中有很大不同。在WinForm中用System.Drawing.Bitmap来处理图像,而在WPF中是用System.Windows.Media.Imaging.WriteableBitmap来处理图像的。本文的主要内容也是对WriteableBitmap类使用的介绍。

从相机中接收图像

首先当然要创建一个WriteableBitmap,这里以PixelFormats.Bgr24像素格式举例说明

PropertyInfo dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
PropertyInfo dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
int dpiX = (int)dpiXProperty.GetValue(null);
int dpiY = (int)dpiYProperty.GetValue(null);
WriteableBitmap WBitmap = new WriteableBitmap(PhotoWidth, PhotoHeight, dpiX, dpiY, PixelFormats.Bgr24, BitmapPalettes.Halftone256);

接收相机中的照片数据得使用相机SDK提供的方法,一般都是向方法提供一个IntPtr变量,然后相机SDK会将图像数据复制一份到这个内存地址中。

WriteableBitmap对象表示像素数据的地址是WBitmap.BackBuffer。

而在WinForm中的Bitmap则有两种方式接收图像。

一种是创建指定大小和像素格式的Bitmap后使用LockBits获得BitmapData,BitmapData的scan0表示像素数据地址然后和前面的方式一样。

另一种是在创建Bitmap时使用Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0)构造函数,使用代表像素数据的IntPtr传给scan0参数即可。

图像的显示

WriteableBitmap使用两个缓冲区,一个后端缓冲区和一个前端缓冲区(后端缓冲区用来处理图像像素数据,前端缓冲区用来显示图像),所以一个WriteableBitmap对象存着图像的两份数据。前面我们接收图像是把图像存入后端缓冲区中(BackBuffer),而界面上Image控件显示图像用的是前端缓冲区中的图像。所以现在我们需要把后端缓冲区中的数据更新到前端缓冲区中去,然后传给Image的Source属性即可。

WBitmap.Lock();
WBitmap.AddDirtyRect(new Int32Rect(0, 0, PhotoWidth, PhotoHeight));
WBitmap.Unlock();
MyImage.Source = WBitmap;

Lock锁定后端缓冲区,AddDirtyRect将后端缓冲区数据更新到前端缓冲区,Unlock解锁后端缓冲区。AddDirtyRect的使用模式是固定的,都是先Lock然后Unlock。

像素操作

System.Drawing.Bitmap对象有GetPixel和SetPixel方法,读取、修改某点的像素值很方便。在WriteableBitmap中则需要用指针区操作。在前面【接收图像】中提到用一个指针地址去接受图像,

所以图像的所有像素数据都保存在这个起始地址的内存中,也就是后端缓冲区中。WBitmap.BackBuffer指向的就是坐标(0,0)点的像素数据。

下面以读取(100,200)坐标点的像素数据举例说明,先介绍要用到的两个属性:WBitmap.BackBufferStride表示一行图像数据的字节数,WBitmap.Format.BitsPerPixel表示一个像素的位数。

首先计算(100,200)处的偏移量应该是WBitmap.BackBufferStride*200 + WBitmap.Format.BitsPerPixel / 8*100,那么BackBuffer加上偏移量就是(100,200)处的地址 ,所以完整的读取像素值的代码如下:

int offset = WBitmap.BackBufferStride * 200 + PixelFormats.Bgr24.BitsPerPixel / 8 * 100;
unsafe {
    byte* pb = (byte*)WBitmap.BackBuffer.ToPointer();
    byte cB = pb[offset];
    byte cG = pb[offset + 1];
    byte cR = pb[offset + 2];
}

或者使用System.Runtime.InteropServices.Marshal.ReadByte,不需要unsafe模式

byte cB = Marshal.ReadByte(WBitmap.BackBuffer, offset);
byte cG = Marshal.ReadByte(WBitmap.BackBuffer, offset+1);
byte cR = Marshal.ReadByte(WBitmap.BackBuffer, offset+2);

像素修改也是同样的方法,把读取变成赋值即可,或者用Marshal.WriteByte写值。

图像的保存

与Bitmap使用Save不同,WriteableBitmap需要使用Encoder编码后才能保存成文件。

using FileStream stream = new FileStream(@"C:\newu8.bmp", FileMode.Create);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(WBitmap));
encoder.Save(stream);

这里使用BmpBitmapEncoder编码器来保存bmp图像,要保存成其他格式则使用对应的编码器即可,如JpegBitmapEncoder等。

注意事项

1:像素格式问题,相机SDK提供转化成你需要的格式的方法,在接收图像时要确保两边像素格式一致。相机SDK中提供的像素格式、Bitmap的System.Drawing.Imaging.PixelFormat和WriteableBitmap的System.Windows.Media.PixelFormats对同一像素格式的命名是不同的。比如本文中的PixelFormats.Bgr24对应的是Bitmap中的PixelFormat.Format24bppRgb。可以通过解析同一张图像来确定两者之间的对应关系。

2:使用工业相机采图的方式一般都是使用回调函数的形式,所以在回调函数的多线程环境中执行显示图像的代码要注意控件的跨线程访问问题。

3:图像保存用的是后端缓冲区中的数据(再次证明前端缓冲区只是用来在界面上展示的),意味着只需要在界面上展示图像的时才调用AddDirtyRect。

4:修改部分像素点值后需要在界面上展示的,调用AddDirtyRect方法时Int32Rect参数应该是包含你修改位置的最小面积矩形区域,出于性能考虑不建议使用整个图像区域。

https://mp.weixin.qq.com/s/UMnO13srh5F0LcUoaUH-0Q

https://mp.weixin.qq.com/s?__biz=Mzk0MDcyNjA2MA==&mid=2247483773&idx=1&sn=c0b6f530b63a06b229e2df430ca5aff9&chksm=c2dc033ef5ab8a284baf42b515e11d8e12bb7c82a641899d7bc3b90d2e6a912c27d539cb72bf

https://www.cnblogs.com/YxzY/p/18299515

https://zhuanlan.zhihu.com/p/708562999

标签:WBitmap,像素,相机,Bitmap,图像,缓冲区,WPF,WriteableBitmap
From: https://www.cnblogs.com/YxzY/p/18300745

相关文章

  • WPF中style的应用(小白快速上手)
    1.解释说明    -通过设置style资源词典可以批量设置控件,不仅节省大量时间,还能方便统一修改    -重复利用Border这个控件,可以自由设计新的控件风格    -这里要注意,虽然style也是写在xaml文件中,但是其文件类型为资源词典类型,这里程序示例也进行不......
  • 优质WPF免费学习资源分享(含代码)
    WPF自学资源分享背景自身是winform开发,winform岗位比较少。wpf和winfom殊途同归,所以自身最近也在学习wpf。分享一下自己寻找到的wpf学习资源,希望对大家有帮助。学习资源推荐书籍学习资源《深入简出WPF》-刘铁猛作者是微软的高级开发工程师,多年的wpf开发经验。不过作者......
  • WPF开源的一款免费、开箱即用的翻译、OCR工具
    思维导航前言WPF介绍工具快捷键工具下载工具部分功能截图项目源码地址优秀项目和框架精选DotNetGuide技术社区交流群前言今天大姚给大家分享一款由WPF开源的、免费的(MITLicense)、即开即用、即用即走的翻译、OCR工具:STranslate。WPF介绍WPF是一个强大的桌面应......
  • 【WPF控件样式】
    自定义弹窗单选框CheckBox扁平化<Stylex:Key="CheckBoxStyle1"TargetType="{x:TypeCheckBox}"><SetterProperty="BorderThickness"Value="1"/><SetterProperty="Template"><Setter.V......
  • WPF中引用不到相对路径图片?
    在wpf中使用相对路径运行项目时却不显示图片怎么解决?新建img文件夹添加所需要的图片选中图片右键属性设置属性重新生成即可运行效果转载请标明出处!......
  • WPF WebBrowser navigate to website via url and escape script error warning
    Copyfrom https://www.iditect.com/faq/csharp/wpf-webbrowser-control--how-to-suppress-script-errors.html#:~:text=To%20suppress%20these%20script%20errors%2C%20you%20can%20handle,using%20the%20Cancel%20property%20of%20the%20WebBrowserNavigatingEventArgs%20pa......
  • WPF display and host pdf via WebBrowser
    //xaml<Windowx:Class="WpfApp206.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • WPF WebBrowser make sure the path or Internet address is correct
      Onepossiblecauseisincludechinesecharacters, //WrongcodeprivatevoidOpenClick(objectsender,RoutedEventArgse){OpenFileDialogdialog=newOpenFileDialog();dialog.Filter="PDFFiles|*.pdf|AllFiles|*.*";i......
  • Simple WPF: S3实现MINIO大文件上传并显示上传进度
    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。创作不易,如果觉得有用请在Github上为博主点亮一颗小星星吧!目的早两天写了一篇S3简单上传文件的小工具,知乎上看到了一个问题问如何实现显示MINIO上传进度,因此拓展一下这个小工具能够在上传大文件时显示进度。完......
  • WPF/C#:在WPF中如何实现依赖注入
    前言本文通过WPFGallery这个项目学习依赖注入的相关概念与如何在WPF中进行依赖注入。什么是依赖注入依赖注入(DependencyInjection,简称DI)是一种设计模式,用于实现控制反转(InversionofControl,简称IoC)原则。依赖注入的主要目的是将对象的创建和对象之间的依赖关系的管......