MATLAB Hough变换例程详解:直线检测、圆检测与文档倾斜校正
简介这套MATLAB例程聚焦Hough变换在图像处理中的典型应用尤其针对圆形检测与圆心定位适合正在学习图像处理、计算机视觉或MATLAB工具箱的初学者与开发者。压缩包共10个文件涵盖4个m源代码脚本、4张tif测试图像以及2个fig图形文件资源总大小3.07MB结构清晰便于直接运行与对照学习。已有145人学习下载。代码以main为主入口演示了图像预处理、Hough变换、峰值提取到圆心坐标恢复的完整流程测试图像包含单个圆、多个圆等不同场景可供观察算法在不同输入下的表现。通过该例程学习者既能掌握hough、houghpeaks等核心函数的用法也能理解亚像素精度圆心坐标的实现思路是一份兼顾原理与实战的入门级参考。1. hough.rar 这种 MATLAB 例程包到底在帮你解决什么问题网上流传下来的 hough.rar_matlab例程 这类压缩包解压后通常是一个脚本加几张测试图脚本里把hough、houghpeaks、houghlines三件套串起来输出一张画着红线的结果图。Hough 变换在 MATLAB 图像处理任务里的地位是「找直线和圆的参数」的默认答案倾斜文档校正要看文字行角度车道线检测要拟合边缘直线棋盘格标定要定位网格线表盘读数要先找到圆心。这些东西的共同点是从大量噪声像素里提取出少数几个几何参数而 Hough 变换用投票的方式把这个问题变成找累加器峰值。这篇博文就从三件套的参数关系讲起给一份可直接运行的 MATLAB 直线检测例程再扩展到圆检测的参数调优最后用一个 deskew 函数收尾。适合有 MATLAB 基础、想在现成例程上二次开发的工程师也适合刚接触 MATLAB 图像处理但被阈值和坐标系绕晕的新手。2. Hough 变换的 MATLAB 三件套hough、houghpeaks、houghlines 怎么配合2.1 参数空间投票是怎么回事Hough 变换的核心思想是点线对偶。图像空间里的一个像素点(x0, y0)对应参数空间rho x0*cos(theta) y0*sin(theta)里的一条正弦曲线。图像上一条直线上的所有像素点它们对应的正弦曲线都会交于同一个(rho, theta)点这个交点累积的投票数就是这条直线在图像里的可信度。所以整个检测流程被拆成两个阶段第一阶段把所有边缘像素投进累加器第二阶段在累加器里找局部峰值。峰值对应的rho是原点到直线的垂线距离theta是这条垂线与 x 轴的夹角。MATLAB 的hough函数返回的H就是累加器矩阵theta和rho是两把坐标尺子。需要注意MATLAB 的hough输入必须是二值边缘图而不是灰度图或彩色图。如果直接把imread的结果塞进去累加器会被大量非目标像素淹没峰值完全不突出。这也是很多例程包在代码开头必定先写一行edge的原因。2.2 先看一个最小例子竖直边缘线的累加器长什么样img zeros(200, 200); img(50:150, 50) 1; % 一条竖直边缘线x50, y从50到150 [H, theta, rho] hough(img); imshow(H, [], XData, theta, YData, rho, InitialMagnification, fit); xlabel(theta (deg)); ylabel(rho (pixels));这段代码里img只在(501:150, 50)位置有非零像素。hough遍历所有非零像素把它代入参数空间画一条正弦曲线最后累加成H。imshow里XData和YData的作用是把累加器的下标映射成真实的theta和rho坐标图像上会看到一个明显的亮斑位置大约在theta0、rho50处。这里的H是二维矩阵行数等于rho网格数量列数等于theta网格数量。hough默认theta范围是-90:89度每度一列rho范围由图像对角线长度决定通常是diagLength的负一半到正一半。竖直边缘线峰值落在theta0水平边缘线则会落在接近±90的边界上这个细节在后面做倾斜校正时会直接用到。2.3 三件套的参数关系一共 8 个参数需要提前决定实际例程里不会直接拿hough的输出画图而是继续交给houghpeaks找候选峰值再用houghlines把峰值还原成线段端点。三个函数的关键参数如下表。函数参数默认值作用houghThetaResolution1度theta 网格步长越小累加器越宽houghRhoResolution1像素rho 网格步长越小对直线位置越敏感houghpeaksNumPeaks1最多找多少个局部峰值houghpeaksThreshold0.5 * max(H(:))峰值最小票数低于此值的峰值被忽略houghpeaksNHoodSizesize(H)/25 取奇峰值周围抑制邻域大小防止同一个直线被重复检出houghlinesFillGap20像素同一直线上断点之间的最大空隙超过则断开houghlinesMinLength40像素合并后线段的最小长度太短的丢弃这几个参数是例程里最常改的也是调参时最容易互相牵连的。Threshold设高了会漏掉弱直线设低了会把噪声点也当成直线FillGap设大了会把本不相干的两条线段强行接成一条设小了车道线这类有断痕的直线会被拆成很多段。我一般会先把NumPeaks设得大一些比如 50 或 100然后靠Threshold和NHoodSize来控制质量而不是一上来就限制数量。3. 用 MATLAB 例程跑通 Hough 直线检测完整可复现代码与参数对照3.1 为什么例程的输入总是 edge 而不是原图Hough 投票是对每个非零像素做正弦曲线累加。如果输入是灰度图几乎所有像素都会参与投票导致累加器里每个位置都有票数峰值不明显。更糟的是MATLABhough内部会对非零像素遍历灰度图会让计算量成倍增加。常见做法是先用 Canny 边缘检测得到二值图再做 Hough 变换。Canny 的两个阈值控制边缘的敏感度[0.1 0.25]这类低阈值能找到更多边缘适合对比度低的图[0.2 0.4]这类高阈值适合干净、线条分明的图。例程里这行通常是BW edge(I, canny, [0.15 0.3], 2);最后一个参数 2 是高斯滤波器的标准差影响边缘平滑程度。3.2 一个可以直接运行的直线检测例程%% 直线检测例程以棋盘格测试图为例 I checkerboard(20, 5, 5) 0.5; % 生成网格图 I imnoise(I, gaussian, 0, 0.02); % 加一点噪声模拟真实场景 if size(I, 3) 3 I rgb2gray(I); end BW edge(I, canny, [0.15 0.3], 2); % 1. 边缘检测 [H, theta, rho] hough(BW, ThetaResolution, 1, RhoResolution, 1); P houghpeaks(H, 30, Threshold, 0.3 * max(H(:)), NHoodSize, [51 11]); lines houghlines(BW, theta, rho, P, FillGap, 25, MinLength, 30); imshow(I); hold on; for k 1:numel(lines) xy [lines(k).point1; lines(k).point2]; plot(xy(:, 1), xy(:, 2), LineWidth, 2, Color, [1 0 0]); end hold off;第一步的edge把灰度图变成二值图[0.15 0.3]是 Canny 的双阈值低于 0.15 的像素不会成为边缘高于 0.3 的像素确定为边缘中间的像素只有在与强边缘相连时才会保留。第二步的hough生成累加器ThetaResolution和RhoResolution都取默认的 1这对大多数图像已经够用。第三步houghpeaks找 30 个候选峰值Threshold取0.3 * max(H(:))表示只有票数超过全局峰值 30% 的位置才被当作候选直线方向。最后houghlines负责把参数还原成图像坐标里的线段并输出结构体数组。lines结构体包含point1、point2、theta、rho四个字段其中point1和point2是线段端点的[x, y]坐标直接拿plot画即可。这里用checkerboard生成棋盘格是为了让读者不需要额外准备图片换成本地图片时只需要替换第一行imread读取的内容。3.3 从 lines 结果反推斜率和角度theta 的正负号约定angles [lines.theta]; % 提取所有线段的法线角度 lineSlope 90 - angles; % 转换成与水平方向的夹角 lineSlope(lineSlope 0) lineSlope(lineSlope 0) 180;lines.theta存储的是直线法线与 x 轴的夹角不是直线本身的倾角。把theta换算成直线与水平方向夹角需要做一次90 - theta结果落在[-90, 90]之间负值加 180 统一到[0, 180]范围。3.3.1 为什么 theta 正负号经常把人绕晕图像中的情况theta 值说明竖直线接近 0法线沿 x 轴方向水平线接近 ±90法线沿 y 轴方向从左下到右上的斜线负值区法线方向偏左上从左上到右下的斜线正值区法线方向偏右上这张表在做倾斜校正时特别有用。例程跑出来的 theta 如果集中在某个值附近说明图像里存在大量平行线如果分布很散说明是噪声或曲线边缘直接取均值没有意义。调试时可以先跑一段代码把histogram([lines.theta], -90:5:90)画出来比盯着数字判断快得多。4. Hough 例程的扩展MATLAB 圆检测 imfindcircles 与两个关键参数4.1 为什么找圆不能用三件套的 hough 函数标准 Hough 圆变换要把圆心(a, b)和半径r三个参数放进累加器存储量和计算量都比直线高一个量级。MATLAB 的hough函数只支持直线圆检测走的是另一条函数imfindcircles它内部用的是 Hough 梯度法变体先估计边缘方向再投票给圆心候选。imfindcircles返回两个数组centers是圆心坐标radii是半径。它还支持第三个输出metric表示每个圆的置信度数值越接近 1 越可靠。这个 metric 在过滤误检时很有用官方文档给出了三个输出的完整用法。4.2 一个圆检测例程及调参方法I imread(coins.png); [centers, radii, metric] imfindcircles(I, [15 40], ... ObjectPolarity, bright, ... Sensitivity, 0.92, ... EdgeThreshold, 0.2); imshow(I); hold on; idx metric 0.5; % 只保留置信度大于0.5的圆 viscircles(centers(idx, :), radii(idx), EdgeColor, r); hold off;[15 40]是半径范围单位是像素需要根据图中目标大小预估。ObjectPolarity指定目标是亮背景上的暗物体还是暗背景上的亮物体coins.png里硬币比背景亮所以用bright。Sensitivity默认 0.85取值范围 0 到 1越大越容易找到置信度低的圆目标但误检也会增多。EdgeThreshold默认 0.1控制边缘梯度阈值值越高要求边缘越强。调参顺序我一般固定成先把半径范围收紧再用默认 Sensitivity 跑一次观察漏检还是误检为主。漏检就每步加 0.03 提高 Sensitivity误检就提高 EdgeThreshold 并配合 metric 过滤。注意不要同时调两个参数否则无法判断是谁起了作用。置信度过滤那段代码只保留metric 0.5的结果实际项目中阈值可以提高到 0.7 甚至 0.8。4.3 圆检测例程里常见的失败模式现象原因参数回退策略硬币少检了几个半径范围太宽或 Sensitivity 太低把半径范围上限下调Sensitivity 每次加 0.03把椭圆也当圆检出来EdgeThreshold 太低梯度弱区域参与投票EdgeThreshold 升到 0.3 附近同心圆被拆成多个候选同一目标的多个边缘环都投票用 metric 排序只保留每个圆心附近 metric 最高的背景纹理被当成圆目标与背景对比度不足先做直方图均衡再重跑例程圆检测比直线检测更依赖图像质量因为圆心投票对边缘方向的精度很敏感。如果例程在噪声图上直接跑建议在前面加一步imgaussfilt(I, 1)做平滑而不是只加高 Sensitivity。平滑会把噪声边缘的梯度方向打散让真正的圆弧边缘在投票中更占优势。5. 例程收尾技巧用 houghlines 输出写一个文档倾斜校正函数5.1 用角度众数求主方向把 houghlines 结果里的 theta 统计成直方图峰值对应的角度就是图像里占主导的平行线方向。对文档扫描件来说这个方向基本等于文字行的方向。注意不要直接取均值因为少数竖直线和斜线会把均值拉偏用众数或直方图峰值更稳。function J deskew_by_hough(I) if size(I, 3) 3 I rgb2gray(I); end BW edge(I, canny, [0.1 0.25], 1.5); [H, theta, rho] hough(BW, Theta, -89:0.5:89); P houghpeaks(H, 20, Threshold, 0.2 * max(H(:))); lines houghlines(BW, theta, rho, P, FillGap, 20, MinLength, 50); angs [lines.theta]; edges -89:2:89; cnts histcounts(angs, edges); % 统计角度直方图 [~, idx] max(cnts); % 找到数量最多的区间 thetaMode edges(idx) 1; % 取区间中心 rot 90 - thetaMode; % 法线角转旋转角 if abs(rot) 45 rot rot - sign(rot) * 90; % 把角度限制在 ±45 内 end J imrotate(I, rot, bilinear, crop); end这段代码里histcounts比直接mode更可靠因为mode在多峰时返回的是第一个最小值容易选到噪声方向。rot的正负号需要说明imrotate正数表示逆时针旋转如果扫描件整体顺时针歪了 3 度这时的thetaMode大约是 93 度90 - 93 -3imrotate(I, -3)会顺时针转回 3 度方向刚好对上。可以用checkerboard(20, 5, 5)先转 5 度再跑这个函数验证。5.2 验证校正结果的两个方法第一个方法是把校正前后的图片各自跑一遍上面的函数对比输出角度。校正前的峰值角度接近 5校正后应接近 0。第二个方法更直观对校正后的图做一次sum投影文字行方向的投影方差最大旋转回去后这个方差应该明显变大。proj sum(double(BW_corrected), 2); variance_before var(sum(double(BW_original), 2)); variance_after var(proj);这个方法只适合有大量平行文字行的文档和表格类图像对照片或曲线为主的图不适用。有一点需要注意imrotate的crop会把旋转产生的黑色三角区裁掉如果原始图边缘有重要信息改成loose再配合后处理裁剪。5.3 分辨率与性能的取舍有人为了把角度算得更准会把ThetaResolution改成 0.1这会让累加器列数膨胀 10 倍三个函数的计算时间明显增加但峰值定位的收益有限。更稳妥的做法是用默认的 1 度网格跑出粗角度然后取峰值附近的角度区间再局部精搜或者在第一次拿到theta后用插值拟合峰值位置。另外如果例程脚本里通过 MEX 或 Python 调用 OpenCV 辅助计算启动时遇到dll 初始化例程失败这类 WinError多半是 MATLAB 位数与外部库的位数不一致或者编译器路径没配对先重新执行mex -setup指定同一套工具链再回头查算法逻辑环境问题比算法问题更容易被忽略。本文还有配套的精品资源点击获取

相关新闻

Claude-Code-Game-Studios 的 /consistency-check 技能实战指南:跨 GDD 一致性扫描、冲突分类与验收测试全解析

Claude-Code-Game-Studios 的 /consistency-check 技能实战指南:跨 GDD 一致性扫描、冲突分类与验收测试全解析

Claude-Code-Game-Studios 的 /consistency-check 技能实战指南:跨 GDD 一致性扫描、冲突分类与验收测试全解析 【免费下载链接】Claude-Code-Game-Studios Turn Claude Code into a full game dev studio — 49 AI agents, 72 workflow skills, and a complete coo…

2026/9/13 19:13:56 阅读更多 →
提示工程上云:Serverless、K8s与虚拟机部署选型深度解析

提示工程上云:Serverless、K8s与虚拟机部署选型深度解析

提示工程上线前,先回答一个问题:你的服务该住进哪种“房子” 我见过太多团队栽在同一个坎上:提示词在测试环境调得漂漂亮亮,单测全过,效果惊艳,但一到“对外开放给客户用”的阶段就卡住了。是放在函数计算里…

2026/9/13 19:13:56 阅读更多 →
Agent Skills 格式完全指南:从规范、集成到编写实战(Agent-Skills-for-Context-Engineering 仓库解读)

Agent Skills 格式完全指南:从规范、集成到编写实战(Agent-Skills-for-Context-Engineering 仓库解读)

Agent Skills 格式完全指南:从规范、集成到编写实战(Agent-Skills-for-Context-Engineering 仓库解读) 【免费下载链接】Agent-Skills-for-Context-Engineering A comprehensive collection of Agent Skills for context engineering, multi-…

2026/9/14 19:57:17 阅读更多 →

最新新闻

视频元数据管理工具与批量处理实战指南

视频元数据管理工具与批量处理实战指南

1. 视频元数据管理的重要性与痛点在数字媒体爆炸式增长的今天,视频文件已成为我们日常工作和娱乐的重要组成部分。每个视频文件都携带了大量元数据(Metadata),这些隐藏在文件内部的信息记录了视频的标题、作者、创建日期、版权信息…

2026/9/15 2:04:12 阅读更多 →
OpenHarmony下Flutter生命周期检测:从信号错乱到稳定可用的实战指南

OpenHarmony下Flutter生命周期检测:从信号错乱到稳定可用的实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:04:12 阅读更多 →
身份可见性与智能平台:如何收缩IAM攻击面

身份可见性与智能平台:如何收缩IAM攻击面

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:04:12 阅读更多 →
微信小游戏源码调试与改造:从猫咪游戏入门到Unity打包上架

微信小游戏源码调试与改造:从猫咪游戏入门到Unity打包上架

简介:这套微信小游戏猫咪源码包,是一份面向微信小游戏开发初学者或对H5游戏感兴趣的读者的学习参考资源,主要用于了解小游戏页面搭建、猫咪形象展示与简单交互的实现方式,通过实际工程文件降低上手门槛。压缩包约49KB,…

2026/9/15 2:04:12 阅读更多 →
模式识别实验代码:Bayes、Fisher、KNN与PCA人脸识别实战

模式识别实验代码:Bayes、Fisher、KNN与PCA人脸识别实战

简介:基于Python的模式识别实验代码包,直接对应本科模式识别课程常见实验任务,适合计算机/人工智能相关专业学生对照学习与完成实验报告。代码包围绕三类典型实验展开:基于FAMALE.TXT与MALE.TXT建立Bayes性别分类器,并…

2026/9/15 2:04:12 阅读更多 →
前端面试进阶:安全取值、Promise.all手写与闭包内存泄漏实战解析

前端面试进阶:安全取值、Promise.all手写与闭包内存泄漏实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:03:12 阅读更多 →

日新闻

Java高级技术:从语言特性到性能优化全解析

Java高级技术:从语言特性到性能优化全解析

1. Java高级技术概述Java作为一门成熟的编程语言,经过二十多年的发展已经形成了完整的生态系统。在企业级应用开发、大数据处理、移动开发等领域,Java都占据着重要地位。掌握Java高级技术不仅意味着能够编写更高效的代码,更代表着开发者能够解…

2026/9/15 0:00:23 阅读更多 →
C#与Halcon结合的工业视觉处理实战指南

C#与Halcon结合的工业视觉处理实战指南

1. 项目概述:C#与Halcon强强联合的视觉处理利器这个基于C#和Halcon的视觉处理Demo项目,是我在工业质检领域摸爬滚打多年后提炼出的实战精华。它完美融合了C#的界面开发优势与Halcon强大的图像处理能力,就像给视觉工程师配上了一把瑞士军刀。项…

2026/9/15 0:00:23 阅读更多 →
32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

1. 为什么“32路复合型”不是营销话术,而是工业现场真实痛点的硬解你有没有遇到过这样的场景:在某大型能源站的PLC机柜里,十几台不同年代、不同品牌的温控仪、电表、气体分析仪、阀门控制器,全靠RS-485总线挂在一根线上&#xff0…

2026/9/15 0:00:23 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/14 5:45:49 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/15 1:32:25 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/15 1:32:21 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/14 17:35:10 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/14 16:59:29 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/14 5:45:14 阅读更多 →