(六)海康工业相机与halcon+C#联合编程

发布时间:2026/7/4 3:11:27
(六)海康工业相机与halcon+C#联合编程 HALCON是德国MVTec公司开发的一款综合性机器视觉标准软件被广泛认为是该领域功能最全面、性能最强大的商业软件之一。集成开发环境HDevelop并包含一个拥有超过2100个独立算子函数的图像处理库。其灵活的架构旨在帮助开发者缩短软件开发周期并降低产品成本是机器视觉领域的行业领头羊。官方网站:授权分为三种开发许可证开发狗用于在HDevelop环境或通过C、C#等编程语言进行程序开发。这是永久授权是购买运行狗的前提。运行许可证运行狗用于在客户端电脑上部署和运行已开发完成的应用程序。这也是永久授权。评估/试用许可证用于短期评估HALCON的全部功能。通常为一个月有效期的文件授权无需加密狗即可使用。一、Halcon 软件安装1 、软件安装1双击下载好的安装包点击下一步2阅读软件协议将下拉滑到最下面勾选我接受协议3将检查更新的勾选去掉点击下一步4根据自己系统位数自行选择点击下一步5自行选择是否安装其他驱动程序点击下一步6选择文档语言默认选择第一项英文7选择软件安装位置8需要选择许可证文件路径这里先选择“Do not install a license file”9安装完成把勾点上桌面才会有图标点击Finish退出软件安装向导10打开软件二、Halcon 与C#联合编程1 、WindForm1创建工程文件-新建-项目选择所需要采用的框架版本以4.8为例将项目的编译配置切换为“Release”并将目标平台设定为“x64”运行成功显示新窗口在窗体中添加显示控件工具箱-PictureBox属性在右下角名称大小颜色样式等从文件中加载一张图片并显示到picturebox点击按钮显示图片private void button1_Click(object sender, EventArgs e) { LoadImage(./139.jpg); }// 从文件中读取图像在名为 pictureBox1 的 PictureBox 控件显示 private void LoadImage(string filePath) { try { // 从文件创建 Image 对象 Image img Image.FromFile(filePath); // 将图像赋值给 PictureBox pictureBox1.Image img; // 可选调整 PictureBox 的显示模式 pictureBox1.SizeMode PictureBoxSizeMode.Zoom; // 按比例缩放适应控件 } catch (Exception ex) { MessageBox.Show($加载图片失败{ex.Message}); } }成功显示图片2配置hlacon算子库到工程中右键-打开文件所在位置bin/.Net35文件夹内复制halcondotnet.dll到工程目录下打开vs2019工程的工程目录右键引用添加引用将halcondotnet.dll添加到工程引用3halcon算子转换C#利用halcon读取一张彩色图像转化成灰度图像后保存为png格式运行如图。保存的png格式图像如下文件-导出选择导出语言为C#导出代码如下/ // File generated by HDevelop for HALCON/.NET (C#) Version 17.12 // // This file is intended to be used with the HDevelopTemplate or // HDevelopTemplateWPF projects located under %HALCONEXAMPLES%\c# using System; using HalconDotNet; public partial class HDevelopExport { public HTuple hv_ExpDefaultWinHandle; // Main procedure private void action() { // Local iconic variables HObject ho_Image139, ho_GrayImage; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Image139); HOperatorSet.GenEmptyObj(out ho_GrayImage); ho_Image139.Dispose(); HOperatorSet.ReadImage(out ho_Image139, C:/Users/**/Desktop/11111111/WindowsFormsApp1/bin/x64/Release/139.jpg); ho_GrayImage.Dispose(); HOperatorSet.Rgb1ToGray(ho_Image139, out ho_GrayImage); HOperatorSet.WriteImage(ho_GrayImage, png, 0, ./gray.png); ho_Image139.Dispose(); ho_GrayImage.Dispose(); } public void InitHalcon() { // Default settings used in HDevelop HOperatorSet.SetSystem(width, 512); HOperatorSet.SetSystem(height, 512); } public void RunHalcon(HTuple Window) { hv_ExpDefaultWinHandle Window; action(); } }从导出的代码结构中可以看出halcon库的头文件为using HalconDotNet;其中action函数中的代码为执行的算法部分复制到工程中private void action() { // Local iconic variables HObject ho_Image139, ho_GrayImage; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Image139); HOperatorSet.GenEmptyObj(out ho_GrayImage); ho_Image139.Dispose(); HOperatorSet.ReadImage(out ho_Image139, ./139.jpg); ho_GrayImage.Dispose(); HOperatorSet.Rgb1ToGray(ho_Image139, out ho_GrayImage); HOperatorSet.WriteImage(ho_GrayImage, png, 0, ./gray.png); ho_Image139.Dispose(); ho_GrayImage.Dispose(); }点击按钮执行action函数private void button1_Click(object sender, EventArgs e) { action(); }在根目录下生成的灰度图像证明算法执行完毕4halcon图像转化为C# WindForm框架下的BitMap格式在界面上显示halcon图片转化为BitMap的代码public static Bitmap HobjectToBitmap(HObject ho_image) { HTuple type, width, height; //创建交错格式图像 HOperatorSet.InterleaveChannels(ho_image, out HObject InterImage, rgb, match, 255); HOperatorSet.WriteImage(InterImage, png, 0, ./gray1.png); //获取交错格式图像指针 HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height); IntPtr ptr Pointer; //构建新24位Bitmap图像 Bitmap res24 new Bitmap(width.I/3, height.I , width.I, System.Drawing.Imaging.PixelFormat.Format24bppRgb, ptr); Bitmap result new Bitmap(res24); // 5. 清理资源此时 tempBmp 不再依赖外部内存但依然要释放InterImage 可以安全释放 res24.Dispose(); InterImage.Dispose(); return result; }更改算法执行的函数private void action() { // Local iconic variables HObject ho_Image139, ho_GrayImage; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Image139); HOperatorSet.GenEmptyObj(out ho_GrayImage); ho_Image139.Dispose(); HOperatorSet.ReadImage(out ho_Image139, ./139.jpg); Bitmap show HobjectToBitmap(ho_Image139); pictureBox1.Image show; ho_GrayImage.Dispose(); HOperatorSet.Rgb1ToGray(ho_Image139, out ho_GrayImage); HOperatorSet.WriteImage(ho_GrayImage, png, 0, ./gray.png); ho_Image139.Dispose(); ho_GrayImage.Dispose(); }点击按钮运行同时生成了halcon算法得到的灰度图像2 、从海康相机得到一张图片由halcon处理并显示1首先将海康采集得到的bitmap格式转化为halcon格式public static void Bitmap24ToHobject(Bitmap bmp, out HObject ho_img) { int height bmp.Height; int width bmp.Width; Rectangle imgRect new Rectangle(0, 0, width, height); BitmapData bitData bmp.LockBits(imgRect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); try { int stride bitData.Stride; unsafe { int totalBytes height * width * 3; byte[] data new byte[totalBytes]; byte* bptr (byte*)bitData.Scan0.ToPointer(); fixed (byte* pData data) { for (int i 0; i height; i) { byte* source bptr i * stride; byte* dest pData i * width * 3; // 使用 Buffer.MemoryCopy 替代逐字节复制提升性能 Buffer.MemoryCopy(source, dest, width * 3, width * 3); } // 生成 Halcon 图像对象 HOperatorSet.GenImageInterleaved(out ho_img, new IntPtr(pData), bgr, width, height, 0, byte, width, height, 0, 0, -1, 0); } } } finally { // 确保释放 BitmapData 资源 bmp.UnlockBits(bitData); } }2修改halcon算法更改输入输出private void action(HObject ho_Image139) { // Local iconic variables HObject ho_GrayImage; HOperatorSet.GenEmptyObj(out ho_GrayImage); ho_GrayImage.Dispose(); HOperatorSet.Rgb1ToGray(ho_Image139, out ho_GrayImage); HOperatorSet.WriteImage(ho_GrayImage, png, 0, ./gray.png); ho_Image139.Dispose(); ho_GrayImage.Dispose(); }3从相机采集图像并执行算法的函数private void button1_Click(object sender, EventArgs e) { // LoadImage(./139.jpg); //枚举设备 int nRet DeviceEnumerator.EnumDevices(enumTLayerType, out deviceInfoList); if (nRet ! MvError.MV_OK) { //ShowErrorMsg(Enumerate devices fail!, nRet); return; } // ch:获取选择的设备信息 | en:Get selected device information IDeviceInfo deviceInfo deviceInfoList[0]; try { // ch:打开设备 | en:Open device device DeviceFactory.CreateDevice(deviceInfo); } catch (Exception ex) { MessageBox.Show(Create Device fail! ex.Message); return; } int result device.Open(); if (result ! MvError.MV_OK) { //ShowErrorMsg(Open Device fail!, result); return; } //ch: 判断是否为gige设备 | en: Determine whether it is a GigE device if (device is IGigEDevice) { //ch: 转换为gigE设备 | en: Convert to Gige device IGigEDevice gigEDevice device as IGigEDevice; // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) int optionPacketSize; result gigEDevice.GetOptimalPacketSize(out optionPacketSize); if (result ! MvError.MV_OK) { // ShowErrorMsg(Warning: Get Packet Size failed!, result); } else { result device.Parameters.SetIntValue(GevSCPSPacketSize, (long)optionPacketSize); if (result ! MvError.MV_OK) { //ShowErrorMsg(Warning: Set Packet Size failed!, result); } } } // ch:设置采集连续模式 | en:Set Continues Aquisition Mode device.Parameters.SetEnumValueByString(AcquisitionMode, Continuous); device.Parameters.SetEnumValueByString(TriggerMode, Off); // ch:开始采集 | en:Start Grabbing result device.StreamGrabber.StartGrabbing(); if (result ! MvError.MV_OK) { //ShowErrorMsg(Start Grabbing Fail!, result); return; } IFrameOut frameOut; nRet device.StreamGrabber.GetImageBuffer(1000, out frameOut); if (MvError.MV_OK nRet) { if (pictureBox1.Image ! null) { pictureBox1.Image.Dispose(); } // 创建新图并显示 Bitmap show frameOut.Image.ToBitmap(); HObject ho_img; Bitmap24ToHobject(show, out ho_img); action(ho_img); pictureBox1.Image show; ho_img.Dispose(); } else { return; } // ch:停止采集 | en:Stop Grabbing result device.StreamGrabber.StopGrabbing(); if (result ! MvError.MV_OK) { // ShowErrorMsg(Stop Grabbing Fail!, result); return; } }4显示效果与算法运行得到的灰度图5从相机采集图像在WPF设计的界面中显示时可以将bitmap转化为BitImage显示public static BitmapImage ConvertToBitmapImage(System.Drawing.Bitmap bitmap) { using (MemoryStream memory new MemoryStream()) { // 将 System.Drawing.Bitmap 保存到内存流 bitmap.Save(memory, ImageFormat.Png); memory.Position 0; BitmapImage bitmapImage new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.CacheOption BitmapCacheOption.OnLoad; bitmapImage.StreamSource memory; bitmapImage.EndInit(); bitmapImage.Freeze(); // 跨线程使用时需要 Freeze return bitmapImage; } }System.Drawing.Bitmap show frameOut.Image.ToBitmap(); BitmapImage showBitmapImage ConvertToBitmapImage(show); Original.Source showBitmapImage;