资讯详情

Halcon多圆检测与圆心距离计算:从原理到实战的全流程解析

📅 2026/9/16 7:09:13 | 华诺云谱 👁 阅读
Halcon多圆检测与圆心距离计算:从原理到实战的全流程解析
做视觉项目这么多年圆检测算是最常碰到的需求之一。不管是定位工件圆心、检测轴承滚珠、测量两个孔位之间的距离还是做对象的轮廓匹配Halcon里的圆拟合这套操作几乎是每次都要写一遍的活儿。网上零散的代码很多但要么只讲一个圆要么完全没讲多目标怎么处理经常是抄过来没法直接用。这篇文章我就把怎么快速找到图像里的多个圆、并把圆心距离算出来这件事从头到尾完整走一遍代码直接可跑参数也会展开说说为什么要这样设。我默认你会打开HDevelop跟着操作如果还没安装环境或者正在折腾许可文件先花十分钟把Halcon装好并确认license能用后文内容都基于HDevelop 13到23版之间常见的算子接口老版本差异不大。图像方面我建议先拿一张背景简单、目标对比度清晰的图来测试比如白底上的黑色垫片或背光下的透明瓶盖等流程跑通了再上复杂的现场图。1. 项目背景与整体方案设计1.1 圆检测在工业视觉中的典型场景圆是工业零件里出现频率极高的几何特征。定位销、法兰孔、轴承滚珠、密封圈、药片、瓶盖、晶圆上的对准标记全都可以抽象成“图像中的圆”。我们需要的不只是把这个圆找出来而是把它精确到亚像素级别的圆心坐标和半径值这样才能继续做位置判断、尺寸测量或机械臂抓取引导。举个例子装配线上有两个定位孔视觉系统拍一张图算出两个圆心之间的距离再告诉机器人该往哪儿插销钉。这种场景下图像里往往不止一个圆有时候是两个有时候是十几个。只要圆的个数一变或者圆的排列不规则你就不能靠鼠标点两下收工得让代码自动把每个圆都找出来、分别拟合再统一计算彼此之间的距离。另一个常见场景是批量检测。一块板子上有几十个过孔要判断所有孔位是否偏离设计坐标。这时候你要的不是“某一个圆”的参数而是整张图里所有圆的圆心列表再和标准模板做比对。标题里强调的“多个圆”和“圆心的距离”恰恰是这种批量测量需求的核心。1.2 整体流程设计从图像到距离结果拿到一张含有多个圆的图片我通常会按照下面这条流水线来处理顺序基本固定改动的只有参数读图并灰度化。如果相机直接输出灰度图就跳过第二步。预处理核心是把目标圆和背景拉开对比度。常用的方法有阈值分割、灰度形态学、中值滤波。阈值分割得到包含圆区域的二值图。这一步要保证圆区域完整不能断成碎块。连通域分析把每一个独立的圆区域单独拎出来。区域筛选用面积、圆度、长宽比等特征把干扰块过滤掉只留下真正要测的圆。提取每个区域的亚像素轮廓。用轮廓做圆拟合得到圆心坐标(row, column)和半径Radius。根据圆心坐标计算两两之间的距离输出结果。这八步里第3到第5步是传统Blob分析连通域分析的固定套路第6到第7步是Halcon里从区域到几何参数的过渡。整套流程不涉及深度学习不需要标注数据只要图像质量不过分恶劣稳定性和速度都有保障。Halcon里很多封装好的测量助手其实内部也是走同样的思路只不过把它们自动化了。我自己做项目时会把这套流程封装成一个小函数输入是图像和一些上下限参数输出是圆心坐标数组和半径数组。有了这个函数不管是两个圆还是二十个圆调用起来都是一行代码的事。2. 环境准备与关键算子选型2.1 开发环境HDevelop安装与基本操作Halcon目前由MVTec公司出品安装包可以直接去官网下载试用版也可以用公司购买的正版授权。安装过程基本是下一步下一步装完启动HDevelop它会要求指定license文件。如果你只是学习试用版license足够跑通本文的代码如果是商用项目请务必使用正规授权。打开HDevelop后你会看到左侧是算子窗口中间是程序编辑区下方是变量窗口。写图像处理程序时我习惯先把图像读进内存然后一步一步在编辑区写算子每写一行按F6执行再在变量窗口里双击查看中间结果。这种“逐步执行可视化中间结果”的方式是调试Halcon程序的核心手法一定要养成习惯。对新手来说第一次跑通代码最好的方式是新建一个程序把下面第三节的完整代码粘贴进去改一下图像路径然后直接运行。运行完再在前面的read_image之后插入断点逐段双击变量窗口里的Region、Contour等图标亲眼看每一步产生的变化。看一遍胜过读十篇教程。2.2 核心算子逐个拆解整个流程涉及十几个算子但真正的关键角色是下面这几个read_image把图像文件读进内存。Halcon里图像用HObject类型承载这个算子背后会申请内部存储不用手动释放HDevelop会帮你管理。rgb1_to_gray三通道彩色图转单通道灰度。工业相机很多直接输出灰度图这一步可以直接跳过但如果拿手机或普通相机拍的彩色图来测试就需要先转灰度。Halcon里灰度转换的权重是按标准公式来的不用自己操心。threshold阈值分割。它把灰度值处于给定区间的像素设为前景其他设为背景。参数是一个灰度下限和一个灰度上限形式是threshold(Image, Region, MinGray, MaxGray)。这个算子是整套Blob分析的分水岭参数选得好不好直接影响后面所有步骤。connection连通域分析。它把一个大Region里互不相连的像素块拆成多个独立Region。注意Halcon里的Region是一组像素的集合threshold得到的结果可能包含好几个孤立的圆块connection之后每个圆才能作为独立对象被单独处理。这一步特别关键否则你过滤的时候会把所有圆当一个整体。select_shape按形状特征筛选区域。它有几十个特征可用最常用的是area面积、circularity圆度、width和height宽高。我一般至少同时用面积和圆度两个条件。圆度的计算是基于区域的面积和周长的理想圆的圆度是1实际零件在0.7到0.99之间波动具体阈值要根据你的实物调试。gen_contour_region_xld把区域的边缘转成亚像素轮廓。注意Halcon里区域Region是像素精度的而XLD轮廓是浮点精度的。从Region转XLD这一步是把像素边缘平滑成亚像素位置的关键直接决定后面圆拟合的精度。fit_circle_contour_xld对亚像素轮廓做圆拟合。它会根据轮廓上的点通过最小二乘法拟合出一个最匹配的圆输出圆心坐标(row, column)和半径Radius。这个算子还带一个算法参数可选algebraic代数拟合或geometric几何拟合。几何拟合精度更高但速度稍慢一般场景用代数拟合就够了。还有一个重要输出是Score表示拟合的贴合程度可以用来判断这个轮廓是不是一个标准的圆。distance_pp计算两个点之间的欧几里得距离。输入两个点的行列坐标输出距离值。这个算子既可以算单对点的距离也支持数组形式批量计算。除了这几个还有个频繁用到的小算子叫area_center可以快速得到区域的面积和质心坐标。在不需要高精度圆拟合的场景直接用区域的质心当圆心也很方便而且速度极快。3. 完整代码与逐步实现3.1 主程序完整代码我把完整程序贴在下面图像路径换成你自己的测试图就能跑。代码里加了详细注释方便对照前文的流程来看。* 读取图像路径请改成你自己的图片文件 read_image (Image, circles.png) * 彩色图转灰度图如果本身就是灰度图这步可以直接注释掉 rgb1_to_gray (Image, GrayImage) * 中值滤波去除少量噪点保留边缘信息 median_image (GrayImage, ImageMedian, circle, 3, mirrored) * 阈值分割假设目标圆比背景暗取灰度值0到128之间的像素作为前景 threshold (ImageMedian, Regions, 0, 128) * 连通域分析把不相连的圆块拆开 connection (Regions, ConnectedRegions) * 筛选出面积合适的区域去掉噪点和杂质 select_shape (ConnectedRegions, SelectedRegions, area, and, 500, 100000) * 再用圆度筛选去掉明显不是圆的区域 select_shape (SelectedRegions, CircularRegions, circularity, and, 0.5, 1.0) * 提取区域边缘轮廓转成亚像素XLD gen_contour_region_xld (CircularRegions, Contours, border) * 对每个轮廓拟合圆得到圆心和半径 fit_circle_contour_xld (Contours, algebraic, -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder) * 计算所有圆心两两之间的距离 Count : |Row| if (Count 1) for i : 0 to Count - 2 by 1 for j : i 1 to Count - 1 by 1 distance_pp (Row[i], Column[i], Row[j], Column[j], Distance) * 在图像上显示圆心和连线方便肉眼验证 gen_cross_contour_xld (Cross1, Row[i], Column[i], 20, 0.785398) gen_cross_contour_xld (Cross2, Row[j], Column[j], 20, 0.785398) dev_display (Image) dev_display (Cross1) dev_display (Cross2) disp_message (WindowHandle, Distance: Distance, window, Row[i] - 40, Column[i] - 40, black, true) stop() endfor endif endif这段代码看起来不长但每一行背后都有讲究。下面我把几个关键段落单独拿出来拆开讲方便你按自己的项目去调整参数。3.2 关键步骤代码详解灰度化与滤波rgb1_to_gray (Image, GrayImage) median_image (GrayImage, ImageMedian, circle, 3, mirrored)灰度化这一步不必多说。重点说median_image它的作用是去噪的同时尽量保留边缘。工业现场打光不均匀、传感器有热噪声或者工件表面有细微纹理都会在图像上形成孤立亮点或暗点。如果用高斯滤波边缘会变模糊后面圆拟合的边缘定位精度会下降中值滤波则能在不破坏边缘陡峭度的前提下把孤立噪点抹掉。这里的参数circle, 3表示用半径为3像素的圆形窗口做中值滤波。半径太大会把细小的圆边缘磨掉太小起不到降噪作用。我个人习惯先用3试如果噪点还很多再试5。阈值分割threshold (ImageMedian, Regions, 0, 128)阈值是整套流程里最需要花时间调的参数。我上面写0到128是假设目标圆是暗色、背景是亮色。如果你图像里圆是亮的而背景是暗的就要反过来取128到255。怎么快速确定阈值范围在HDevelop里可以用灰度直方图工具它会显示每个灰度值对应的像素数量分布。观察直方图通常会出现两个峰一个代表背景一个代表目标峰谷的位置就是阈值的好选择。要特别注意阈值分割后得到的Regions里可能会包含面积特别小的小噪点也会包含亮斑、文字、边缘反光等干扰区域。不要慌后面有select_shape统一过滤。连通域分析connection (Regions, ConnectedRegions)这一步是很多人容易忽略的。没有connection之前所有前景像素是一个整体Region哪怕它们之间隔了一千像素编程上也是“同一个对象”。connection会根据像素是否八邻域连通把这个大Region拆成一个个互不接触的小Region。拆完之后每个圆就是一个独立的Region元素。Halcon里Region数组是隐式支持的connection之后你可以直接通过select_shape对数组整体操作。区域筛选select_shape (ConnectedRegions, SelectedRegions, area, and, 500, 100000) select_shape (SelectedRegions, CircularRegions, circularity, and, 0.5, 1.0)筛选条件的选择直接决定你后面处理的是不是真正的目标圆。面积下限要根据图像分辨率和圆的实际大小估算。比如一个直径100像素的圆面积大约是7854像素我设500的下限能把各种小噪点全滤掉上限100000则能滤掉一些意外出现的大块亮区。面积上限可以设一个很大的值反正后面还有圆度把关。圆度circularity这个特征很妙它的计算公式是4π乘以面积除以周长的平方。正方形大概是0.785等边三角形是0.605细长条会非常低而圆形接近1。我取0.5到1.0能筛掉大部分矩形、细线、不规则反光。如果你的圆本身因为打光问题边缘有些残缺圆度可能会掉到0.4以下这时候不要盲目的把下限调太低而是要回头优化打光或阈值让圆区域更完整这样拟合出来的半径才准。有时候单靠面积和圆度还不够。比如图像里有一个圆形标签文字和你要测的圆环混在一起面积圆度都很接近这时候可以根据位置筛选或者用灰度值进一步区分。总之select_shape可以连写多个每加一个条件干扰就少一分。轮廓提取与圆拟合gen_contour_region_xld (CircularRegions, Contours, border) fit_circle_contour_xld (Contours, algebraic, -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)从Region转XLD轮廓这一步是把像素精度的边缘转换成浮点精度的亚像素坐标链。Halcon内部会做边缘平滑和外插拟合出来的圆半径能到亚像素精度这是它比传统像素级Blob分析更精确的地方。fit_circle_contour_xld的参数里第一个是输入的轮廓数组第二个是拟合算法我用algebraic后面几个数字分别是最大轮廓点数、最大半径、起始角度、结束角度、轮廓点距离阈值等这些在大多数场景保持默认即可。输出Row和Column是圆心坐标数组Radius是半径数组。如果你对精度要求特别高可以把算法改成geometric它迭代次数更多对轮廓质量也敏感速度会慢一些但精度通常更好。这里的数组长度等于之前筛选出来的目标圆个数。比如图里有5个圆Row就是一个长度为5的元组Row[0]是第一个圆的行坐标以此类推。3.3 多个圆的距离计算循环与结果展示Count : |Row| if (Count 1) for i : 0 to Count - 2 by 1 for j : i 1 to Count - 1 by 1 distance_pp (Row[i], Column[i], Row[j], Column[j], Distance) ... endfor endfor endif计算多圆之间的两两距离最直观的方法就是双重循环。i从0到Count-2j从i1到Count-1这样每一对圆只会被计算一次不会重复也不会漏掉。distance_pp的输出是像素距离。如果你的相机已经做了标定想得到毫米单位的真实距离可以参考第5节的内容做坐标变换或者在标定完成后直接把像素距离乘以一个比例系数。显示部分我用gen_cross_contour_xld在圆心位置画一个十字标记再用disp_message在图像上显示距离值。注意disp_message需要传一个窗口句柄HDevelop里可以通过dev_open_window得到写成0也可以在某些版本下自动使用当前活动窗口。为了不打断程序上面代码里放了stop()方便你每看一对圆按一次F6继续。实际项目里我会把这个显示部分放到一个单独调试开关里正式跑的时候关掉提高速度。4. 调试技巧与常见问题排查4.1 阈值与筛选参数如何一步到位很多初学者最头疼的就是参数怎么选。我的经验是不要直接在生产环境的程序里反复试效率太低。正确做法是先复制一份图像在HDevelop里用“灰度直方图”工具观察阈值范围再用“特征检测”交互界面实时调整select_shape的参数一边调一边看结果。Halcon的Feature Histogram工具非常强大。你把图像或者某个Region连接到工具里它可以显示面积、圆度、灰度均值等特征在整个区域集合上的分布。你可以直接在工具里拖动上下限立刻看到筛选效果。等参数调好再把数值抄回代码里。这比自己写print输出再猜要快一个数量级。另外如果是彩色图像可以用decompose3把RGB三通道拆开选择对比度最高的那个通道做后续处理。比如红色工件在蓝色背景下B通道的对比度可能明显高于R通道。优先使用对比度高的通道可以让阈值分割稳定很多。4.2 光照与背景干扰的应对圆检测遇到问题十有七八不是算法的问题而是图没拍好。打光均匀、背景干净的情况下上面的代码几乎不需要改就能跑。但如果图像是现场拍的往往有以下几种干扰第一种是阴影。工件边缘投下的阴影会让圆区域和背景的灰度边界变得模糊阈值无论怎么调边缘都会抖动。这种情况可以在代码里加大Median滤波半径或者考虑换用背光源从工件背面打光让工件呈黑色剪影阴影问题迎刃而解。第二种是反光。金属表面会把点光源反射成高亮光斑导致圆区域内部出现亮斑外圈却被阴影包围形似圆环。这种情况下单纯的threshold很难同时处理内部亮斑和外部阴影。我的应对办法是先用灰度形态学做闭运算把圆环内部的孔洞填上再二值化。Halcon里对应算子是gray_closing可以理解为先膨胀再腐蚀能把细小的暗缝填平。闭运算之后圆区域就从断断续续的环变成实心圆。第三种是复杂背景比如传送带上有纹理、旁边有其他零件。这时候靠全局阈值很难分离目标。我通常会用动态阈值先做一次均值滤波生成背景估计图再把原图和背景相减只剩下和背景亮度差异明显的目标。算子dyn_threshold专门干这个活。它比固定threshold更适合背景光照不均的场合。还有一种更省心的方式是换思路直接用Halcon的find_circle或基于形状匹配的create_shape_model来做圆定位。前者是专门针对圆特征的快速查找后者通过模板匹配对旋转、缩放、遮挡都有更强的鲁棒性。不过这些方案在配置复杂度上比Blob分析高本文不再展开有兴趣可以翻Halcon的例程了解。4.3 常见报错与解决方案速查表我整理了一份问题速查表按实际项目里出现频率从高到低排列方便你对照排查。问题现象可能原因解决方案threshold后Regions为空灰度区间设置反了目标在另一边检查直方图把区间换成相反的范围select_shape后一个区域都不剩面积或圆度上下限设置过严先用Feature Histogram看实际值分布放宽条件圆数量偶尔多一个或少数一个光照波动导致阈值边缘不稳定改用动态阈值或增加滤波强度检查图像采集帧率是否太低fit_circle后半径明显偏大或偏小区域边缘包含杂散突起或缺口在gen_contour_region_xld前对Region做开运算或闭运算拟合出的圆严重偏离真实位置有干扰轮廓混入圆度筛选失效增加灰度均值筛选或限定圆心在ROI区域内程序运行速度太慢图像过大或轮廓点数过多在ROI内处理或缩小图像尺寸fit_circle限制轮廓点数disp_message报窗口句柄错误没有先dev_open_window或句柄传了0在局部不适用在程序开头dev_open_window(0,0,512,512,black,WindowHandle)并作为参数传入多个圆颜色深浅不一同一个阈值漏检目标本身的灰度差异大考虑对每个目标自适应分割或转用基于边缘的找圆算法其中灰度均值筛选这个补充条件值得单独说一下。比如图像里有两个圆一个是深黑色一个是浅灰色你在threshold时只能选一个灰度区间另一个就可能漏掉。这时可以在select_shape里加一个gray_mean条件先用一个宽的阈值把两个圆都粗分割出来再用灰度均值把同类的圆分组处理。如果必须同时测量深浅两个圆则要分开两次处理每次只选一个灰度段的圆。5. 从像素到毫米标定与扩展应用5.1 相机标定与物理距离换算很多人跑通了代码看到程序输出圆心坐标和像素距离第一反应是这个距离除以分辨率不就能得到毫米吗如果相机光轴完全垂直于被测平面、镜头畸变可忽略不计这种做法是近似可行的。但实际项目中相机安装难以做到完全垂直镜头也存在径向畸变尤其在图像边缘区域直接按比例换算会带来较大误差。正规做法是使用Halcon的标定助手做相机标定。流程大致是打印一张Halcon标准标定板用相机在不同姿态下拍15到20张图片标定算子自动计算内参焦距、畸变系数、像素尺寸和每个视角的外参。标定完成后可以用image_to_world_plane算子把图像坐标转换到世界平面坐标系或者用contour_to_world_plane直接把轮廓转过去。转换之后再用distance_pp算出来的就是真实的物理距离了。如果只是做一个快速验证不追求高精度也可以用简单的比例尺法拍一个已知尺寸的标准件算出它的像素直径和实际直径之比当作像素当量。这个方法在视野中心区域、相机垂直安装的前提下能达到1%到3%左右的精度很多东西检测任务够用了。但要注意如果镜头视角较大或者有俯仰角边缘畸变会造成明显误差这时候就别偷懒老老实实做标定。5.2 程序扩展定位、测量与批量处理当核心的圆检测和距离计算跑通之后这个程序的价值就远不止“找一个圆”了。你可以在这套基础上做很多扩展第一是位置补偿。视觉系统每次只算绝对坐标但工件在传送带上不可能每张图都停在同一个位置。你可以在测量之前先计算所有圆心坐标的均值把它作为工件的参考中心再输出各圆心相对于参考中心的偏移量。这样机械手只需要知道工件中心相对于相机视野中心的偏差就能调整抓取位置这就是最常见的视觉引导思路。第二是尺寸测量。拟合出来的Radius数组本身就是每个圆的直径来源。你可以通过min_max_tuple或直接在代码里设定上下限判断每一个圆的直径是否超差。实时输出包括圆直径、圆度、圆心距离等多项指标。第三是批量处理。工业项目很少只处理单张图片。你可以用list_files读取一个文件夹下的所有图片循环调用上面这段核心逻辑把每次的测量结果存成csv或通过socket发给上位机。这样从“跑通一张图”变成“跑通一个批次”通常只需要在程序外包一层循环加上文件读写。第四是混合使用深度学习。Halcon的深度学习工具可以做目标检测把ROI区域里的圆粗略定位出来再用传统的fit_circle做精确拟合。这个组合能应对背景很复杂的场景因为深度模型负责“找”传统视觉负责“量”各发挥各的优势。如果你用C#或C做上位机开发Halcon的库也提供了完整的接口。你可以在HDevelop里把调试好的脚本导出成C#或C代码然后封装成一个类供上位机调用。图像采集部分可以用Halcon自己支持的GigE Vision或USB3 Vision接口也可以从第三方相机SDK拿图再传给Halcon处理后者在多相机、定制触发等场景下更灵活。最后再补充一点关于ROI的体会。从性能角度讲很多现场相机分辨率高达500万甚至1200万像素如果全图跑Blob分析一些复杂的筛选和拟合操作耗时可能达到几十毫秒甚至上百毫秒。而实际需要检测的圆往往只在某个小区域内。你可以先用draw_rectangle1或read_region手动框出ROI再对裁剪后的图像运行核心算法速度提升会非常明显。这个习惯一开始就养成后面现场调试会省很多事。我自己在做这类视觉项目时最喜欢用的调试流程是先在HDevelop里把图像跑起来每一个中间结果都双击看看确认OK之后再往工程里集成。千万不要一上来就把代码扔进C#项目里调试那样既看不到中间图像参数调整也麻烦。把精力花在把图像调干净、把特征选准确这两件事上你的圆检测项目就已经成功了八成。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。