原文作者:aircraft
原文链接: halcon 入门教程(三) 边缘检测
有兴趣可以多看其他的halcon教程
halcon 学习教程目录
本篇讲一下边缘检测(边缘提取),因为这个我发现也是比较常用的,放在入门教程(三)会比较好,在入门教程(一)(二)学完了形态学,和Blob分析,再来学边缘检测并且结合案例感觉会掌握学习的很快。跟openCV一样主流的还是那几个检测算子Sobel、Canny、Laplacian等等。
一.边缘检测简介
1. 边缘检测的基本原理
边缘是图像中灰度、颜色或纹理发生显著变化的区域,通常对应物体的边界。边缘检测的目标是定位这些变化的区域,方法可分为:
- 基于梯度:通过计算像素的梯度幅值和方向(如Sobel、Canny)。
- 基于二阶导数:利用拉普拉斯算子检测过零点(如Laplacian)。
- 基于模板匹配:使用预定义的边缘模板进行卷积。
2. Halcon边缘检测的核心算法
**(1) 一阶梯度法(Sobel, Prewitt)**
- 原理:通过卷积核计算像素在水*和垂直方向的梯度(Gx和Gy),合成梯度幅值和方向。
halcon示例:- sobel_amp(Image, EdgeAmplitude, 'sum_abs', 3) // Sobel算子,3x3卷积核
- edges_image(Image, ImaAmp, ImaDir, 'canny', 1, 'nms') // 综合梯度计算
复制代码 (2) Canny边缘检测**
- 步骤:
- 高斯滤波:去噪。
- 梯度计算:类似Sobel。
- 非极大值抑制(NMS):保留梯度方向上的局部最大值,细化边缘。
- 滞后阈值:使用高低阈值(LowThreshold, HighThreshold)连接边缘。
halcon示例:- edges_sub_pix(Image, Edges, 'canny', 1.5, 20, 40) // Canny算法,亚像素精度
复制代码 (3) 亚像素边缘检测**
- 原理:在像素级边缘检测的基础上,通过插值或梯度模型拟合(如高斯函数、多项式)将精度提升到亚像素级别(精度可达0.1像素)。
halcon 示例:- edges_sub_pix(Image, Edges, 'canny', 1.5, 20, 40) // 直接输出亚像素边缘轮廓
复制代码
3. Halcon边缘检测的关键技术
**(1) 高斯滤波与尺度控制**
- 作用:通过调节高斯滤波的Sigma参数控制边缘检测的灵敏度。示例:
- 大Sigma:检测粗边缘,抗噪能力强。
- 小Sigma:检测细边缘,但易受噪声干扰。
- edges_sub_pix(Image, Edges, 'canny', Sigma, LowThresh, HighThresh)
复制代码 (2) 非极大值抑制(NMS)**
- 作用:在梯度方向上仅保留局部最大值的像素,消除边缘的“宽线”现象。
- Halcon参数:
- edges_image(Image, ImaAmp, ImaDir, 'canny', 1, 'nms') // 使用NMS
复制代码 (3) 滞后阈值(双阈值)**
- 原理:参数示例:
- 高阈值:强边缘必须超过此值。
- 低阈值:弱边缘若与强边缘连接则保留。
- edges_sub_pix(Image, Edges, 'canny', 1.5, 20, 40) // Low=20, High=40
复制代码
4. Halcon边缘检测的优势
- 亚像素精度:通过模型拟合实现超像素级边缘定位,适合高精度测量。
- 灵活性:支持多种算法(Canny、Sobel、Lanser等)和参数调节。
- 抗噪能力:高斯滤波和滞后阈值有效抑制噪声。
- 实时性:高度优化的算法实现,适用于工业实时检测。
5. 总结
Halcon的边缘检测通过梯度计算、非极大值抑制、双阈值分割和亚像素优化,实现了高精度和强鲁棒性的边缘提取。其核心在于*衡噪声抑制与细节保留,广泛应用于工业检测、自动驾驶、医学成像等领域。实际使用时需根据场景特点调整算法参数,并结合形态学操作(如膨胀、填充)优化结果。
二.算子与案例学习
这里正常我是想让大家先学习相关的算子函数的,但是因为我自己也学习过,我们学习的心态都是不见兔子不撒鹰,没有看到一些效果之前,我们都难以产生比较大的学习热情,所以这里先上一个车道线提取的案例学习,注释都会详细打清楚。在大一上学期的时候自己买了本单片机来学,发现学的太枯燥了,后来就放弃的硬件的路,后面偶然得到了个c语言的学习视频,然后跟着视频学,大一就把c语言c++,MFC那些东西都自学完了。对于初学的人没有能直观看到效果的学习,都是没有太大兴趣的。书本和文字冷冰冰的,怎么让初学者去学!!!
1.案例:车道线检测(autobahn.hdev)
老规矩,先上图,我们的目的是把一定距离内的车道的车道线给提取出来
实例代码:autobahn.hdev- * autobahn.hdev: Fast detection of lane markers
- *
- dev_update_window ('off')
- * 关闭窗口自动更新,避免频繁刷新提升执行速度
- dev_close_window ()
- * 关闭所有已打开的图形窗口
- dev_open_window (0, 0, 768, 575, 'black', WindowID)
- * 打开新窗口,位置(0,0),尺寸768x575,背景黑色
- MinSize := 30
- * 定义形态学膨胀的核大小(30x30矩形)
- get_system ('init_new_image', Information)
- * 获取系统默认的'init_new_image'参数值
- set_system ('init_new_image', 'false')
- * 禁止系统自动初始化新图像,避免覆盖已有图像
- * 生成网格区域,用于限制后续处理的ROI(感兴趣区域) 注意这里只是提取宽度为30像素的网格线区域出来
- gen_grid_region (Grid, MinSize, MinSize, 'lines', 512, 512)
- * 参数说明:
- * Grid : 输出网格区域
- * MinSize : 网格线间距(水*和垂直均为30像素)
- * 'lines' : 生成线型网格(非矩形块)
- * 512, 512 : 网格覆盖的原始图像尺寸(此处可能与实际图像尺寸不一致,后续通过裁剪修正)
- * 裁剪网格区域,仅保留道路部分(坐标范围:行130~450,列10~502)
- clip_region (Grid, StreetGrid, 130, 10, 450, 502)
- dev_set_line_width (3)
- * 设置显示线宽为3(用于网格和边缘的高亮显示)
- dev_set_color ('green')
- * 设置显示颜色为绿色(用于网格)
- read_image (ActualImage, 'autobahn/scene_00')
- * 读取第一帧图像(scene_00)
- dev_display (ActualImage)
- * 显示图像
- stop ()
- * 暂停程序,等待用户按F5继续
- dev_display (StreetGrid)
- * 在图像上叠加显示裁剪后的网格区域(绿色)
- stop ()
- * 再次暂停
- for i := 0 to 28 by 1
- * 读取当前帧图像(例如:scene_00, scene_01,..., scene_28)
- read_image (ActualImage, 'autobahn/scene_' + (i$'02'))
- * i$'02'表示两位数字补零
-
- * 将处理区域限制到StreetGrid网格内
- reduce_domain (ActualImage, StreetGrid, Mask)
- * 作用:生成一个掩膜图像Mask,仅保留StreetGrid区域内的像素
-
- * Sobel边缘检测(梯度幅值计算)
- sobel_amp (Mask, Gradient, 'sum_abs', 3)
- * 参数说明:
- * 'sum_abs' : 梯度计算方法(水*与垂直方向绝对值之和)
- * 3 : Sobel算子尺寸(3x3核)
-
- * 初次阈值分割提取边缘点 Gradient这个是得到的梯度图,只有在边缘区域(也就是道路和道路线交汇的区域)才会有较高的灰度值存在
- threshold (Gradient, Points, 20, 255)
- * 提取梯度值在[20, 255]之间的区域(初步筛选车道线边缘)
-
- * 形态学膨胀(连接离散边缘点)
- dilation_rectangle1 (Points, RegionDilation, MinSize, MinSize)
- * 使用30x30矩形核对边缘点进行膨胀,连接相邻点形成连续区域
-
- * 限制处理区域到膨胀后的区域
- reduce_domain (ActualImage, RegionDilation, StripGray)
- * StripGray为仅包含RegionDilation区域的灰度图像
-
- * 高亮度区域提取(车道线通常为白色/黄色)
- threshold (StripGray, Strip, 190, 255)
- * 提取灰度值在[190, 255]之间的区域(高亮度车道线)
-
- * 填充区域内的孔洞
- fill_up (Strip, RegionFillUp)
- * 确保车道线区域连续无断裂
-
- * 显示处理结果
- dev_display (ActualImage)
- * 显示原始图像
- dev_display (RegionFillUp)
- * 叠加显示检测到的车道线区域(默认颜色)
- endfor
- dev_set_line_width (1)
- * 恢复默认线宽为1
- dev_update_window ('on')
- * 重新启用窗口自动更新
- set_system ('init_new_image', Information)
- * 恢复系统参数'init_new_image'的默认值
复制代码 关键步骤总结
- ROI限制:通过网格裁剪 (clip_region) 和域缩减 (reduce_domain) 聚焦道路区域,减少计算量。
- 边缘检测:Sobel算子提取梯度,阈值分割初步筛选边缘点。
- 形态学处理:膨胀操作连接离散点,填充操作确保车道线连续。
- 亮度阈值:假设车道线高亮,通过二次阈值分割精确定位。
效果图:
第一个案例有我的注释在理解起来应该还是比较简单的,也发现了里面开始运用到了一些边缘检测的算子,接下来我们就学习一下几个常用的边缘检测的算子。
1.sobel算子sobel_amp(Image : EdgeAmplitude : FilterType, Size : )详解:
函数原型:- sobel_amp(Image : EdgeAmplitude : FilterType, Size : )
复制代码
- 功能:通过 Sobel 算子计算图像的梯度幅值,用于边缘检测。
- 输入/输出:
- Image:输入图像(单通道灰度图像)。
- EdgeAmplitude:输出图像,表示梯度幅值(边缘强度)。
- FilterType:梯度计算方法(如 'sum_abs')。
- Size:Sobel 核的大小(3, 5, 7, 9, 11 等奇数)。
1. **FilterType参数(梯度计算方式)**
控制梯度幅值的计算方法,常见选项如下:
- **'sum_abs'**(默认):
- 计算水*和垂直方向梯度的绝对值之和:
- 计算速度快,适用于实时性要求高的场景。
- **'thin_sum_abs'**:
- 类似 'sum_abs',但使用更小的卷积核(仅适用于 Size=3)。
- **'x'** 或 **'y'**:
- 仅计算水*方向('x')或垂直方向('y')的梯度。
- **'frei_chen'**:
- 使用 Frei-Chen 算子,增强对角边缘的响应。
- 适用于复杂纹理或对角边缘检测。
- **'sobel'**:
- 更接*理论梯度,但计算量较大。
2. **Size(卷积核大小)**
- 取值范围:3, 5, 7, 9, 11 等奇数。
- 影响:
- 小尺寸(如 3):检测细边缘,但对噪声敏感。
- 大尺寸(如 5):检测粗边缘,抗噪能力强,但可能丢失细节。
- 典型选择:
- 大多数场景:Size=3。
- 高噪声图像:Size=5 或 7。
使用示例
示例 1:基本边缘检测
- read_image(Image, 'part.png')
- sobel_amp(Image, EdgeAmplitude, 'sum_abs', 3)
- threshold(EdgeAmplitude, Edges, 20, 255) // 阈值分割提取边缘
复制代码 应用场景
- 工业检测:
- 检测零件轮廓、缺陷边缘。
- 参数建议:FilterType='sum_abs', Size=3。
- 车道线检测(如 autobahn.hdev):
- 提取车道线边缘,需*衡噪声抑制和边缘连续性。
- 参数建议:FilterType='sum_abs', Size=3。
- 医学图像处理:
- 检测组织边界或血管。
- 参数建议:FilterType='frei_chen', Size=5(增强复杂边缘)。
参数选择建议
场景需求推荐参数实时性要求高FilterType='sum_abs', Size=3高精度边缘定位FilterType='sobel', Size=3抗噪需求强Size=5 或 7检测对角边缘FilterType='frei_chen'与其他算子的对比
算子特点适用场景sobel_amp灵活调节核大小,多种梯度计算方式通用边缘检测edges_image集成非极大值抑制(NMS)和亚像素精度高精度边缘(如测量)canny双阈值和NMS,抗噪能力强但计算量大复杂背景下的弱边缘检测
2.亚像素精度边缘提取算子(常用)edges_sub_pix(Image : Edges : Filter, Alpha, Low, High : )详解:
函数原型:- edges_sub_pix(Image : Edges : Filter, Alpha, Low, High : )
复制代码
- 功能:亚像素级精度的边缘检测,输出连续的边缘轮廓(XLD格式)。
- 输入/输出:
- Image:输入图像(单通道灰度图像)。
- Edges:输出的亚像素边缘轮廓(XLD对象)。
- Filter:边缘检测滤波器类型(如 'canny', 'lanser2', 'deriche1')。
- Alpha:滤波器的*滑参数(控制边缘锐度与抗噪性)。
- Low, High:滞后阈值(用于边缘连接)。
参数详解
1. **Filter(滤波器类型)**
不同滤波器对应不同的边缘检测算法:
- **'canny'**(默认):
- 基于高斯导数,支持亚像素精度。
- 适用于通用场景,计算效率高。
- Alpha:高斯滤波器的标准差(推荐值:1.0~3.0)。
- **'lanser2'**:
- 使用 Lanser 滤波器,边缘定位更精确。
- 适用于高精度测量,但计算量较大。
- Alpha:*滑参数(推荐值:0.3~0.7)。
- **'deriche1'** 和 **'deriche2'**:
- 基于递归滤波器,适合实时处理。
- Alpha:控制*滑程度(值越大,*滑越强)。
2. **Alpha(*滑参数)**
- 作用:*衡边缘锐度与噪声抑制。
- 小Alpha(如 0.5):保留细节,但易受噪声干扰。
- 大Alpha(如 3.0):强*滑,适合高噪声图像。
- 典型值:
- 'canny':1.0~3.0。
- 'lanser2':0.3~0.7。
3. **Low 和 High(滞后阈值)**
- 作用:经验规则:High ≈ 2 * Low。
- High:边缘强度的最低阈值,高于此值的边缘被保留。
- Low:低于此值的边缘被忽略;介于两者之间的边缘需与高阈值边缘连接。
- 示例:
- 若图像对比度低,设置 Low=10, High=20。
- 若对比度高,设置 Low=30, High=60。
使用示例
示例 1:Canny 边缘检测
- read_image(Image, 'part.png')
- edges_sub_pix(Image, Edges, 'canny', 1.5, 25, 50)
- dev_display(Edges) * 显示亚像素边缘
复制代码
示例 2:Lanser 滤波器(高精度)
- edges_sub_pix(Image, Edges, 'lanser2', 0.5, 20, 40)
复制代码
应用场景
- 工业测量:
- 检测零件边缘,用于尺寸测量。
- 参数建议:Filter='lanser2', Alpha=0.5, Low=20, High=40。
- 车道线检测:
- 提取车道线轮廓,结合形态学处理。
- 参数建议:Filter='canny', Alpha=1.5, Low=15, High=30。
- 医学图像分析:
- 定位组织或器官边界。
- 参数建议:Filter='canny', Alpha=2.0, Low=10, High=20。
参数调优策略
问题现象解决方案边缘断裂降低 Low 或增大 Alpha噪声过多增大 Alpha 或提高 Low/High边缘模糊减小 Alpha漏检弱边缘降低 High 或 Low对比其他边缘检测算子
算子精度抗噪性速度适用场景edges_sub_pix亚像素高中高精度测量sobel_amp像素级中快快速边缘检测canny像素级高慢复杂背景下的边缘总结
edges_sub_pix 是 Halcon 中实现亚像素边缘检测的核心算子,通过合理选择滤波器类型(Filter)、*滑参数(Alpha)和阈值(Low, High),可在噪声抑制与细节保留之间取得*衡。典型场景包括工业零件测量、车道线识别和医学图像分析。实际应用中需结合后处理操作(如边缘连接和拟合)以提升结果质量。
3.像素精度边缘提取算子edges_image(Image : ImaAmp, ImaDir : Filter, Alpha, NMS, Low, High : )详解:
函数原型:- edges_image(Image : ImaAmp, ImaDir : Filter, Alpha, NMS, Low, High : )
复制代码
- 功能:执行像素级边缘检测,输出梯度幅值图像(ImaAmp)和方向图像(ImaDir),支持多种滤波器和非极大值抑制(NMS)。
- 输入/输出:
- Image:输入图像(单通道灰度图像)。
- ImaAmp:输出梯度幅值图像(灰度图,高值对应边缘)。
- ImaDir:输出梯度方向图像(角度图,范围0~180°)。
- Filter:边缘检测滤波器类型(如 'canny', 'sobel_fast')。
- Alpha:滤波器*滑参数。
- NMS:非极大值抑制模式('none', 'nms', 'thin')。
- Low, High:滞后阈值(用于边缘连接)。
参数详解
1. **Filter(滤波器类型)**
- **'canny'**:
基于高斯导数的Canny算法,支持亚像素级精度。
- Alpha:高斯滤波的标准差(推荐值1.0~3.0)。
- 特点:抗噪能力强,适用于复杂场景。
- **'sobel_fast'**:
优化的Sobel算子,计算速度快。
- Alpha:无意义(可设为任意值)。
- 特点:适合实时处理,但精度较低。
- **'lanser2'** 或 **'deriche2'**:
高精度滤波器,适合测量任务。
- Alpha:控制*滑强度(参考值0.3~0.7)。
2. **Alpha(*滑参数)**
- 作用:控制滤波器的*滑程度。
- 小Alpha(如0.5):保留细节,适合清晰边缘。
- 大Alpha(如3.0):强*滑,适合高噪声图像。
3. **NMS(非极大值抑制模式)**
- **'none'**:不进行非极大值抑制,输出宽边缘。
- **'nms'**:标准非极大值抑制,细化边缘至单像素宽。
- **'thin'**:优化细化模式,适合高精度测量。
4. **Low 和 High(滞后阈值)**
- 作用:经验规则:High ≈ 2 * Low。
- High:边缘强度的最低阈值,高于此值的像素被保留为强边缘。
- Low:低于此值的像素被忽略;介于两者之间的像素需与强边缘连接。
- 示例:
- 低对比度图像:Low=10, High=20。
- 高对比度图像:Low=30, High=60。
使用示例
示例1:Canny边缘检测(带NMS)
- read_image(Image, 'part.png')
- edges_image(Image, Amp, Dir, 'canny', 1.5, 'nms', 20, 40)
- threshold(Amp, Edges, 1, 255) // 二值化边缘
复制代码
示例2:Sobel快速检测(无NMS)
- edges_image(Image, Amp, Dir, 'sobel_fast', 0, 'none', 10, 20)
复制代码 应用场景
- 工业零件检测:
- 参数:Filter='canny', Alpha=1.5, NMS='nms', Low=20, High=40。
- 效果:高精度定位边缘,用于尺寸测量。
- 实时视频处理(如车道线检测):
- 参数:Filter='sobel_fast', NMS='none', Low=15, High=30。
- 特点:牺牲精度换速度,适合嵌入式设备。
- 医学图像分析(如血管分割):
- 参数:Filter='lanser2', Alpha=0.5, NMS='thin', Low=10, High=20。
- 效果:增强弱边缘检测能力。
参数调优策略
问题现象解决方案边缘过宽启用 NMS='nms' 或 NMS='thin'噪声过多增大 Alpha 或提高 Low/High弱边缘漏检降低 Low 和 High计算速度慢改用 Filter='sobel_fast'与其他算子的对比
算子精度抗噪性输出类型适用场景edges_image像素级高梯度幅值+方向通用边缘检测edges_sub_pix亚像素高XLD轮廓高精度测量sobel_amp像素级中梯度幅值快速边缘检测总结
edges_image 是 Halcon 中灵活的边缘检测算子,支持多种滤波器和非极大值抑制模式。其核心优势在于:
- 灵活性:通过 Filter 和 NMS 适配不同场景(速度、精度、抗噪性)。
- 可调性:通过 Alpha 和阈值*衡噪声抑制与细节保留。
- 输出丰富:梯度幅值和方向信息可用于后续处理(如边缘跟踪或方向分析)。
典型应用包括工业检测、医学图像处理和实时视频分析。实际使用中需根据具体需求调整参数,并配合阈值分割或形态学操作优化结果。
写到这里我想的是边缘检测都学了,霍夫变换也可以了解学习一下,反正基本都是可以配合起来一起使用的:霍夫变换的基本原理
Halcon 中的霍夫变换(Hough Transform)是一种强大的工具,主要用于从图像中检测几何形状(如直线、圆、椭圆等)
霍夫变换通过将图像空间中的点映射到参数空间(极坐标系),利用投票机制检测几何形状。
对于直线检测,每个边缘点 (x,y) 对应极坐标中的一条正弦曲线:
- r:直线到原点的距离(像素)
- θ:直线与图像x轴的夹角(弧度,范围:-π / 2 ~ π / 2)
关键步骤:
- 参数空间量化:将 θ 和 r 离散化为有限区间。
- 累加器投票:每个边缘点在参数空间中对应的曲线经过的区间投票计数。
- 峰值检测:累加器值超过阈值的区间视为检测到的直线参数。
霍夫变换在halcon中的算子有:hough_lines(),hough_circles(),hough_line_trans(),hough_circle_trans()等等。然后继续我们的算子学习正题: 4.霍夫变换直线检测算子hough_lines(RegionIn : : AngleResolution, Threshold, AngleGap, DistGap : Angle, Dist)详解(像刚才的车道线的提取就可以用这个函数来实现): 示例1:基础直线检测
- * 读取图像并提取边缘
- read_image(Image, 'road.png')
- edges_sub_pix(Image, Edges, 'canny', 1.5, 20, 40)
- threshold(Edges, RegionEdges, 1, 255)
- * 霍夫变换检测直线
- hough_lines(RegionEdges, 0.02, 50, 0.1, 10, Angle, Dist)
- * 绘制检测到的直线
- gen_region_hline(RegionLines, Angle, Dist)
- dev_display(Image)
- dev_display(RegionLines)
复制代码
函数原型:- hough_lines(RegionIn : : AngleResolution, Threshold, AngleGap, DistGap : Angle, Dist)
复制代码
- 功能:使用霍夫变换(Hough Transform)从二值区域中检测直线,返回直线的角度和距离参数。
- 输入/输出:
- 输入:
- RegionIn:输入区域(通常为边缘检测后的二值图像)。
- 参数:
- AngleResolution:角度分辨率(控制角度检测精度)。
- Threshold:累加器阈值(决定直线的最小支持点数)。
- AngleGap:角度合并阈值(合并相*角度的直线)。
- DistGap:距离合并阈值(合并相*距离的直线)。
- 输出:
- Angle:检测到的直线的角度(弧度制,范围:-π/2 ~ π/2)。
- Dist:直线到原点的距离(像素单位,基于极坐标公式:r = x*cosθ + y*sinθ)。
参数详解
1. **AngleResolution(角度分辨率)**
- 作用:定义霍夫空间中角度θ的步长(分辨率)。
- 取值范围:通常为 0.01 ~ 1.0(弧度)。
- 影响:
- 小值(如 0.01):角度划分精细,检测精度高,但计算量大。
- 大值(如 0.1):角度划分粗糙,计算速度快,可能漏检细节。
2. **Threshold(累加器阈值)**
- 作用:直线在霍夫空间中的累加器值需超过此阈值才被保留。
- 示例:调优建议:根据图像中边缘点密度调整,避免漏检或噪声干扰。
- Threshold=50:直线至少需要50个边缘点支持。
3. **AngleGap(角度合并阈值)**
- 作用:合并角度差小于此值的相邻直线。
- 单位:弧度。
- 示例:
- AngleGap=0.05(约2.86°):若两条直线角度差小于0.05弧度,视为同一方向。
4. **DistGap(距离合并阈值)**
- 作用:合并距离差小于此值的相邻直线。
- 单位:像素。
- 示例:
- DistGap=10:若两条直线距离差小于10像素,视为同一位置。
示例2:合并相*直线
[code]* 合并角度差 |