C# + Halcon实战:手把手教你搞定药盒追溯码识别(附完整代码)

张开发
2026/4/17 6:10:52 15 分钟阅读

分享文章

C# + Halcon实战:手把手教你搞定药盒追溯码识别(附完整代码)
C# Halcon实战手把手教你搞定药盒追溯码识别附完整代码在工业自动化领域药品追溯码识别是确保产品质量和安全的重要环节。传统的人工检查方式效率低下且容易出错而基于机器视觉的自动化识别技术正在彻底改变这一现状。本文将带你从零开始使用C#和Halcon构建一个高效的药盒追溯码识别系统。Halcon作为业界领先的机器视觉库在条码识别方面有着显著优势。相比常见的EmguCV等开源库Halcon在复杂背景、低对比度或部分遮挡情况下仍能保持极高的识别率。我们将通过一个完整的项目示例展示如何利用Halcon的强大功能解决实际问题。1. 环境准备与项目搭建1.1 开发环境配置首先确保你的开发环境满足以下要求Visual Studio 2019或更高版本.NET Framework 4.8Halcon 20.11或更新版本运行时库注意Halcon的版本需要与运行时库严格匹配否则可能导致兼容性问题。安装Halcon后需要在项目中添加引用。右键点击项目引用选择添加引用浏览到Halcon安装目录下的dotnet35文件夹添加halcondotnet.dll。1.2 创建基础项目结构在Visual Studio中新建一个控制台应用程序项目文件 → 新建 → 项目 → 控制台应用(.NET Framework)选择.NET Framework 4.8作为目标框架项目命名为PharmaBarcodeReader。2. Halcon核心API解析2.1 条码模型创建与参数设置Halcon的条码识别流程始于创建条码模型。CreateBarCodeModel函数是这一过程的核心HTuple barCodeHandle; HOperatorSet.CreateBarCodeModel( new HTuple(element_size_min), new HTuple(2), // 最小条码单元尺寸(像素) out barCodeHandle );关键参数说明参数名类型说明推荐值element_size_minHTuple最小条码单元尺寸1-3(根据图像分辨率调整)element_size_maxHTuple最大条码单元尺寸自动(max)persistenceHTuple模型持久化标识0(不保存)2.2 图像读取与预处理高质量的图像输入是准确识别的基础。Halcon提供了多种图像增强方法HObject image; HOperatorSet.ReadImage(out image, barcode2.png); // 图像增强处理 HObject enhancedImage; HOperatorSet.Emphasize(image, out enhancedImage, 7, 7, 1.0);常用预处理技术包括直方图均衡化高斯滤波降噪边缘增强局部对比度调整3. 完整代码实现与优化3.1 基础识别代码框架以下是完整的药盒追溯码识别实现using HalconDotNet; using System; namespace PharmaBarcodeReader { class Program { static void Main(string[] args) { // 初始化Halcon环境 HOperatorSet.SetSystem(do_low_error, true); // 创建条码模型 HTuple barCodeHandle CreateBarcodeModel(); // 处理单张图像 ProcessSingleImage(barCodeHandle, barcode2.png); // 清理资源 HOperatorSet.ClearBarCodeModel(barCodeHandle); } static HTuple CreateBarcodeModel() { HTuple barCodeHandle; HOperatorSet.CreateBarCodeModel( new HTuple(element_size_min), new HTuple(1.5), out barCodeHandle ); // 设置条码参数 HOperatorSet.SetBarCodeParam(barCodeHandle, check_char, present); HOperatorSet.SetBarCodeParam(barCodeHandle, persistence, 1); return barCodeHandle; } static void ProcessSingleImage(HTuple model, string imagePath) { try { // 读取并预处理图像 HObject image; HOperatorSet.ReadImage(out image, imagePath); // 执行条码检测 HObject symbolRegions; HTuple decodedStrings; HOperatorSet.FindBarCode( image, out symbolRegions, model, auto, out decodedStrings ); // 输出结果 Console.WriteLine(识别结果:); for(int i0; idecodedStrings.Length; i) { Console.WriteLine($条码{i1}: {decodedStrings[i]}); } // 可视化(可选) if(decodedStrings.Length 0) { DisplayResults(image, symbolRegions); } } catch(HalconException ex) { Console.WriteLine($识别失败: {ex.Message}); } } static void DisplayResults(HObject image, HObject regions) { // 创建窗口并显示结果 HWindow window new HWindow(0, 0, 800, 600); window.SetColor(green); window.DispObj(image); window.DispObj(regions); window.SetTposition(24, 12); window.WriteString(识别成功 - 按任意键继续); Console.ReadKey(); window.CloseWindow(); } } }3.2 性能优化技巧提升识别率和速度的关键参数调整// 优化条码搜索参数 HOperatorSet.SetBarCodeParam(barCodeHandle, stop_after_result_num, 10); HOperatorSet.SetBarCodeParam(barCodeHandle, num_scanlines, 50); // 针对特定条码类型的优化 HOperatorSet.SetBarCodeParam(barCodeHandle, code128_len_size, max); HOperatorSet.SetBarCodeParam(barCodeHandle, ean13_check_char, true);4. 高级应用与错误处理4.1 批量处理与多线程实现在实际生产环境中通常需要处理大量图像。以下是批量处理的实现示例static void ProcessBatchImages(HTuple model, string[] imagePaths) { Parallel.ForEach(imagePaths, imagePath { try { using (var haltuple new HTuple()) { HObject image; HOperatorSet.ReadImage(out image, imagePath); HObject symbolRegions; HTuple decodedStrings; HOperatorSet.FindBarCode( image, out symbolRegions, model, auto, out decodedStrings ); lock(Console.Out) { Console.WriteLine(${Path.GetFileName(imagePath)}:); foreach(var code in decodedStrings.SArr) { Console.WriteLine($\t{code}); } } } } catch(Exception ex) { Console.WriteLine(${imagePath}处理失败: {ex.Message}); } }); }4.2 常见问题排查指南在实际部署中可能遇到的问题及解决方案图像质量问题症状识别率低或完全无法识别解决方案检查照明条件确保条码区域光照均匀调整相机焦距和光圈增加图像预处理步骤参数配置问题症状特定类型的条码无法识别解决方案明确指定条码类型而非使用auto调整element_size_min/max参数启用校验位检查性能问题症状处理速度慢解决方案限制搜索区域(ROI)减少num_scanlines参数值使用多线程处理// 性能优化示例限制搜索区域 HObject roi; HOperatorSet.GenRectangle1(out roi, 100, 100, 500, 500); HObject imageReduced; HOperatorSet.ReduceDomain(image, roi, out imageReduced); HOperatorSet.FindBarCode(imageReduced, ...);5. 实际应用扩展5.1 与数据库系统集成将识别结果存储到数据库是追溯系统的核心功能。以下是SQL Server集成的示例static void SaveToDatabase(string barcode, DateTime scanTime) { string connectionString Server.;DatabasePharmaTrace;Integrated Securitytrue; using(var connection new SqlConnection(connectionString)) { var command new SqlCommand( INSERT INTO BarcodeScans (Barcode, ScanTime) VALUES (barcode, time), connection); command.Parameters.AddWithValue(barcode, barcode); command.Parameters.AddWithValue(time, scanTime); connection.Open(); command.ExecuteNonQuery(); } }5.2 用户界面开发对于需要人工干预的场景可以开发简单的WPF界面!-- MainWindow.xaml -- Window x:ClassPharmaBarcodeReader.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation Title药品追溯码扫描系统 Height450 Width800 Grid Image x:NameCameraImage StretchUniform/ Button Content开始扫描 ClickScanButton_Click HorizontalAlignmentRight VerticalAlignmentBottom/ ListView x:NameResultsList ItemsSource{Binding Barcodes} ListView.View GridView GridViewColumn Header条码 DisplayMemberBinding{Binding Code}/ GridViewColumn Header时间 DisplayMemberBinding{Binding Time}/ /GridView /ListView.View /ListView /Grid /Window// MainWindow.xaml.cs private void ScanButton_Click(object sender, RoutedEventArgs e) { var task Task.Run(() { var processor new BarcodeProcessor(); var result processor.ProcessFromCamera(); Dispatcher.Invoke(() { Barcodes.Add(new BarcodeResult { Code result.Barcode, Time DateTime.Now }); }); }); }6. 部署与维护建议6.1 系统部署注意事项硬件选择根据处理速度要求选择合适的工业相机和处理器环境控制确保扫描区域光照稳定避免反光Halcon运行时部署机器必须安装对应版本的Halcon运行时6.2 长期维护策略定期校准相机参数建立测试用例库确保系统更新不影响现有功能监控识别率变化及时发现潜在问题// 监控代码示例 public class PerformanceMonitor { private ConcurrentQueuedouble successRates new ConcurrentQueuedouble(); public void RecordResult(bool isSuccess) { // 记录最近100次识别结果 successRates.Enqueue(isSuccess ? 1.0 : 0.0); while(successRates.Count 100) { successRates.TryDequeue(out _); } } public double GetSuccessRate() { return successRates.Any() ? successRates.Average() : 0; } }

更多文章