2. HALCON项目代码的基本构成
在HALCON视觉项目中,代码并不是“一个文件写完所有逻辑”的形态。一个可维护、可复用的项目,通常由若干层次不同的代码单元组成:最底层是HALCON算子(Operator),其上是外部过程(External Procedure)与函数(Procedure/Function),再往上是HDevelop程序(Program)与库(Library),最终由项目文件(Project File)把这些单元组织在一起。理解这些单元的边界与调用关系,是识别“哪些代码值得复用、应该以什么粒度复用”的前提。
一、从算子到过程:代码单元的四个层级
HALCON算子是最小执行单元,例如 read_image、threshold、connection、select_shape、gen_rectangle1。算子由HALCON运行时提供,用户不能修改其内部实现,只能通过参数调用。算子的输入输出以图标参数(Iconic)和控制参数(Control)区分,这一约定贯穿整个HALCON代码体系。
外部过程是用户用HDevelop语言编写、可被其他程序调用的过程文件,扩展名通常为 .hdvp。它有自己的过程名、输入输出参数和局部变量,是HALCON项目中最主要的复用单元。一个外部过程可以封装“图像预处理”“ROI提取”“形状匹配定位”“标定转换”等完整功能。与外部过程相对的是“本地过程”(Local Procedure),它写在某个HDevelop程序内部,只对该程序可见,适合一次性逻辑,不适合跨项目复用。
函数在HDevelop语境中通常指带返回值的Procedure,或通过 procedure 定义、以表达式形式调用的过程。它强调“输入参数→计算→返回结果”的映射关系,适合封装数学计算、坐标变换、参数校验等无状态逻辑。库则是若干过程与函数的集合,可以是HDevelop库(.hdpl)或外部语言库(如C++、C#封装),用于按业务域或功能域批量管理复用单元。
二、项目文件如何组织这些单元
HDevelop程序(.hdev)是开发与调试的入口,它记录主程序流程、本地过程、外部过程引用路径以及程序参数。项目文件(.hproj)则进一步把多个HDevelop程序、外部过程、图像资源、标定文件等组织为一个工程视图。典型组织方式是按“功能域”分目录:
VisionProject/
├── project.hproj
├── main/
│ └── inspect_main.hdev
├── procedures/
│ ├── preprocess.hdvp
│ ├── locate_part.hdvp
│ ├── measure_geometry.hdvp
│ └── calib_transform.hdvp
├── libraries/
│ └── vision_common.hdpl
├── config/
│ ├── camera_params.hdvp
│ └── roi_config.hdvp
└── images/
└── sample_001.png
这种结构的关键在于:main 只负责流程编排与结果汇总,具体算法逻辑下沉到 procedures;跨项目通用的过程进入 libraries;与现场相关的参数、ROI、标定数据放入 config,避免硬编码在算法过程中。这样,当相机更换或工位调整时,只需修改配置层,算法过程保持不变。
三、调用关系与数据流
HALCON代码的调用关系是“主程序→外部过程→算子”的逐层下沉。主程序通过过程名和参数列表调用外部过程,外部过程内部再调用HALCON算子或其他外部过程。数据以图标变量(Image、Region、XLD)和控制变量(整数、实数、字符串、句柄)在层间传递。识别可复用单元时,应重点观察:哪些过程被多个主程序调用、哪些过程的输入输出参数稳定、哪些过程内部只依赖HALCON算子而不依赖现场配置。
四、如何识别可复用单元
识别可复用单元不能只看“代码是否重复”,而应从三个维度判断。第一是参数稳定性:过程的输入输出参数是否已经收敛,不会因为换一个工位就全部改变。第二是依赖边界:过程内部是否只依赖HALCON算子和自身参数,而不直接读取某个固定路径的图像或某个写死的相机句柄。第三是调用频次:同一段逻辑是否在两个以上主程序或两个以上工位中出现。
以“定位”为例,如果 locate_part.hdvp 内部把模板文件路径、匹配分数阈值、角度范围都写成常量,那么它只能用于当前工位,复用价值低。更合理的做法是把模板句柄、最小分数、角度搜索范围作为输入参数,把位姿作为输出参数,模板文件由主程序或配置过程加载。这样,同一过程可以用于不同工位,只需传入不同的模板和阈值。
.hdpl),可以用一个简单标准:把它复制到另一个项目时,是否需要修改过程内部代码?如果不需要修改,只需改变调用参数,它就具备库级复用价值;如果需要修改内部常量或路径,则应先做参数化改造,再考虑入库。
五、一个可参考的复用单元清单
下表给出HALCON视觉项目中常见的复用单元及其建议归属,可作为整理现有项目代码时的对照参考。表中“归属”指该单元应放在项目目录的哪一层,“复用级别”指它适合在项目内复用还是跨项目复用。
| 单元名称 | 类型 | 典型输入 | 典型输出 | 归属 | 复用级别 |
|---|---|---|---|---|---|
| preprocess | 外部过程 | Image, 滤波参数 | Image | procedures/ | 项目内 |
| locate_part | 外部过程 | Image, 模板句柄, 分数阈值 | Pose | procedures/ | 项目内/跨项目 |
| calib_transform | 外部过程 | Pose, 标定参数 | 物理坐标 | libraries/ | 跨项目 |
| measure_geometry | 外部过程 | Image, Pose, ROI | 尺寸数组 | procedures/ | 项目内 |
| load_camera_params | 函数 | 配置文件路径 | 相机参数字典 | config/ | 项目内 |
| check_result_range | 函数 | 测量值, 上下限 | OK/NG | libraries/ | 跨项目 |
六、组织方式对复用的影响
项目文件组织方式直接决定复用成本。如果所有过程都堆在同一个 .hdev 里作为本地过程,其他项目无法直接引用,只能复制粘贴,后续维护会出现多份副本。如果外部过程分散在多个目录且没有统一命名,调用时容易找不到或引错版本。推荐的做法是:按功能域建立 procedures 子目录,过程名使用“动词+对象”命名(如 locate_part、measure_geometry),库文件按业务域拆分(如 vision_common.hdpl、calib_common.hdpl),并在项目文件中显式配置外部过程搜索路径。
此外,HDevelop程序中的本地过程应定期审查:如果某个本地过程被复制到第二个程序,就应将其提升为外部过程并放入 procedures;如果某个外部过程在三个以上项目中稳定使用,就应将其纳入库并版本化管理。通过这种“本地→外部→库”的渐进式提升,项目代码会逐步形成清晰的复用层次,而不是一开始就过度设计。