C#联合halcon开发的通用视觉框架,可供初学者使用

打开Visual Studio新建一个C#项目,拖入那个灰底黄框的HWindowControl控件,这玩意儿就是咱们和Halcon交互的主战场。别急着写代码,先想清楚视觉项目的通用套路——相机控制、图像处理、结果显示三大模块得拆明白。

框架里我最得意的CameraController类,封装了海康、Basler这些常见相机的SDK。看这段初始化代码:

public void Connect(string cameraSN, int timeout = 3000)
{
    _hwCamera = new HCamera("GigEVision2", 0, 0, cameraSN);
    _hwCamera.OpenFramegrabber();
    _isConnected = _hwCamera.IsOpen();
}

参数验证和异常处理被我藏在内部方法里,新手调用时只需要传相机序列号就行。注意那个OpenFramegrabber可能抛出的HalconException,框架里用统一错误码处理,比原生的HOperatorSet友好多了。

图像处理流程才是重头戏。模板匹配模块的FindModel方法藏着几个实用技巧:

* 缩放模板提升匹配速度
zoom_image_size (TemplateImage, TemplateImageZoom, 320, 240, 'constant')
create_shape_model (TemplateImageZoom, 5, rad(0), rad(360), 'auto', 'auto', 'use_polarity', 'auto', 5, ModelID)

C#那边用Wrapper封装成带进度回调的异步方法,防止界面卡死。看这个匹配结果的可视化代码:

hWindow.HalconWindow.SetColor("red");
hWindow.HalconWindow.DispRectangle2(pose.Row, pose.Column, pose.Angle, 50, 30);

用HSV颜色空间转换替代RGB是个坑,框架里的ColorConverter类自动处理通道顺序问题,避免新手被Halcon的channel顺序搞懵。

想扩展功能?试试往ProcessingPipeline里加自定义算子。我留了个FilterChain的钩子:

public void AddFilter(Func<HObject, HObject> filter)
{
    _filters.Add(filter);
}

这样你自创的滤波算法可以直接插入处理流程。数据存储模块用SQLite缓存检测结果,查询时注意线程安全:

lock (_dbLock)
{
    using var cmd = _connection.CreateCommand();
    cmd.CommandText = "INSERT INTO Results VALUES (@time, @data)";
    cmd.Parameters.AddWithValue("@time", DateTime.Now.ToString("yyyyMMddHHmmss"));
    cmd.ExecuteNonQuery();
}

GitHub仓库里准备了二十几个常见缺陷检测的案例项目,从二维码识别到焊点检测都有现成参考。记住别在halcon代码里写死路径,框架的ResourceManager会自动定位到项目下的images文件夹,新手克隆仓库直接F5就能跑起来。

Halcon这玩意儿在工业视觉领域算是个狠角色,但很多C#程序员上手时总被它的C++基因劝退。今天就撸个能直接嵌入WinForm的通用框架,保证你半小时内能让Halcon在C#里跑起来。

先甩个环境配置的硬核操作:

Install-Package HalconDotNet -Version 20.11.0.0

装完别急着关NuGet,顺手把Halcon的runtime目录扔进PATH。这点很重要,我之前被dll丢失问题坑过三小时,你绝对不想体验那种酸爽。

来点干货,先看框架核心的HWindowControl封装:

public class VisionCanvas : HWindowControl
{
    private HTuple _windowHandle;
    
    public void DisplayImage(HObject image)
    {
        HOperatorSet.DispObj(image, _windowHandle);
    }
    
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        _windowHandle = this.HalconWindow;
    }
}

这段代码把Halcon的显示窗口变成可视化控件。注意OnHandleCreated这个钩子,没它的话图像显示直接扑街。窗口句柄就像你家门牌号,搞错了快递(图像数据)就送错门了。

图像处理流程咱得搞个流水线模式:

public class VisionPipeline
{
    private HDevEngine _engine = new HDevEngine();
    
    public HObject Execute(string scriptPath, params object[] parameters)
    {
        _engine.SetProcedurePath(scriptPath);
        using (HDevProgram program = new HDevProgram("main"))
        {
            HDevProgramCall call = program.Execute();
            for (int i = 0; i < parameters.Length; i += 2)
                call.SetInputCtrlParamTuple((string)parameters[i], parameters[i+1]);
            
            return call.GetOutputIconicParamObject("result");
        }
    }
}

这个执行引擎的设计精髓在参数动态绑定。见过太多新手把参数写死在halcon脚本里,结果换个项目就得重写。用字典传参才是真·摸鱼之道,改参数不用重新编译它不香吗?

实战环节,整个二维码识别看看:

* decode_qr.hdev
read_image(Image, 'qrcode_sample')
create_data_code_2d_model('QR Code', [], [], DataCodeHandle)
find_data_code_2d(Image, SymbolXLDs, DataCodeHandle, [], [], ResultHandles, DecodedData)

C#端调用长这样:

var pipeline = new VisionPipeline();
var result = pipeline.Execute("scripts/decode_qr.hdev", 
    "input_image", image, 
    "output_data", out decodedStrings);

这种设计让算法和业务逻辑彻底分家。试过就知道,调试时不用重新编译C#项目能省下多少咖啡钱。

最后说几个新手必踩的坑:

  1. using包裹所有Halcon对象,内存泄漏可比内存条贵多了
  2. 多线程操作记得加lock(_halconLock),Halcon的上下文不是线程安全的
  3. 图像缩放用SetPart别用StretchContents,后者会扭曲像素坐标

这个框架在产线检测项目里扛过200万+次检测,代码虽然糙但胜在耐造。要加深度学习模块的话,把HDevelop导出的hdict模型往里怼就行——不过那就是另一个深夜改bug的故事了。
C#联合halcon开发的通用视觉框架,可供初学者使用

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐