Halcon 程序结构
- 读取/采集图像(
read_image/grab_image)获取待处理的原始数据; - 处理图像:预处理 - 分割 - 特征提取;
- 输出结果(
disp_region/write_excel)将判定结果显示或输出; - 释放资源(
clear_image/clear_vars)清理内存,防止程序跑久崩溃。
每次不一样的任务其实只需要调整第二步即可。
场景一:表面缺陷检测
读取图像 → 预处理(滤波去噪)→ 分割(动态阈值)→ 特征提取(connection+select_shape)→ 输出结果
场景二:字符识别 OCR
读取图像 → 定位(模板匹配find_shape_model)→ 分割(提取字符区域)→ 识别(调用do_ocr_multi_class_mlp)→ 输出文本结果
场景三:高精度边缘测量
读取图像 → 定位 → 亚像素边缘提取(edges_sub_pix)→ 几何拟合 → 计算距离/角度 → 输出结果
图像预处理
一、看“图像本身”
- 有噪点(雪花点、椒盐噪点):用
median_image(中值滤波)或gauss_filter(高斯滤波); - 光照不均匀(一边亮一边暗):用灰度形态学
gray_tophat(顶帽变换)提取局部特征,或者用emphasize增强局部对比度,甚至用scale_image进行全局拉伸; - 有规律的周期性纹理(如布匹织纹、金属拉丝):频域滤波(
fft_generic+convol_fft),把特定频率的纹理直接抹掉; - 目标与背景对比度太低(灰蒙蒙的):用
emphasize锐化边缘,或者scale_image增强对比度。
二、看“后续任务”需要什么
- Blob分析 / 阈值分割:做对比度增强、光照补偿,确保目标和背景的灰度差足够大;
- 边缘提取 / 卡尺测量:先做平滑滤波(如
gauss_filter),把毛刺抹平,然后再用emphasize把真正的物理边缘锐化; - 形状模板匹配:不需要预处理。
三、看“缺陷类型”
- 检测表面微小划痕:划痕是高频信息。用
emphasize或高通滤波,把高频细节放大; - 检测表面污点/色斑:污点是局部灰度异常。用
gray_tophat(顶帽变换)或者dyn_threshold(动态阈值),过滤掉大面积的背景,只留下局部的异常点。
分割
1. 阈值分割(threshold)
- 核心原理:设定一个灰度临界值,大于它的归为前景,小于它的归为背景。
- 适用场景:光照均匀、对比度极高、背景单一的场景。例如:文档扫描、印刷字符提取、黑白二维码分割、纯色工业零件检测。
- 局限性:一旦遇到颜色渐变、阴影或复杂纹理,就会彻底失效。
2. 边缘分割(Edge Detection)
- 核心原理:寻找物体和背景灰度突变的地方(边缘),然后将边缘闭合形成轮廓。
- 适用场景:简单几何工件的轮廓提取、零件尺寸检测。
- 局限性:对噪声极度敏感,容易产生大量碎边缘;如果物体边缘有轻微断裂,就无法形成完整的轮廓。
3. 区域类分割(Region Growing & Watershed)
- 核心原理:把特征相近、空间连通的像素合并为完整区域。
- 适用场景:
- ① 漫水填充(FloodFill):适合交互式的单色块提取、污渍标记。
- ② 分水岭算法(Watershed):这是传统算法中的“大杀器”,唯一能分割堆叠、粘连颗粒的方法(例如药片计数、细胞分割、重叠的米粒)。
- 局限性:分水岭算法对噪声敏感,容易出现“过分割”(把一个物体切成好几块),且预处理流程非常复杂。
4. 聚类方法(Clustering)
- 核心原理:用 K-Means 或 Mean-Shift 等算法,根据像素的颜色、纹理相似度自动将像素分组。
- 适用场景:人像美颜预处理、纹理平滑分割、不需要先验知识的场景。
- 局限性:对高维特征处理能力弱,极易受光照影响,且运算耗时。
参数设定
一、物理约束
- 滤波掩膜尺寸(Mask Size):比如中值滤波或形态学操作,掩膜尺寸必须大于要去除的噪点尺寸,但又要小于要保留的缺陷尺寸。
- 形态学结构元素:如果要断开两个相距 5 像素的粘连区域,腐蚀算子(Erosion)半径就必须大于 2.5。
- 面积筛选阈值(Area):在
select_shape中,测量 10 个正常样本,找出其中最大噪点的面积,然后在此基础上乘以 1.5 到 2 倍作为下限。
二、统计学法
- 动态阈值(
dyn_threshold)的 Offset:这个参数决定了灵敏度。先提取正常背景区域的灰度值,计算其标准差(Standard Deviation)。Offset 通常设置为标准差的 2 到 3 倍,这样就能在统计学上保证把正常的背景波动过滤掉,只抓真正的缺陷。 - 模板匹配的 MinScore:不要盲目设为 0.8。采集 20 张良品图跑一遍匹配,记录下最低的匹配分数(比如是 0.75);再拿几张有遮挡或光照变暗的图跑一遍,看看分数掉到了多少(比如 0.65)。MinScore 就应该设定在这两者之间(如 0.7)。
三、参数联动与协同法
- Canny 边缘检测的联动:在提取亚像素边缘(
edges_sub_pix)时,如果发现边缘断断续续,通常是因为 Canny 的高阈值(High Threshold)设得太高了。这时候,不仅要降低 High Threshold,还要联动降低 Low Threshold(通常保持 High 是 Low 的 2 到 3 倍),这样才能找回丢失的边缘。 - 形状匹配的金字塔层级(NumLevels)与对比度(Contrast):金字塔层级越高,匹配速度越快,但会丢失细节。如果处理的是高反光金属件,适当减少金字塔层级,同时调低 MinContrast,反而能大幅提高匹配的稳定性。
四、边界测试法
- 极限测试:假设找到了一个完美的 Offset=15。试着把它调到 10,看看会不会误报;调到 20,看看会不会漏检。如果 12 到 18 之间都能稳定检测,那么 15 就是一个极其安全的参数。
- 鲁棒性验证:把产线上光照最亮、最暗、产品位置最偏的几张“极端图”拿出来跑一遍。如果在你设定的参数下,这些极端图依然能 OK,参数才算真正合格。
相机标定
相机内参标定(解决镜头畸变问题)
在工业现场,由于镜头并非理想的光学模型,拍摄出的图像往往会产生形变(比如直线在边缘变弯曲了,这被称为径向畸变或枕形/桶形畸变)。相机内参标定的核心目的,就是计算出镜头的畸变系数,把弯曲的图像“拉直”,从而保证后续的高精度测量不出现偏差。
第一步:准备标定板描述文件(create_calib_data)
使用现成的描述算子calibrate_hand_eye_cam_plate.descr
第二步:采集多张标定板图像(find_calib_object)
让相机从不同角度、不同位置、不同倾斜度拍摄标定板(通常需要 10~20 张,确保覆盖视野的中心和边缘)。这个算子会在图像中自动寻找标定板的特征点(如棋盘格的角点),并将这些 3D 世界点与 2D 图像点建立对应关系。
第三步:执行标定计算(calibrate_cameras)
让 Halcon 的底层算法去解算相机的内部参数。它会根据上一步提取的特征点,自动计算出相机的焦距、光轴中心以及畸变系数等内参。
第四步:获取结果并校正图像
拿到参数后,就可以用来校正后续拍摄的图像了。
get_calib_data:提取计算出的相机内参;change_radial_distortion_cam_par/gen_radial_distortion_map:生成畸变校正映射;map_image:将原始畸变图像映射为校正后的完美图像。
手眼标定(解决像素到物理坐标的转换问题)
本质是求解一个数学转换矩阵,在相机坐标系和机器人坐标系之间架起一座桥梁,让机器人能够理解相机视野中目标物体的三维位置和姿态,并规划出精准的抓取或操作路径。
一、首先根据你的硬件安装方式选择对应的模式
- 眼在手外:相机固定安装在机器人外部的工作区域,视野广阔,观察机器人末端的运动。
- 眼在手上:相机安装在机器人的末端执行器(法兰)上,随着机械手一起移动,适合抓取大范围或深箱内的物体。
二、数学原理
手眼标定的核心是求解一个 4x4 的齐次变换矩阵。在数学上,这通常被抽象为经典的AX = XB方程:
- A:机器人末端执行器的运动变换矩阵(基坐标系到末端坐标系)。
- B:相机观察到的目标(标定板)运动变换矩阵(相机坐标系到目标坐标系)。
- X:待求的手眼变换矩阵(相机坐标系到机器人基坐标系的转换)。
三、工作过程
1. 硬件准备与安装
根据任务需求确定安装模式(Eye-in-Hand 或 Eye-to-Hand),并准备好高精度的标准标定板(如棋盘格或圆点阵)。确保机器人底座、相机支架安装牢固,且相机已进行预热暖机。
2. 采集标定数据
控制机器人带动标定板(或相机)运动到多个不同的位置和姿态。建议采集 9-12 组数据,确保覆盖相机视场的主要区域,避免边缘死角。每次移动后保持静止,记录此时机器人末端的物理位姿,同时控制相机拍摄图像并提取特征点坐标。
3. 图像处理与特征提取
对采集到的图像进行分析,精确提取标定板上的特征点。在处理反光或复杂表面时,需调整好光源和相机参数,确保标定板特征点清晰可见,为后续计算打下坚实基础。
4. 求解手眼关系
利用采集到的多组机器人位姿和图像特征数据,通过专门的数学算法(如 Tsai-Lenz、Kronecker 积法等)进行求解,计算出相机坐标系与机器人手部坐标系之间的转换矩阵。
5. 精度验证与优化
标定完成后必须进行验证。通过让机器人移动到由相机定位的某个目标点,检验实际到达位置与理论位置的误差(通常通过重投影误差或变换误差来评估)。如果误差较大,可通过非线性优化算法进一步减小误差。
halcon
create_hand_eye_calibration (HECModelID) set_hand_eye_calibration_pose calibrate_hand_eye四、把相机看到的像素坐标,精准转换为机械手能懂的物理坐标
image_points_to_world_points:把图像上的 2D 像素坐标 (Row, Column),结合相机的内参,转换成相机坐标系下的 3D 物理坐标 (X, Y, Z)。Z 轴通常需要自己设定。create_pose:把上一步算出的相机坐标系下的 (X, Y, Z) 坐标,打包成一个 Halcon 专用的“位姿(Pose)”变量。pose_compose:将两个位姿矩阵相乘。最终机械手位姿 = 手眼标定矩阵 (HandEyeMatrix) × 目标在相机下的位姿 (CamPose)
算法性能优化
一、算法与代码逻辑优化
1. 限定 ROI 区域(reduce_domain)
先用模板匹配或粗定位找到目标,用reduce_domain框出关键区域,后续所有算子只在这个小区域内运行。
2. 模板匹配性能调优
- 金字塔层数(NumLevels):高对比度目标设 3-5 层,低对比度设 1-3 层。层数越多速度越快,但容易丢失细节;
- 贪婪度(Greediness):速度要求高时调大(如 0.9),精度要求高时调小;
- 切记:千万不要在 for 循环内创建模板!
create_shape_model必须在循环外执行一次,循环内只调用find_shape_model。在循环内建模板是性能灾难,还会导致内存泄漏。
3. 组件匹配
在复杂装配体检测中,使用find_component_model时,将搜索策略设为'prune_branch'。一旦发现缺失组件就提前终止搜索,能将检测时间大幅缩短。
二、Halcon 自动并行化(AOP)与多核加速
Halcon 默认开启了自动操作员并行化(AOP),它会自动将图像数据切分给多个 CPU 核心处理。
halcon
* 获取当前系统核心数和线程池状态 get_system ('processor_num', ProcessorNum) get_system ('thread_num', ThreadNum) * 查看 AOP 是否开启(默认是 true) get_system ('parallelize_operators', AOP)如果默认 AOP 效率不高,可以使用optimize_aop算子。它会通过几小时的硬件测试,为你的 CPU 生成最优的并行策略文件(.aop_info),以后运行程序会自动加载。
三、硬件级加速(GPU 提速)
对于极其耗时的图像处理(如大尺寸图像的频域滤波、复杂的深度学习推理),可以调用 GPU 加速。使用 GPU 加速前必须先关闭界面的自动刷新(dev_update_off()),否则图像在 CPU 和 GPU 之间频繁传输反而会拖慢速度。
异常处理与工程鲁棒性
一、Try-Catch 异常捕获机制
防止程序崩溃的最有效手段。当 Halcon 算子遇到致命错误(比如读取了不存在的图片、相机未连接)时,它会抛出异常(Exception)。如果不捕获,程序就会直接停止运行。
在 HDevelop 中,使用try...catch...endtry将可能出错的代码包裹起来:
halcon
try * 尝试执行可能出错的代码(例如读取图像) read_image (Image, 'D:/images/cam_01.png') catch (Exception) * 如果出错,程序不会崩溃,而是跳到这里 * Exception[0] 包含了错误代码(例如 5200 表示文件未找到) dev_get_exception_data (Exception, 'error_message', ErrMsg) disp_message (0, '捕获到异常: ' + ErrMsg, 'window', 10, 10, 'red', 'true') * 在这里可以执行清理操作或跳过当前检测 endtry二、主动判断与状态机
- 结果校验:在执行
find_shape_model后,不要默认它找到了结果。必须判断返回的 Score 数组是否为空。如果为空,说明没匹配到,应主动跳过后续测量步骤; - 超时熔断机制:在高速流水线或复杂算法中,如果算法陷入死循环或耗时过长,会导致产线堆积。可以设置超时机制(例如在 C# 中使用 Task 配合 CancellationToken,或在 Halcon 中通过 timeout 参数),一旦超时立即放弃当前检测,进入下一节拍;
- 状态机架构:工业软件绝不能写成线性的
while(true)。必须采用状态机:初始化 → 待机 → 触发采集 → 算法处理 → 结果输出 → 异常复位。当发生异常时,程序进入“异常复位”状态,等待人工干预或自动重试,而不是直接崩溃。
三、日志记录与质量看板
- 记录关键信息:每次检测都必须将“时间戳、图像文件名、检测结果(OK/NG)、耗时、错误代码”写入本地 CSV 或数据库;
- 异常图像留存:当触发 catch 或检测到 NG 时,自动将该图像保存到特定的 NG_Images 文件夹中。
边缘检测
边缘检测的实质是通过局部图像微分技术,计算图像灰度分布的梯度(一阶导数极值或二阶导数过零点),从而提取出对象与背景间的交界线。
一、传统经典的算子
1. Sobel 算子
- 特点:利用像素上下左右邻域的灰度加权差分来计算梯度。
- 优势:对噪声具有平滑作用,能提供较精确的边缘方向信息。
- 劣势:定位精度不高,容易检测出伪边缘。
2. Canny 算子(工业界最常用)
- 特点:被公认为最稳健的边缘检测算法之一。它包含四个严谨的步骤:高斯滤波去噪、计算梯度强度和方向、非极大值抑制(细化边缘)、迟滞阈值化(双阈值边缘跟踪)。
- 优势:抗噪能力强,边缘连续且精准。
3. Laplacian 算子(LoG)
- 特点:基于二阶导数,通过寻找零交叉点来定位边缘。对细节和噪声非常敏感,通常需要先做高斯平滑(LoG)。
二、Halcon 中的边缘检测
1. 像素级边缘检测(基础轮廓提取)
sobel_amp:Sobel 梯度算子。计算速度快,对水平和垂直边缘敏感,适合做简单的边缘粗提取;edges_image:综合梯度计算算子,支持 Canny、Lanser 等算法,输出梯度幅值和方向图像。
2. 亚像素级边缘检测
edges_sub_pix:它直接输出亚像素精度的边缘轮廓(XLD 格式),精度可达 0.1 甚至 0.01 像素级别。支持'canny'、'sobel'、'roberts'等。其中 Canny 算法因为结合了高斯滤波、非极大值抑制(NMS)和滞后双阈值,抗噪能力和边缘定位最准。
halcon
edges_sub_pix (Image, Edges, 'canny', Sigma, Low, High)参数说明:
- Sigma(高斯平滑系数):控制边缘检测的灵敏度。
- 大 Sigma(如 2.0~3.0):检测粗边缘,抗噪能力强,但会丢失微小细节;
- 小 Sigma(如 0.5~1.0):检测细边缘,但容易把噪点当成边缘。
- Low / High(滞后双阈值):过滤伪边缘,连接断裂的真实边缘。
- High(高阈值):强边缘的门槛。高于此值的必定是真实边缘。
- Low(低阈值):弱边缘的门槛。低于此值的直接丢弃;介于 Low 和 High 之间的,如果与强边缘相连,则保留,否则丢弃。
- 通常建议 High 是 Low 的 2~3 倍。如果边缘断断续续,降低 Low;如果背景噪点太多,提高 High。