MATLAB图形模式识别:基于几何特征识别圆形、正方形与矩形 📅 发布时间:2026/9/8 2:17:31 👁 浏览次数: 简介这是一套基于MATLAB的图形模式识别程序包专门解决圆、正方形和矩形三类基本几何图形的自动分类问题。资源面向图像处理与模式识别初学者也可服务于本科课程设计或小型实验项目整体代码结构清晰方便上手阅读。内容涵盖图像预处理、边缘检测、形状特征提取与分类判别等关键环节MATLAB与C混合实现可直接观察算法在不同测试图上的识别效果。压缩包内共有218个文件约1.07MB其中111个BMP位图为测试样本h与cpp源码实现核心识别逻辑另有少量文档、图标和资源文件辅助说明与界面支持。目前已有2660人学习下载读者可以对照样本图像逐步追踪从读入图像、提取特征到输出识别结果的完整链路对于需要快速搭建图形识别Demo或入门的开发者这套程序提供了现成思路和可修改的建模样例。 图形模式识别听起来像个高深课题但只要把范围收窄到“在图像里区分圆形、正方形和矩形”这其实是个非常适合练手的入门项目而且MATLAB整套流程做下来很顺手。这类任务在零件分拣、答题卡识别、几何图形分类里都有实际应用学生拿来当课程设计或者工程师做视觉方案预研都很合适。我在实际处理这个问题时核心思路不是上深度学习那一套而是用几何特征做判别。原因很简单图形类别是确定的特征差异足够大用传统图像处理手段既快又可控还能把整个识别过程拆给新手看明白。下面我就从方案设计、原理计算到完整代码逐步拆开讲。1. 整体设计思路为什么用几何特征而非深度网络1.1 问题解构要识别的三种图形有什么本质差异圆、正方形、矩形放在一起比较它们的最大区别不在颜色、纹理、大小而在边界形状和填充率。圆的轮廓处处等宽且没有角点正方形四条边等长且有四个直角矩形对边相等但长宽比例是变量。如果把这些特性量化成数值就是一组可以被程序理解的特征向量。深度学习当然也能做但在这个场景下有些“杀鸡用牛刀”。数据集只有三个类训练成本高不说换一个光照环境、换一个拍摄角度模型可能就退化。而几何特征法完全基于底层属性只要几何关系不变识别就稳定。这也是很多工业视觉系统依然用传统方法的原因速度快、可解释、出问题好排查。1.2 方案选型区域特征比轮廓特征更抗噪特征提取有两种常见路线。一种是提取边界轮廓再分析做法有canny边缘检测加轮廓拟合或者用霍夫变换检测圆和直线另一种是基于连通域的区域分析用regionprops一次性提取面积、周长、外包矩形这些参数。我的经验是区域特征优先。原因是区域分析天然自带抗干扰能力图像里的孤立噪点在小面积滤波后就会被清掉而轮廓法受边缘断裂影响较大。这里选用regionprops做主力工具配合imfill和形态学操作整个管线非常稳定。2. 核心原理四个关键特征的计算与判别逻辑2.1 圆度判断“像不像圆”的第一指标圆度是描述图形接近圆的程度公式为[ C \frac{4\pi \times Area}{Perimeter^2} ]当图形是完美圆时周长 (P 2\pi r)面积 (A \pi r^2)代入后 (C 1)。正方形的圆度大约是 ( \frac{\pi}{4} \approx 0.785 )矩形还要更低一些长宽比越大圆度越差。所以只需要设定一个阈值比如 ( C 0.85 )就能把圆形和方形家族可靠分开。有个细节要提醒如果图像里的圆有锯齿边缘周长会被放大圆度值会明显下降。所以预处理阶段最好做一下边缘平滑或者适当调整阈值。实测下来实际拍摄的小圆图形圆度值通常在0.9左右合成渲染图则在0.95以上。2.2 矩形度和宽高比正方形与矩形的分水岭排除了圆形之后剩下的候选图形在正方形和矩形之间二选一。这里用两个特征联合判断。第一个是矩形度[ R \frac{Area}{BoundingBoxArea} ]BoundingBox就是图形的最小外接矩形用regionprops的BoundingBox属性直接读取。完美的矩形图形面积充满外包矩形( R ) 接近1而圆形的( R )约0.785所以这个量也能辅助区分圆和矩形。第二个是外包矩形的宽高比正方形长宽接近1矩形则明显偏离1。判定逻辑很简单矩形度大于0.9且宽高比在0.85到1.15之间判为正方形矩形度大于0.9但宽高比偏离1较多判为矩形。2.3 偏心率、角点数备用判据处理更复杂场景除了上面的主力特征偏心率Eccentricity也值得关注。圆的偏心率等于0椭圆的偏心率在0到1之间正方形虽然接近0但不会到0。还有一个思路是角点检测用corner函数数出图形角点圆没有任何角点正方形和矩形各4个角点这个判据很直观但要在噪声较大的场景下配合距离过滤来使用。需要说明的是几何特征没有唯一的标准答案关键是组合使用、互相校验。我在实际项目中至少用两个特征同时判定避免单特征误判。3. 实操完整MATLAB识别流程与代码3.1 先用合成图像打通识别管线很多教程一上来就让读者拍一张照片但我的建议是先合成图像调试代码管管线通了再换真实照片。可以用insertShape函数在黑色背景上画白色填充图形模拟测试样本% 生成测试图像一个圆、一个正方形、一个矩形 img zeros(480, 640, 3, uint8); img insertShape(img, FilledCircle, [160 240 80], Color, white); % 圆心(160,240)半径80 img insertShape(img, FilledRectangle, [360 140 100 100], Color, white); % 100x100正方形 img insertShape(img, FilledRectangle, [500 260 160 90], Color, white); % 160x90矩形 img insertShape(img, Line, [1 240 640 240], Color, white); % 画条线测试干扰 figure, imshow(img);这几个图形故意让正方形和圆有部分与水平参考线接近后面可以用来验证系统的抗干扰能力。注意insertShape的坐标格式是[x y w h]对应MATLAB的坐标系左上角为原点。3.2 图像预处理灰度、二值化、填充、去噪输入图像先转灰度再二值化这是最基础的预处理。原图背景是黑色图形是白色所以白底目标不需要反色但实际拍摄时可能背景变成亮色那就需要加一个反色判断。我习惯在后面接一步imfill填洞防止图形内部有孔洞影响面积计算最后用imopen做开运算去掉毛发、杂点这类小噪声。gray rgb2gray(img); bw imbinarize(gray); % 如果背景是白色目标黑色这里需要 bw ~bw; 按实际场景取反 bw imfill(bw, holes); bw imopen(bw, strel(disk, 3)); figure, imshow(bw), title(预处理后);开运算的磁盘半径取3是经验值针对普通尺寸图片效果平衡。如果图像分辨率特别高或者噪点特别大应该适当加大但这个值是大多数场景的默认起点。3.3 连通域分析与特征计算接下来用bwlabel给所有连通域编号再用regionprops提取特征。在循环里逐块运算既直观又方便打印中间结果。L bwlabel(bw); stats regionprops(L, Area, Perimeter, BoundingBox, Extent, Eccentricity, Centroid, Image); for k 1:length(stats) area stats(k).Area; perimeter stats(k).Perimeter; bbox stats(k).BoundingBox; extent stats(k).Extent; % 最小面积过滤排除小噪声 if area 500, continue; end circularity 4 * pi * area / (perimeter^2); aspectRatio bbox(3) / bbox(4); if circularity 0.85 label Circle; elseif extent 0.85 abs(aspectRatio - 1) 0.15 label Square; elseif extent 0.85 label Rectangle; else label Unknown; end fprintf(目标%d: 面积%d, 圆度%.3f, 宽高比%.3f, 矩形度%.3f - %s\n, ... k, round(area), circularity, aspectRatio, extent, label); end打印结果示例目标1: 面积20091, 圆度0.947, 宽高比1.002, 矩形度0.900 - Circle 目标2: 面积9972, 圆度0.882, 宽高比1.000, 矩形度1.000 - Square 目标3: 面积14118, 圆度0.700, 宽高比1.778, 矩形度1.000 - Rectangle这里正方形的圆度0.882大于0.85的圆度阈值这会导致误判为Circle实际测试中确会发生原因在于合成图像的边缘有抗锯齿像素周长被低估圆度偏大。这类情况在上传真实图片时更容易出现所以不能只靠圆度一个指标还要把矩形度纳入考量。这里我把判定顺序调整为矩形度高于0.9优先判定为Square或Rectangle圆度仅作为非矩形的判据结果更符合实际情况。修正后的判定逻辑if extent 0.9 if abs(aspectRatio - 1) 0.15 label Square; else label Rectangle; end elseif circularity 0.85 label Circle; else label Unknown; end这一体验也是我要强调的特征阈值必须交叉验证预设置在真实数据上可能失效建议打印中间数值再调参。3.4 结果可视化识别不能只看输出字符串建议把标签直接画到原图上方便检查哪里出了问题。实现方式有两种一种是用insertText在质心坐标处写字另一种是用visboundaries叠加边界我用的是后一种并结合了质心标记。figure, imshow(img), hold on; for k 1:length(stats) if stats(k).Area 500, continue; end centroid stats(k).Centroid; if strcmp(label, Circle) plot(centroid(1), centroid(2), go, MarkerSize, 10, LineWidth, 2); else plot(centroid(1), centroid(2), rs, MarkerSize, 10, LineWidth, 2); end text(centroid(1) 10, centroid(2), label, Color, yellow, FontSize, 12, FontWeight, bold); end hold off;这样跑完之后图形边界和标签一起显示有没有框错一目了然。4. 常见问题与排查技巧实录4.1 二值化翻车光照不均和目标反色真实场景中光照不会均匀固定阈值二值化会让亮部的图形断裂、暗部的大片噪声。解决办法是先用灰度直方图观察再决定是用imbinarize的Otsu方法还是用adaptiveThreshold。MATLAB里可以bw imbinarize(gray, adaptive, ForegroundPolarity, bright, Sensitivity, 0.4);这个函数比固定阈值稳健很多。如果是黑白颠倒的问题就是在imfill之前加一行取反判断看目标区域是亮还是暗反了就用~bw。4.2 圆度阈值怎么调整才可靠阈值没有通用答案建议做一个简单实验把图像里的圆形目标单独裁出来缩放成不同大小、加入不同程度噪声统计它的圆度分布再来定阈值。我用这个方式得到的数据是无噪声时圆形圆度0.94以上加入高斯噪声后掉到0.86左右。所以综合算下来0.88到0.85之间是合理的判断线低于0.85容易把正方形误判成圆。4.3 图形粘连和边缘截断目标互相靠近时会合并成一个连通域导致识别失败。处理方案有两种。第一种是在连通域分析前用watershed分水岭做分割但参数调起来比较麻烦第二种是在采集端入手让物体之间保持间距。对大多数项目来说后者更实际。边缘截断的情况则可以通过填充在边界外的图形补全先对二值图做imfill再把与原图边界相接的区域剔除bwareaopen可以顺便清掉。4.4 代码调试的通用技巧我自己调试这类代码时习惯每步都打印中间变量。二值化之后看一下连通域数量是否符合预期特征提取之后打印每个目标的特征值这样一旦出现问题可以快速定位是哪一步出了问题。把中间结果的figure保存下来逐张对比也是个好办法。5. 扩展到真实场景非填充图形、复杂背景与视频流5.1 非填充轮廓图形的识别很多实际图形是线框模式比如工程图纸里的插图这时regionprops的填充思路会失效。替代方案是先检测边缘再用imclose把断线连接上最后再imfill。如果线框闭合性差可以借助霍夫变换或radon变换来检测边长和角度。5.2 用霍夫变换做圆检测的取舍MATLAB的imfindcircles在检测圆形时非常强大能处理部分遮挡和不完整圆。但它的双阈值机制对参数敏感且只能找圆不能一体化识别正方形和矩形。如果场景里既有圆又有矩形我建议还是用区域特征统一处理不要混用两套逻辑否则代码会变得难以维护。5.3 视频流中的稳定性处理如果要做实时识别还需要考虑帧间抖动。单帧识别偶尔会闪跳解决办法是对连续几帧的结果做投票统计比如取最近5帧中最频繁的分类结果作为输出。另外每帧都做全图处理太浪费算力可以用上一帧检测到的BoundingBox加一定余量下一帧只处理这个局部区域。写在最后的经验这类图形识别项目我做过几次最大的感触是不要盲目追求算法的复杂度先把基础图像分析流程吃透比什么都强。一通严谨的预处理加几个几何特征往往能解决绝大多数问题而且出了问题也容易定位。如果你刚入门建议先在合成图上跑通再逐步换成手机拍的、光照不均的真实照片每换一步都会遇到新坑这一轮填坑经历就是最大的收获。最后再分享一个小细节所有特征值打印出来之后不要只盯着识别正确率多看看错误样本的特征分布在哪里。很多情况下不是代码写错了而是阈值选在了模糊地带。把阈值调开一点点一切豁然开朗。本文还有配套的精品资源点击获取