ARTICLE DETAIL

建站实战干货

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

MATLAB图形识别实战:基于几何特征的形状分类方法

2026/9/8 9:51:39 拓冰建站 浏览量
MATLAB图形识别实战:基于几何特征的形状分类方法 简介这是一套面向图像处理与模式识别初学者的MATLAB实现资料围绕圆、正方形、矩形三类基本几何图形的检测与分类集中提供了对应的识别算法源码与可运行工程文件适合课程设计、毕业设计或竞赛备赛阶段对照学习。压缩包共包含218个文件以bmp格式测试图像、h头文件与cpp源码为核心辅以ico、rc等界面资源及少量说明文档整体大小约1.07MB目录结构清楚易于按模块查阅。其中bmp样本涵盖不同尺寸与背景情况便于验证算法在实际输入上的鲁棒性。已有2660人学习浏览说明该资料在同类图形识别任务中具有较高的参考热度。读者可从中获得完整的算法框架、样本图像与工程组织方式理解图形特征提取、形状分类判别及结果验证的具体实现流程对于快速搭建自己的识别实验或扩展其他几何图形识别方案均有帮助。 先说个场景有个同学在课程设计里拿到一个任务给一张含有圆、正方形、矩形的图片要求用MATLAB自动区分出每一类图形并用不同颜色标记出来。乍一听好像挺简单但真正下手做的时候会发现什么形状算圆旋转后的正方形还是正方形吗光照不均匀导致轮廓断开了怎么办这些问题的背后就是图形模式识别里最基础也最关键的一环——形状特征的提取与判断。这篇文章我打算把从预处理到特征计算再到分类判别的完整流程拆开讲清楚代码直接可用原理也会解释到位适合正在做MATLAB图像处理作业、入门计算机视觉或者想搞明白“机器是怎么认图形”的人参考。我最早接触这个题目是在帮人调一段大作业代码的时候当时网上能搜到的版本几乎都是直接调regionprops量几个参数然后硬编码阈值看起来能跑换一张图就歇菜。后来我重新把整个识别流程捋了一遍才发现关键在于搞清楚每个特征到底在度量什么、为什么这个特征能把圆和矩形分开、什么情况下会失效。这篇文章就按这个逻辑来讲。1. 识别思路为什么不用“看起来像”而是用几何特征1.1 一个容易被忽略的前提机器看到的只是像素矩阵首先得想明白一件事MATLAB读入一张图片之后它看到的不是“一个圆”或者“一个正方形”而是一个巨大的数值矩阵。每个像素点的灰度值、RGB值对它来说只是数字。所以所谓的图形模式识别本质上就是通过设计某些数学公式把这些像素数字压缩成若干个有语义的特征值再用特征值的区间来判断类别。我见过很多新手第一反应是做模板匹配——提前存好三张标准图然后逐个像素对比。这种做法在图像完全不变、不旋转、不缩放的情况下勉强可行但只要你把图片旋转45度或者把圆缩小一半匹配度立刻崩盘。原因很简单模板匹配依赖的是像素位置的一一对应而真实场景中的图形往往存在平移、旋转、缩放变化。1.2 三种常见方案对比对于“圆、正方形、矩形”这样规则且差异明显的几何图形主流的做法大体分三类基于边缘的几何特征法提取轮廓后计算圆度、矩形度、宽高比等指标通过组合阈值判断。基于不变矩的方法使用Hu矩的7个不变矩作为特征向量对平移、旋转、缩放不敏感适合复杂形状。基于深度学习的方法训练一个简单的CNN分类器效果上限高但需要数据集和算力对课程作业来说往往杀鸡用牛刀。我最终选择的是第一类方案。原因有三个一是可解释性强每个判断依据都能直观对应到几何性质二是代码量少不依赖额外工具箱三是在图形规则、背景干净的场景下它的准确率已经足够高而且调整阈值的逻辑很清楚。Hu矩虽然对旋转更加鲁棒但这个场景下几何特征法配合主轴长度判断已经能解决旋转问题没必要把问题复杂化。2. 图像预处理与轮廓提取是识别成败的分水岭2.1 灰度化与二值化把问题简化到极致拿到一张RGB图片第一步永远是把颜色信息去掉。因为我们要识别的是形状不是颜色——红色的圆和蓝色的圆应该是同一个类别。用rgb2gray转成灰度图后再通过imbinarize做二值化让目标区域变成白色前景、背景变成黑色。二值化的核心是阈值选择。最简单的做法是指定一个固定阈值比如imbinarize(gray, 0.5)但这种方法对光照变化极其敏感同一个物体亮一点可能整个变成白色暗一点可能被当成背景。更可靠的做法是Otsu方法大津法MATLAB里直接调用imbinarize(gray)时默认就使用Otsu阈值。它是自动计算一个能把前景和背景类间方差最大化的阈值实际使用中适应性比固定阈值好很多。如果图片背景本身就很复杂比如有纹理或者阴影Otsu也可能不给力。这时候可以先做imgaussfilt高斯滤波平滑一下或者用imbinarize(gray, adaptive)做局部自适应阈值。对于课程设计里那种白纸上的黑色图形imgaussfilt加imbinarize就足够稳了。2.2 形态学操作清除噪点与断点的小技巧二值化之后图像上常常会有两类问题一类是背景里散落的小噪点另一类是图形内部因为反光或者边缘模糊产生的孔洞。噪点会在后续连通域分析时被当成伪目标孔洞则会让周长变大、面积变小直接拉低圆度指标。我的处理顺序是这样先用bwareaopen去掉面积小于某个阈值的连通区域比如bwareaopen(bw, 100)会把小于100像素的杂点全部清掉。然后对前景做一次形态学闭运算imclose(bw, strel(disk, 5))闭运算擅长填补小孔洞和连接断开的小缝隙而且对整体形状的改变非常小。最后如果有需要再用imfill(bw, holes)把图形内部的孔洞填满。这一步做完后面的轮廓提取质量会明显提升。2.3 提取轮廓两种方式edge与bwboundaries边缘检测和连通域边界提取是两条不同的路。edge函数基于梯度变化找边缘点输出的是二值化的边缘图适合做细线条特征分析。而bwboundaries直接以连通域为对象输出每个区域的边界像素坐标序列更贴合“按目标物体来分析”的需求。在形状识别这个任务里我建议用bwboundaries而不是edge。原因很实际edge得到的边缘往往是断裂的、粗细不均的曲线后面不管是算周长还是拟合形状都别扭而bwboundaries返回的是闭合的外轮廓坐标天然成环直接可以用来计算各种几何特征。如果你在处理多个目标还能通过第二个输出参数拿到每个连通域的标记编号方便循环处理。3. 形状判别圆度、矩形度与宽高比的计算逻辑3.1 regionprops一个函数拿到几乎所有关键参数MATLAB图像处理工具箱里regionprops是个宝藏函数它能一次性测量连通域的各种属性。针对圆、正方形、矩形识别这个任务核心关注四个量Area区域实际像素面积。Perimeter区域边界周长基于边界像素计算。BoundingBox包含该区域的最小轴对齐矩形框格式为[x, y, width, height]。MajorAxisLength和MinorAxisLength与区域具有相同标准二阶中心矩的椭圆的长轴和短轴长度。为什么选这四个量因为它们的组合正好能唯一区分三类规则图形。面积和周长配合可以算出圆度外接框宽高比可以区分正方形与矩形长短轴则能解决旋转场景下的正方形误判问题后面详细说。3.2 圆形判别用圆度指标而不是直接量半径定义圆度的经典公式是circularity 4 * pi * Area / Perimeter^2这个公式的原理是在所有封闭图形中圆在面积相同的情况下周长最短。因此把圆形的圆度值归一化到1其他任何形状的圆度值都会小于1。具体来说理想圆的圆度等于1理想正方形的圆度约为0.785而矩形越扁长圆度值越小。所以判断圆形的规则可以这样定circularity 0.85就认为它是圆。这个阈值留了余量因为实际图像中像素离散化会让圆的圆度略微下降一般干净图像中圆的圆度实测在0.90到0.95之间。如果你发现圆的识别率低可以去数一下二值化后边缘有没有锯齿状缺口那通常是预处理不到位而不是阈值设错了。3.3 正方形与矩形宽高比加矩形度双保险圆被排除之后剩下的候选就在正方形和矩形之间二选一。最直觉的特征是外接框的长宽比aspect_ratio width / height % 或者反过来取大于1的那个比小的那个理想正方形的宽高比等于1矩形的宽高比明显偏离1。但这里有个隐藏的坑如果正方形在图片中是旋转过的regionprops返回的BoundingBox是轴对齐的外接框它会把旋转后的正方形框成一个比实际更大的长方形宽高比不再是1。这就是为什么只用宽高比判断会在旋转问题上翻车。更稳的办法是使用MajorAxisLength与MinorAxisLength的比值。这两个量是基于二阶中心矩得到的等效椭圆长短轴它的特点是正方形无论如何旋转等效椭圆的长短轴之比始终接近1这是因为正方形的转动惯量在平面内是各向同性的。而矩形的长短轴之比则会随边长差异增大而增大。为了更保险还可以引入矩形度rectangularity Area / (bbox_width * bbox_height)矩形度衡量的是区域面积占其外接矩形面积的比例。理想矩形这个值等于1圆大约为0.785。它的主要作用是排除那种“看起来像矩形但边缘有缺口”的噪声干扰。正方形的矩形度应当接近1如果低于0.9基本可以判断是有凹角或边缘残缺需要回到预处理阶段补洞。综合下来我的判别顺序是先用圆度筛出圆再用长短轴比区分正方形与矩形。流程上是一个级联判断而不是一次性把所有阈值并列判断这样每一步只需关心一个指标逻辑清晰调参也更容易。4. 完整MATLAB代码实现与逐步解读4.1 主流程代码下面这段代码我按“读图-预处理-连通域分析-特征判别-可视化”的顺序组织可以直接复制运行。示例假设图片中只有这三种图形且背景相对干净。clear; close all; clc; % 1. 读入图像并转为灰度 img imread(shapes.png); gray rgb2gray(img); % 2. 预处理高斯滤波平滑Otsu二值化去噪闭运算补洞 smooth imgaussfilt(gray, 2); bw imbinarize(smooth); % Otsu自动阈值 if mean(bw(:)) 0.5 % 若前景是黑色则反转 bw ~bw; end bw bwareaopen(bw, 100); % 去除小面积噪点 bw imclose(bw, strel(disk, 5)); % 闭合边缘小缺口 bw imfill(bw, holes); % 填充图形内部孔洞 % 3. 连通域标记与属性测量 labeled bwlabel(bw); stats regionprops(labeled, Area, Perimeter, ... BoundingBox, MajorAxisLength, ... MinorAxisLength, Centroid); % 4. 按几何特征逐类判别 figure; imshow(img); hold on; for k 1:length(stats) area stats(k).Area; perim stats(k).Perimeter; major stats(k).MajorAxisLength; minor stats(k).MinorAxisLength; % 圆度理想圆1正方形约0.785 circularity 4 * pi * area / (perim^2); % 长短轴比理想正方形1矩形明显大于1长边/短边 axisRatio major / minor; if circularity 0.85 label Circle; elseif abs(axisRatio - 1) 0.1 label Square; else label Rectangle; end % 画边界框和标签 bbox stats(k).BoundingBox; rectangle(Position, bbox, EdgeColor, r, LineWidth, 2); text(bbox(1), bbox(2)-5, label, Color, blue, ... FontSize, 14, FontWeight, bold); end hold off;4.2 关键代码行为什么要这么写先看二值化之后的if mean(bw(:)) 0.5这一段。二值化结果可能有两种情况白底黑图或者白图黑底。如果不做统一后面bwareaopen会把白色背景当成巨大前景区域导致regionprops算出一堆无效目标。判断前景是黑是白可以看大部分像素是0还是1因为正常情况下图形区域占画面比例总是小于背景的。bwlabel的作用是把二值图中每一个独立的连通域分配一个编号从1到N。regionprops配合这个编号就能分别统计每个目标的属性。如果你要识别的是图片里多个同类别图形这个结构天然支持——循环遍历stats即可每个元素对应一个目标。矩形框标注时我用的是BoundingBox注意里面坐标含义是[左上角x, 左上角y, 宽, 高]。在imshow显示的图像坐标系中y轴向下为正但这个坐标系下画rectangle不需要额外翻转直接使用即可。4.3 当图片里有多个同类目标时的扩展上面的代码其实已经天然支持多目标识别因为regionprops返回的是一个结构体数组循环就是为多个目标准备的。如果图片中出现了第五种形状比如三角形当前代码会把不满足圆条件、也不满足正方形条件的都归为矩形。这时候你需要在级联判断中增加一个分支比如三角形的矩形度远低于正方形且长短轴比也不固定可以加入“凸度”或“三角形度”指标来排除。另一种常见需求是输出识别结果统计表。可以用struct2table(stats)把属性转成表格再新增一列类别最后用writetable存成CSV。我在做批量图片处理时经常会加这样一段输出便于离线分析哪些图片识别失败、失败原因是什么。5. 实测中踩过的坑与解决办法5.1 光照不均匀导致轮廓断裂第一次拿真实摄像头拍的图形图片测试时圆形的圆度只有0.7左右怎么调阈值都识别不出来。后来把二值化后的图像显示出来才发现图形的下半部分和背景糊在一起轮廓是断裂的。原因是光照不均匀Otsu虽然自适应但处理的是全局阈值无法照顾到局部亮暗差异。解决方法有两个方向一是打光或者拍照时尽量保证区域亮度均匀这在实验室环境下最容易做到二是在算法上用imbinarize(gray, adaptive)替代全局阈值让每个像素根据邻域亮度动态决定阈值。代价是计算量变大但效果立竿见影。如果采集图像的光照条件无法控制建议直接在代码里默认用自适应方法。5.2 正方形被旋转后宽高比失效正方形旋转45度后轴对齐外接框的宽高比大约是1.414如果只用BoundingBox的宽高比判断很容易把旋转正方形误判为矩形。这个坑我一开始就踩了后来改用等效椭圆长短轴比才解决。你可以做一个简单实验画一个正方形旋转不同角度输出MajorAxisLength / MinorAxisLength会发现它始终稳定在1附近或略大于1受像素离散化影响。这就是为什么长轴/短轴比是对旋转不敏感的正方形判据。如果用的MATLAB版本较老regionprops不支持MajorAxisLength属性可以退而求其次用BoundingBox的宽高比加面积占比联合判断。但需要注意旋转问题判断阈值要放宽比如aspect_ratio 1.3才认为是正方形否则误判率会明显上升。5.3 边缘锯齿和内部孔洞对周长的影响周长在圆度公式里是以平方形式出现的所以周长对边缘锯齿特别敏感。同样是10×10像素的圆连续光滑的边缘和带锯齿边缘的周长可能差出20%圆度值一下子就跌破0.85。这是像素离散化的固有误差无法完全消除只能通过预处理缓解。我常用的手段是闭运算的半径稍微开大一点比如用disk, 7并且在计算周长前确保bwboundaries提取的边界是单像素连续的。孔洞的影响方向相反——面积减少周长基本不变圆度被拉低。如果你发现某个区域的填充结果出现异常可以检查imfill是否因为连通域结构复杂而漏填必要时配合imclose先闭合前景区域再填充。5.4 背景中其他物体误识别为目标课程设计给的图通常是干净的但如果你自己拍照片背景里的笔、桌面纹理、阴影都可能成为独立的连通域。bwareaopen只能过滤小面积目标处理不了和图形一样大的杂物。我的经验是给识别目标加一个面积范围约束先统计所有连通域的面积分布再设定一个合理区间只有面积落在区间内的目标才参与后续判别。这个方法在批处理多张图片时特别有用可以避免每一张图都去手动调参数。6. 从规则识别到更复杂场景的扩展思考图形模式识别做到这里其实只完成了一半。规则的几何特征方法在“图形规则、背景干净”的前提假设下表现良好但一旦遇到手绘的不规则圆、被遮挡的矩形、或者透视畸变的目标这套阈值逻辑很快就会到达瓶颈。我自己的看法是像圆、正方形、矩形这种强规则形状几何特征法永远是最值得首选的方案因为它轻量、可控、可解释但如果你要处理的是自然场景中的复杂图形识别那就要考虑两条进阶路线。一条是改用Hu矩构成特征向量配合决策树或SVM分类器这样做的好处是特征不局限于单个指标对轻微形变的容忍度更高另一条是直接用深度学习比如用MATLAB的Deep Learning Toolbox搭建一个几层的小型卷积神经网络把图形图片缩放到统一尺寸后输入网络训练。CNN的好处是特征自动学习不需要人工设计阈值但代价是需要准备足够多的标注样本训练时间也长一些对于一次性任务来说性价比不高。我实际在做项目时有一个习惯先用几何特征法跑通基线记录哪些样本识别失败再看失败样本主要集中在什么原因上。如果是因为图形本身不规则就考虑引入机器学习分类器如果只是光照和噪声问题就继续打磨预处理。绝大多数情况下预处理改进带来的收益远远大于更换分类算法。有一点值得单独提醒无论使用哪种方法验证集一定要覆盖旋转和缩放这两种情况。很多代码在原始图片上跑得完美一旋转就崩本质上是特征没有选对。等效椭圆长短轴比就是我为解决旋转问题留下的后手这个思路在处理其他规则形状时也完全适用比如三角形的判别可以加入凸度特征星形可以加凹角计数。动手跑通这段代码之后建议你刻意做两个小实验一是把相同图形放在同一张图的不同位置观察识别结果是否一致二是把图片旋转若干角度再测试。这两个实验能帮你直观感受到哪些特征稳定、哪些特征脆弱也比单纯调阈值更能加深对图形模式识别的理解。本文还有配套的精品资源点击获取