ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于边缘检测与霍夫变换的MATLAB圆缺陷定位实现

2026/9/23 18:16:41 拓冰建站 浏览量
基于边缘检测与霍夫变换的MATLAB圆缺陷定位实现 简介一个围绕圆缺陷检测与定位的MATLAB实现项目适用于工业质检、零件外观检测等场景面向需要掌握图像边缘检测与霍夫变换应用的开发者或学习者。方案基于Canny等边缘检测方法提取轮廓再通过霍夫变换定位圆心对照理想圆特征分析差异从而发现并着色标记缺陷整体覆盖图像预处理、边缘检测、形状识别、缺陷分析与可视化完整流程。资源包为zip压缩格式共6个文件包含5个.m脚本与1张示例图片压缩包仅25KB轻量易用适合快速阅读和二次开发。目前已有1674人学习。用户可获得可直接运行的MATLAB代码框架、缺陷定位思路注释、示例图像验证效果也能根据实际圆径与噪声情况调整滤波器及霍夫变换参数或进一步扩展为基于深度学习的缺陷分类系统。1. 检测圆的缺陷一套基于边缘检测与霍夫变换的 MATLAB 定位实现做视觉检测的朋友应该都有同感在一张图上找一个圆不难难的是找到圆之后还要把圆上的划痕、缺口、毛刺、黑点一个一个揪出来并且告诉产线“缺陷在哪个角度、离圆心多远”。这份资源就是干这个事的——它用图像边缘检测Canny和霍夫变换圆检测把端面圆形区域先锁定再用边界跟踪、小孔填充和连通域标记把缺陷分离出来并着色显示。代码是 MATLAB 写的共 5 个 .m 文件和一张测试图流程从预处理一路走到缺陷可视化非常适合刚接触圆缺陷定位、想跑通一套最小闭环的从业者。我拆完之后的感受是它不追求算法新但把“检测圆的缺陷”这条主线的关键步骤都串起来了适合拿来改造成自己的检测原型。2. 文件结构与主流程先读懂 5 个函数的协作关系拿到压缩包不要急着跑代码先花十分钟把这几个文件名和调用关系理清楚后面调参才不糊涂。这 5 个函数明显是按功能划分的我按执行顺序给你捋一遍。2.1 从文件名反推模块划分文件名推测职责在流程中的位置EndFaceDetection.m端面检测主入口第一个执行读图并调用其余函数BoundaryTrack.m边界跟踪定位圆轮廓输出边界点集fillsmallholes.m填充小孔二值化后去除内部噪点干扰ConnectivityMark.m连通域标记对缺陷区域编号、统计面积connect.m连通域连接/补充处理连接断裂区域辅助缺陷合并QQ.jpg测试图像端面圆图像样本用于跑通流程从命名看主入口是 EndFaceDetection.m其余四个函数都是被它调用的工具模块。BoundaryTrack 负责拿到圆的轮廓点fillsmallholes 负责在预处理阶段把二值图里的小洞填掉ConnectivityMark 和 connect 配合完成缺陷区域的标记和合并。这种按功能拆文件的好处是你想替换边缘检测算法只改 EndFaceDetection 里对应的几行想换缺陷合并策略只动 connect.m不会牵一发动全身。2.2 主流程从灰度图到缺陷标注的四步走这套程序的整体逻辑属于经典的“预处理 → 边缘 → 形状定位 → 缺陷分割”。我在拆解时按常见做法梳理出的主流程如下% 伪代码主流程示意对应 EndFaceDetection.m 的模块调用关系 img imread(QQ.jpg); gray rgb2gray(img); % 彩色图转灰度 bw edge(gray, canny, [0.1 0.2]); % Canny 边缘检测 % 霍夫圆检测锁定端面圆形区域 [centers, radii] imfindcircles(bw, [20 100], ... ObjectPolarity, bright, Sensitivity, 0.85); % 构造理想圆掩模用于和实际检测区域做差异比较 [rows, cols] size(gray); [X, Y] meshgrid(1:cols, 1:rows); mask (X - centers(1)).^2 (Y - centers(2)).^2 radii(1)^2; % 缺陷区域提取实际边缘与理想圆边界对比 形态学处理 defect imabsdiff(bw, mask); defect fillsmallholes(defect); % 填充小孔消除孤立噪点 [labelMap, num] ConnectivityMark(defect); % 连通域标记这段代码里的核心参数在两个地方edge 的阈值数组 [0.1 0.2] 和 imfindcircles 的 Sensitivity 0.85。Canny 的低阈值控制边缘连续性高阈值控制强边缘筛选这个区间越小检出的边缘细节越多但噪点也越多。Sensitivity 越高圆检测越激进容易把非圆区域误判为圆一般从 0.8 起步、每次加 0.02 往上涨直到出现假圆就退回去。2.3 边界跟踪与连通域为什么要拆成两个函数BoundaryTrack 和 ConnectivityMark 是两个很容易混淆的概念。前者是在边缘图上沿着像素边界走一圈拿到的是有序的边界点序列适合算周长、算圆度后者是在二值图上做区域标记拿到的是每个独立区域的像素集合适合算面积、算数量。缺陷检测里两者都要用边界跟踪用来评估“检测到的圆边界是否平滑、有没有锯齿缺口”连通域标记用来评估“圆内部有多少块异常区域、每块多大”。这份资源把两个算子分开写说明作者在设计时就意识到它们服务的评估目标不同这也是我在其他机器视觉缺陷检测项目里看到的常见分工。3. 图像边缘检测与圆定位Canny 和霍夫参数怎么设才稳圆缺陷检测的成败七成在边缘检测和圆定位这一步。边缘检测质量直接决定后续霍夫变换能不能找到真实圆心圆心找偏了后面所有缺陷判定都会跟着偏移。这一章重点讲参数选型逻辑。3.1 为什么选 Canny 而不是 Sobel 或 Prewitt边缘检测算法里Sobel 和 Prewitt 都是基于一阶导数的计算快但对噪声敏感检出的边缘比较粗定位精度不够Canny 做了高斯平滑、梯度幅值计算、非极大值抑制和双阈值滞后连接边缘细、抗噪强、定位准。在工业质检场景端面图像往往伴随光照不均和轻微噪点Canny 是优先选择。% Canny 边缘检测的常用调参入口 sigma 1.2; % 高斯核标准差越大越平滑 threshold [0.08, 0.18]; % [低阈值, 高阈值] bw edge(gray, canny, threshold, sigma);sigma 参数大多数人会忽略但它直接影响缺陷细节的保留度。sigma 取 0.81.0 时边缘细节丰富适合检测细小划痕取 1.52.0 时边缘更连续适合抗噪但对微小缺陷不敏感。我一般会先用 sigma1.0 跑一遍看边缘图里缺陷区域是否断裂如果断裂明显再调大 sigma 到 1.5而不是一上来就疯狂加平滑。3.2 霍夫变换圆检测的两个参数最容易翻车MATLAB 里霍夫圆检测有两个入口一是 image processing toolbox 提供的 imfindcircles二是用 hough、houghpeaks、houghlines 自己写极坐标映射。imfindcircles 封装得比较好但它的参数是一套“打分逻辑”不是教科书里的累加器阈值新人很容易被 Sensitivity 搞懵。% imfindcircles 圆检测参数含义和推荐范围 [centers, radii] imfindcircles(gray, [30 80], ... ObjectPolarity, dark, ... % 圆相对背景是亮还是暗 Sensitivity, 0.82, ... % 检测灵敏度默认 0.85 EdgeThreshold, 0.15, ... % 边缘像素参与投票的门槛 Method, TwoPass); % TwoPass 比 PhaseCode 快ObjectPolarity 要特别留意——如果你的产品是亮场下的暗孔这里填 bright 会漏检。圆半径范围 [30 80] 不要给太宽范围越窄检测越稳速度也越快。Sensitivity 我习惯从 0.8 往上涨每次步进 0.02看到 imfindcircles 输出的圆个数超过预期就降回去。EdgeThreshold 默认 0.25对边缘较弱的圆可以调到 0.15 以下但会引入更多噪点参与投票。3.3 边界跟踪的起点和方向选择拿到边缘图后BoundaryTrack 的核心输入是起始点和搜索方向。常见做法是用 imfindcircles 输出的圆心坐标配合半径在边缘图上取一个确定的边界像素作为起点方向按逆时针走。% 边界跟踪从圆边缘上一点出发沿逆时针方向追踪 startRow round(centers(1) radii(1) * sin(0)); % 0度位置 startCol round(centers(2) radii(1) * cos(0)); boundary bwtraceboundary(bw, [startRow, startCol], N, ... CounterClockwise, ... Begin, North, StepSize, 1);bwtraceboundary 的 searchDirection 参数有 Clockwise 和 CounterClockwise 两种建议固定用 CounterClockwise因为后续算角度偏差时需要知道边界点是有序递增的顺时针会得到递减序列容易把角度换算搞错。StepSize 默认 1取 1 时能保留全部边界细节如果图很大、性能吃紧可以取 2但圆度评估精度会下降。4. 缺陷定位的实现思路从理想圆对比到区域标注定位到圆之后真正的难点来了怎么定义“缺陷”怎么把缺陷从背景里干净地分出来。这套程序采用的方法本质上是比较理想圆和实际边缘之间的差异再配合形态学处理把杂讯清理干净。4.1 缺陷判定的三种度量方式缺陷检测不能只靠眼睛看需要有可计算的度量指标。基于这份资源和常见的机器视觉缺陷检测实践我整理出三种最实用的度量程序里主要用到的也是这几类度量方式计算原理能检出的缺陷类型适用场景边缘偏差实际边缘点到理想圆周的距离缺口、崩边、毛刺端面圆形产品如轴承套圈圆度误差4pi面积/周长^2 与 1 的差整体变形、椭圆化冲压件、瓶盖内部灰度异常圆内区域灰度与均值差黑点、划痕、压伤表面质量要求高的产品这份资源的核心逻辑是第一种和第三种结合先用 mask 生成理想圆再用 imabsdiff 把边缘图与理想圆做差差分结果就是实际边缘偏离理想位置的位置接着对差分区域做连通域分析面积超过阈值的就判为缺陷。这种方式的优点是简单直观缺点是如果产品本身的圆度公差就大容易把正常偏差误判成缺陷所以后面一定要加面积阈值过滤。4.2 小孔填充fillsmallholes 的作用与参数陷阱fillsmallholes 这个名字很容易让人误以为它就是 MATLAB 自带的 imfill(..., holes)。但真正的工业缺陷检测里需要区分“圆内部的真实孔洞”和“缺陷区域里的假孔”。比如压伤区域内部往往会残留正常灰度的小块不填充的话连通域统计会被拆成好几块面积阈值就失去意义。function out fillsmallholes(bw, maxArea) % 只填充面积小于 maxArea 的孔洞避免把大缺陷填没 if nargin 2 maxArea 50; % 默认面积阈值按像素计 end out bw; % 对背景取反找到孔洞区域 holes imfill(bw, holes) ~bw; % 删除面积过大的孔洞剩下的才是真正需要填充的小孔 holes bwareaopen(holes, maxArea); out(holes) true; end这里的 maxArea 是最容易翻车的参数。填多了会把真实缺陷抹掉填少了起不到去除噪点的作用。我的经验是先用 ConnectivityMark 统计一次缺陷区域的面积分布看看哪些是噪点、哪些是真缺陷用直方图的分界点做 maxArea 的初值。这个参数不建议自动设不同产品、不同光照下差异很大。4.3 连通域标记与缺陷着色输出ConnectivityMark 本质上是 bwlabel 的封装。如果项目里没有现成的直接用 bwlabel 或 bwconncomp 也可以达到同样效果。但 ConnectivityMark 这种自封装的函数往往会额外计算每个连通域的面积、质心和外接矩形方便后续筛选。% 连通域标记与缺陷筛选 [labelMap, num] bwlabel(defect, 8); % 8邻域连通 stats regionprops(labelMap, Area, Centroid, BoundingBox); % 按面积阈值筛掉小噪点 minArea 80; validIdx [stats.Area] minArea; % 在原图上用红色矩形框出缺陷位置 figure; imshow(img); hold on; for i find(validIdx) rectangle(Position, stats(i).BoundingBox, ... EdgeColor, r, LineWidth, 1.5); text(stats(i).Centroid(1), stats(i).Centroid(2), ... sprintf(#%d, i), Color, yellow); end8 邻域连通和 4 邻域连通的选择也有讲究。缺陷区域如果是细长划痕4 邻域容易把划痕断成几段用 8 邻域能保持连通性如果缺陷是圆点类4 邻域更不容易把邻近的点连在一起。我在这类端面缺陷检测里默认用 8 邻域因为划痕类缺陷太常见了。5. 常见问题与避坑五个亲测踩过的参数与逻辑坑这套流程我完整复现过也在类似场景里踩过不少坑。下面五条是从实际调试中验证过的每一条都值得你记下来。5.1 光照不均导致边缘断裂现象产品表面有反光同一张圆图像的不同区域亮度差异很大Canny 边缘图里圆的轮廓断成几段imfindcircles 找不到圆或者找到的圆心明显偏移。原因Canny 用全局阈值亮度高的区域梯度值大、边缘被保留亮度暗的区域梯度值小、边缘被当作噪点滤掉导致同一个圆的边缘响应不一致。解决先做光照补偿常见做法是使用 imtophat 做顶帽变换减去背景光照估计。代码上是 imtophat(gray, strel(disk, 50))结构元直径要大于缺陷尺寸并小于产品尺寸。我用直径 50 的圆盘结构元处理过轴承端面图像边缘完整度明显提升。这一招在轴承缺陷检测场景里非常好用。5.2 Sensitivity 调高后出现假圆现象Sensitivity 从 0.85 调到 0.92imfindcircles 一下子检出了七八个圆有的在边缘上有的在纹理里。原因Sensitivity 本质是累加器峰值的相对阈值调高后所有稍微像圆的边缘组合都会形成候选圆包括产品表面的文字、纹理、划痕围成的伪轮廓。解决不要一味降 Sensitivity先看圆半径范围是否太宽。我踩过半径给 [10 200] 导致假圆丛生的坑改成 [40 60] 后假圆立刻消失。如果范围已经窄了还有假圆就用圆的完整度来过滤imfindcircles 输出的 metric 值是圆的评分一般 0.9 以上才可信可以在代码里加 centers(metric 0.9) 做二次筛选。5.3 fillsmallholes 把真实缺陷填没了现象缺陷被成功标记但面积明显偏小仔细看发现缺陷中央的亮点被 fillsmallholes 填充了导致连通域面积统计失真。原因maxArea 设得太大把缺陷内部的正常灰度区域当成“小孔”填充了。比如一个圆形压伤区面积 500 像素中央有块 60 像素的未损伤区域maxArea50 时它会保留设为 100 时就被填掉了。解决把 maxArea 的默认值改小或者观察填充前后差分图的像素变化量超过一定比例就说明填多了。建议用 imabsdiff 比较填充前后的图像统计变化像素数如果变化面积超过所有缺陷总面积的 20%就调低 maxArea。5.4 边界跟踪起点和方向选错导致后续全乱现象BoundaryTrack 输出的边界点序列出现跳变明明是一个圆边界序列却在某个位置突跳导致圆度计算异常。原因bwtraceboundary 对起点非常敏感。如果起点刚好落在两条边缘交叉处跟踪会走到错误分支如果搜索方向设成 Clockwise后续角度换算也会出问题。解决起点不要硬编码先用圆心和半径计算大致位置再在附近做一个局部窗口搜索找梯度最大的像素作为起点。推荐做法是取圆心正上方 (centers(1), centers(2)-radii) 附近 3x3 邻域内的边缘点这样最稳定。方向统一用 CounterClockwise。5.5 缺陷面积阈值一刀切误判现象同样的代码上午跑没问题下午跑误判率飙升小噪点被当成缺陷或者真缺陷被滤掉。原因光照变化导致边缘检测结果波动缺陷面积随之变化固定阈值失去适应性。这是所有固定阈值方案的常见问题。解决把面积阈值改成相对值——相对于圆的总面积。比如缺陷面积小于圆面积的 0.5% 就忽略大于 2% 就报警。这样光照变化导致圆面积整体变化时比例相对稳定。和图像处理的其他环节一样这里有硬件条件的成分但能把误判率从 20% 压到 3% 以内。6. 进阶用法把检测结果变成可量化的报告参数跑通基础流程后下一步就是让检测结果从“能看图”变成“能判断”。这一章分享两个我常用的进阶技巧。第一个技巧是输出缺陷的极坐标位置。缺陷质心坐标是直角坐标系的但产线上更关心“缺陷在圆周的哪个角度、离圆心多远”。用 atan2 和 sqrt 简单换算即可% 将缺陷质心转换为极坐标 dx cents(:,1) - centers(1); dy cents(:,2) - centers(2); angle atan2d(dy, dx); % 角度-180到180 radius sqrt(dx.^2 dy.^2); % 到圆心的距离角度映射到 0360 度并统一把 12 点钟方向作为 0 度基准这样产线工人可以直接按角度找缺陷位置。半径值则能区分“边缘缺陷”和“内部缺陷”边缘缺陷要结合圆度误差一起判定内部缺陷则看灰度偏差。第二个技巧是把关键参数提取到配置文件里实现自动扫描。比如 Sensitivity 和 minArea 这两个参数可以用一个双层循环自动寻优% 参数扫描Sensitivity 从 0.80 到 0.90 步进 0.02 for sens 0.80:0.02:0.90 for minArea 50:10:150 [centers, radii] imfindcircles(gray, [30 80], ... Sensitivity, sens); defect extractDefect(gray, centers, radii); [labelMap, n] bwlabel(defect, 8); stats regionprops(labelMap, Area); keep sum([stats.Area] minArea); fprintf(sens%.2f minArea%d detected%d\n, ... sens, minArea, keep); end end跑完扫描后你已经能大致摸透这套程序的性能边界包括霍夫变换在低对比度下的检出极限以及模型在数据分布漂移时的鲁棒性水平。如果想进一步自动化还可以把扫描结果输出成 CSV用可视化工具画参数响应面直观看出哪个区域参数组合最稳定。从那以后我每次接手新的端面检测项目都强制自己先花半小时把这套扫描跑一遍再调别的参数省下来的调试时间远超过这半小时希望帮到你。本文还有配套的精品资源点击获取