小白学习图像处理7——Hough变换检测直线
文章目录
- 一、Hough变换的原理
- 1、过定点的直线方程
- 2、两点确定一条直线
- 3、方程的形式
- 二、实现过程
- 三、程序代码
- 1、程序片段
- 2、总程序
- 四、matlab 的hough函数
一、Hough变换的原理
1、过定点的直线方程
在 xoy 平面给定一个点P(xi, yi),则过点P的一条直线可以用表示为(直线x = C 除外):
yi=axi+by_{i} = ax_{i}+b yi=axi+b
过点P的直线有无数条,它们构成一个集和,参数a、b满足方程:
b=−axi+yib = - ax_{i} + y_{i} b=−axi+yi
也就是说,参数a、b在一条直线上,直线斜率为-xi,截距为yi。把a、b构成的平面称为参数空间,因此:xoy平面内的一点确定参数空间的一条直线,下图展示了对应关系:,对应关系如下图所示:
2、两点确定一条直线
如下图,若给定 xoy 平面内的两个点 P(x1, y1) 和 Q(x2, y2),则在参数空间内我们可以确定两条直线,这两条直线交于一点 (a0, b0),参数空间内点(a0, b0)对应着过两点的直线。
参数空间内的一条直线对应着 xoy 平面的一个点,参数空间的一个点对应着 xoy 平面的一条直线。
3、方程的形式
上面的结果说明了,我们可以在参数空间找直线的交点,反过来确定 xoy 平面的直线。前面的直线方程表达式为斜截式,斜截式存在一个问题,当直线的斜率很大的时候,截距趋于无穷,因此需要考虑别的形式。
使用直线的 法线斜率 来表示直线可以巧妙地避开参数无穷大的问题(注意这个表达式不是极坐标表示):
xcosθ+ysinθ=ρx cos\theta + y sin\theta = \rho xcosθ+ysinθ=ρ
其中,参数 ρ 表示原点到直线的距离,ρ∈[-D, D],D 为图像的对角线长度,参数θ表示直线的法线与x轴的夹角,θ∈[-pi/4, pi/4]。对上式变一下形可得:
y=−xcotθ+ρ/sinθy = - x cot \theta + \rho / sin \theta y=−xcotθ+ρ/sinθ
这个式子和斜截式一模一样,下图说明了它的几何意义:
解释:其中,对于点 (xi, yi) 来说,OB 表示ρ,0A代表 xi cosθ,AB表示 yi sin θ,于是xi cosθ + yi sinθ = ρ,由于点 (xi, yi) 是任意的,因此直线上每一点豆豆满足该方程(有没有觉得很直观)
xoy 平面内的任意一个点都对应了一个方程,每一个方程确定了参数空间的一条 正弦波,若已知两个定点(xi, yi),(xj, yi),则在参数空间内对应的正弦波交于一点,该点确定了过两点的直线,如图:
二、实现过程
上一部分给出了hough变换的理论基础,要在图像中检测直线还需要一定的处理。一幅图像对应着一系列的离散点,映射到参数平面一系列(ρ, θ)的组合,首先将ρθ参数空间划分为 累加单元,xy平面内一个点对于的参数空间的每一条曲线离散化为点,落在累加单元内,如下图所示:
坐标(i, j)处的单元具有累加值 A(i, j),它对应于参数空间坐标(ρi, θj)相关联的正方形(我们对参数空间离散化为无数个正方形)
具体的步骤:
- 离散化ρθ参数空间,得到累加单元 A。
- 最初将所有累加单元的值A(i, j)置为零。
- 然后对于xoy平面内的每一个非背景点(xk, yk),令 θ 等于 θ 轴上每一个允许的离散值,使用参数方程计算出 ρ 的对应值。对得到的 ρ 值四舍五入,得到最邻近的ρ轴上的离散值。对每一个非背景点,一个 θp 对于着 ρq ,则令A(p, q)加一。
- **完成上述步骤后,A(i, j)的值对应着xoy平面内有多少个点位于由参数(θ, ρ)确定的直线上。
三、程序代码
1、程序片段
提取边缘
为了检测直线,首先要提取图像的边缘,可以使用edge 函数提取图像边缘,假设读入的图像为灰度图:
img = imread(file_name);
img = im2double(img);
Edge = edge(img, 'canny', 0.2, 0.5, 1);
figure
subplot(121), imshow(img)
subplot(122), imshow(Edge)
set(gcf, 'color', [1 1 1])
结果如下:
参数平面离散化
构建一个ρθ平面,并离散化为一个个方格,每一个小方格代表一个计数器,将计数器的值初始化为0,每个计数器对应的ρ-θ值确定了x-y平面内的一条直线(注意计数器的坐标与计数器对应的ρ-θ值的关系):
[h, w] = size(Edge);
D = ceil(sqrt((h*h + w*w))); % 对角线
d_rho = 2*D/precision; % 单元大小
d_theta = pi/precision; % 单元大小
rho = -D : d_rho : D;
theta = -pi/2 : d_theta : pi/2;counter = zeros(length(rho), length(theta)); % ρ-θ平面计数器
累加器单元计数
遍历图像的每一个像素点,如果该像素点上的灰度为1(edge函数得到一个二值图像,灰度为1说明像素点为非背景点),则通过点的坐标 (x, y) 得到 ρ-θ 平面内的一条直线,将 ρ-θ 内满足该直线方程的计数器的值加一:
rho_val = @(x, y, theta) x*cos(theta) + y*sin(theta);for x = 1 : h for y = 1 : wif Edge(x, y) == 1for theta_i = -pi/2 : d_theta : pi/2rho_i = rho_val(x, y, theta_i);rho_pos = round((rho_i + D) / d_rho + 1); % 累加单元纵坐标theta_pos = round((theta_i + pi/2) / d_theta + 1); % 累加单元横坐标counter(rho_pos, theta_pos) = counter(rho_pos, theta_pos) + 1;endendend
end
检测直线
通过上面的计数过程,我们将 ρ-θ 平面当作图像绘制出来:
counter = counter / max(max(counter)); % 归一化
figure, imshow(counter)
set(gcf, 'color', [1 1 1])
结果如下,它是由很多条正弦曲线叠加得到的,多条曲线的交点就是直线的位置:
下面我们把最亮的那几个点提取出来:
counter = counter.*im2bw(counter, threshold); % 将较暗的点置为0
% 亮的区域,只保留局部最大值
counter = counter.*(counter == ordfilt2(counter, domian_size.^2, ones(domian_size)));
counter = im2bw(counter, 0);
figure, imshow(counter)
set(gcf, 'color', [1 1 1])
结果如下:
最后一步,我们取出所有参数 (ρ, θ)
% 计算所有直线的参数
[rho_pos, theta_pos] = find(counter > 0);
theta_set = (theta_pos * d_theta - pi/2); % theta 集合
rho_set = rho_pos * d_rho - D; % rho 集合
绘制直线
思路:遍历x-y平面内的所有像素点,如果x-y平面内的像素点(x0, y0) 坐标满足任意一对参数所确定的直线方程,则将原图像中的 (x0, y0) 像素点的灰度置为1:
%% 绘制边
for x = 1 : hfor y = 1 : w% 判断点属于某条直线(满足某个直线方程)isLine = find(round(x*cos(theta_set) + y*sin(theta_set) - rho_set) == 0);if ~isempty(isLine)img(x, y) = 1;endend
end
figure, imshow(img)
set(gcf, 'color', [1 1 1])
结果如下:
2、总程序
在程序的开始我们设定了三个参数,参数precision确定要把参数空间划分为多少格;参数threshold用于抑制参数平面内“较暗”的点;参数domian_size用于提取参数空间的局部最大值,确定直线。
close all%% 参数
precision = 900; % 控制精度,越大精度越高
threshold = 0.3; % 控制可被检测的最小直线长度,越小可被检测到的线段越短
domian_size = 30; % 避免重复的直线,适当大一些比较好
file_name = 'septagon.tif';%% 提取边缘
img = imread(file_name);
img = im2double(img);
Edge = edge(img, 'canny', 0.2, 0.5, 1);
figure
subplot(121), imshow(img)
subplot(122), imshow(Edge)
set(gcf, 'color', [1 1 1])%% 参数空间离散化
[h, w] = size(Edge);
D = ceil(sqrt((h*h + w*w))); % 对角线
d_rho = 2*D/precision; % 单元大小
d_theta = pi/precision; % 单元大小
rho = -D : d_rho : D;
theta = -pi/2 : d_theta : pi/2;counter = zeros(length(rho), length(theta)); % ρ-θ平面%% 计数
rho_val = @(x, y, theta) x*cos(theta) + y*sin(theta);for x = 1 : h for y = 1 : wif Edge(x, y) == 1for theta_i = -pi/2 : d_theta : pi/2rho_i = rho_val(x, y, theta_i);rho_pos = round((rho_i + D) / d_rho + 1); % 累加单元纵坐标theta_pos = round((theta_i + pi/2) / d_theta + 1); % 累加单元横坐标counter(rho_pos, theta_pos) = counter(rho_pos, theta_pos) + 1;endendend
end%% 检测边
counter = counter / max(max(counter)); % 归一化
figure, imshow(counter)
set(gcf, 'color', [1 1 1])% 获得计数器值很大的边,抑制位置几乎相同的参数
counter = counter.*im2bw(counter, threshold); % 只保留计数器值大的计数器
counter = counter.*(counter == ordfilt2(counter, domian_size.^2, ones(domian_size))); % 抑制位置相近的参数
counter = im2bw(counter, 0);
figure, imshow(counter)
set(gcf, 'color', [1 1 1])% 计算所有直线的参数
[rho_pos, theta_pos] = find(counter > 0);
theta_set = (theta_pos * d_theta - pi/2); % theta 集合
rho_set = rho_pos * d_rho - D; % rho 集合%% 绘制边
for x = 1 : hfor y = 1 : w% 判断点属于某条直线(满足某个直线方程)isLine = find(round(x*cos(theta_set) + y*sin(theta_set) - rho_set) == 0);if ~isempty(isLine)img(x, y) = 1;endend
end
figure, imshow(img)
set(gcf, 'color', [1 1 1])
四、matlab 的hough函数
参考:小白学习图像处理——使用matlab的hough变换函数
完结~
小白学习图像处理7——Hough变换检测直线相关推荐
- Hough变换检测直线与圆的原理
霍夫变换的基本原理 霍夫变换(Hough Transform)可以理解为图像处理中的一种特征提取技术,通过投票算法检测具有特定形状的物体.霍夫变换运用两个坐标空间之间的变换将在一个空间中具有相同形状的 ...
- hough变换检测直线 matlab,Matlab实现Hough变换检测图像中的直线
Hough变换的原理: 将图像从图像空间变换至参数空间,变换公式如下: 变换以后,图像空间与参数空间存在以下关系: 图像空间中的一点在参数空间是一条曲线,而图像空间共线的各点对应于参数空间交于一点的各 ...
- Python-Anaconda练习candy算子用于边缘提取,再用hough变换检测直线边缘
img: 待检测的图像. threshold: 阈值,可先项,默认为10 line_length: 检测的最短线条长度,默认为50 line_gap: 线条间的最大间隙.增大这个值可以合并破碎的线条. ...
- python 图像变化检测_python hough变换检测直线的实现方法
1 原理 2 检测步骤 将参数空间(ρ,θ) 量化成m*n(m为ρ的等份数,n为θ的等份数)个单元,并设置累加器矩阵,初始值为0: 对图像边界上的每一个点(x,y)带入ρ=xcosθ+ysinθ,求得 ...
- hough变换检测直线 matlab,求能够运行的用matlab进行hough变换直线检测的程序。急!...
满意答案 love8047g 2013.05.15 采纳率:43% 等级:13 已帮助:12527人 直接运行: RGB = imread('gantrycrane.png'); I = rgb ...
- 基于Hough变换的直线和圆的检测与提取
学数字图像处理有挺长时间了,正好最近这段时间有空,学习了一下Hough变换,作了几个比较简单的东西,分享出来,希望能和大家一起学习,也希望各位能提出宝贵的意见,共同进步,文采不好,欢迎拍砖,下面正式进 ...
- java hough_hough变换检测直线Java
hough变换检测直线原理: 假设在图像中存在一条直线y=k*x+b(此时k,b未知).取直线上的任意两点进行说明,设为(x0,y0),(x1,y1). 所有经过点(x0,y0)的直线满足:-x0*k ...
- MATLAB编程 利用Hough变换检测圆
MATLAB代码下载:利用Hough变换检测圆.docx-专业指导文档类资源-CSDN下载利用Hough变换检测圆,可以设置要检测圆的个数,最小尺寸.更多下载资源.学习资料请访问CSDN下载频道.ht ...
- 【机器视觉学习笔记】Hough变换直线检测(C++)
目录 源码 效果 平台:Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文源码摘自OpenCV2马拉松第22圈--Hough变换直线检测原理与实现 源 ...
最新文章
- 网易云课堂 学习教程
- 带有BERT模型代码的BILSTM+BERT+CRF
- Xshell登录Ubuntu12.04
- 记事本写python怎么运行-python入门之一个简单记事本
- OpenCV 为图像转换为漫画效果
- qq消息连发代码_我们用的QQ是怎样实现通讯的
- python现在的时间是几点_Python 的日期和时间处理
- Javaweb学习笔记——使用Jdom解析xml
- 【转】利用匿名namespace解决C++中重复定义的问题
- 查看视频文件格式信息的工具--MediaInfo
- 台式计算机用手机流量上网,台式机如何使用手机流量上网
- ceph (luminous 版) primary affinity 管理
- 如何准备机器学习工程师的面试
- linux-锁屏时间设置
- 可在WPS环境中通用的vb6代码修改方法
- linux磁盘坏块 cp报错,Linux磁盘坏道的检测及修复
- 苹果刷机服务器验证失败,iPhone手机刷机报错最全总结 教你学会分析手机问题出在哪...
- 银河麒麟/Ubuntu安装cuda和显卡驱动、cuDNN
- 计算机视觉——符号距离函数SDF
- 费森VZ90 VS雅马哈FG800,你会怎么选择?