1

直线检测问题

在纸上画一条直线,用手机拍下照片,把照片交给计算机识别。

计算机是如何知道这张照片中的这条直线的?

存在直线吗?

直线在哪里?

点、线、面是基本的几何元素。

欧几里得在《几何原本》中写道:

直线是点朝一个方向以及反方向的无限平铺。

一条直线在图像中,每个人一眼就能看出来。

我们不仅能够说出图像中存在一条直线,还可以说出直线经过哪个点,以及直线的方向。

如果有多条直线,我们还能说出直线之间的关系,相交还是(近似)平行,交点在哪里……

计算机怎么识别图像中的直线?

计算机的常规方法是提取边缘点,之后检测直线。

2

灰度矩阵与直线的灰度特征

计算机接收到一张照片,获得一个对应图像的灰度矩阵

矩阵是一格一格的,一格称为一个像素(pixel)。

矩阵的横、纵坐标是离散化的。

矩阵中的元素是量化的值,从0到255,该值称为灰度。

灰度,也称亮度,是该点受到光照亮度的对应数字。

如果是彩色的照片,对于计算机来说就是3张灰度图,即3个灰度矩阵。

按顺序分别是红的、绿的和蓝的灰度图。

因为在摄像机成像元件(CCD或CMOS)前面嵌有拜尔滤镜(如下图所示),使得三种颜色(即波长)的光进入到不同的灰度图中。

显示时,三种颜色同时显示,由于红、绿、蓝挨得很近,远处看就是彩色的。

1975年柯达美国分公司申请了拜尔滤镜发明专利(US3971065),1976年获得授权。

下面是一张灰度图:

计算机的数据用Matlab软件显示出来:

白色直线——灰度呈山峰形貌(黑色直线——灰度呈裂缝形貌)。

下面是两块钢板拼在一起的灰度图,中间有条直线(接缝),如何进行识别直线?

3

边缘检测原理

首先对灰度矩阵进行边缘提取。

边缘就是图像中灰度值变化大的点,凡是差值大于一定程度就当作边缘点。

在灰度矩阵中沿着水平方向从左到右移动当前位置,

从第二个像素开始,将该位置左右两个像素作差分,后者减去前者的灰度差存在另一个结果矩阵中对应当前位置处,直到倒数第二个像素为止,这样就获得了水平方向的边缘点差分结果矩阵。

沿着垂直方向也如此,获得垂直方向的边缘点差分结果矩阵。

有人觉得这样还不能精准找到边缘点,所以在上述思想上进行了修正,给出了索贝尔(Sobel)方法。

Sobel方法是将如下的左边小矩阵扣到灰度矩阵上,将上下对应项相乘再相加,得数就是这个中间位置处的水平差分结果,放入到水平差分结果矩阵中存储,然后移动该小矩阵向右,直到一行都完成这样的运算,再下移一行进行……直到全部算完,获得水平结果矩阵。

下方的右边小矩阵如法炮制,可以获得垂直结果矩阵。

这是在图像上进行计算的典型做法——邻域计算,邻域计算所用到的上述小矩阵被称为“算子”。

上面给出的是Sobel算子,分为x方向和y方向两种算子。

算子不同,得到的处理不同。

下面是Sobel算子与Prewitt算子对比:

在边缘检测领域,有roberts算子、canny算子、log算子、laplacian算子……

用不同的算子会得到不同的结果。

如果边缘点的方向是倾斜的(既不水平也不垂直),在上述两个矩阵中就容易不明显,为了找到这些边缘点,还需要将上述两个矩阵进行一个整合。

整合办法是:

将上述两个矩阵的对应元素平方和、相加,再开根号,

这样就得到了全方向的边缘点差分结果矩阵。

整合公式:

包括了任意方向的灰度差分结果矩阵。

该差分结果矩阵将边缘点凸显出来。

接着进行二值化:

将上述边缘点差分结果矩阵进行二值化:

凡是边缘点差分大于某个事先预定的值(称为阈值)就当作边缘点,设其值为1,非边缘点设值为0。

从而获得一个元素值只有1或0的黑白图像。

下图为采用Sobel方法进行边缘提取得到的黑白图像。

阈值的取值需要慎重:

如果阈值取得过小,会将大量不是边缘的点当作边缘点。

如果阈值取得过大,会将大量是边缘的点忽略掉。

阈值取得过小的结果:

4

最小二乘法

接下来的任务是:

在上述边缘点黑白图像中识别出直线。

有一种方法是用于找到多个点的拟合直线的,叫做最小二乘法。

最小二乘法就是找到一条直线,该直线到各点的距离之和最短。

但是这种方法不适用于边缘点黑白图中识别直线,

原因是边缘点有不少存在错误,即存在噪点,

一个偏离直线很远的点可能被错认为是边缘点,

而且在直线两侧的点的数量也不一样多,

都会导致最小二乘法找不出正确的直线。

噪点存在的原因是多方面的,很难没有一个噪点:

1)光线总是或多或少的照进摄像机;

2)镜头畸变,弧面精度有限,玻璃材质均匀程度偏差导致折射率有变化;

3)摄像机电路干扰、电磁影响;

4)边缘点提取时阈值选择不当会带来大量噪点……

因此最小二乘法无法在存在大量错误点的情况下找到直线。

5

哈夫变换

大量采用的直线检测的方法是哈夫变换。

哈夫变换(Hough Transform, 简称HT,又译作霍夫变换)可以找到经过点最多的直线。

在计算机视觉和图像处理领域,哈夫变换作为一种形状分析技术被广泛应用。

哈夫变换是1959年由Paul Hough申请的美国发明专利技术,1962年获得授权。

Hough发明专利的名称为:

Method and Means for Recognizing Complex Patterns(用于识别复杂图案的方法和手段)

拿穿羊肉串打个比方,就是要找到羊肉穿得最多的竹签。

经过边缘点最多的直线就是要找的直线。

这个方法可以有效克服噪点的影响,

因为噪点往往不在直线上,噪点的数量一般是少于经过直线上的点的。

如果噪点的数量多于经过直线上的点,是什么情况?

就是人眼也分辨不出该直线了,

这种情况出现在前面的边缘点提取环节,灰度跳变的阈值选小了。

哈夫变换方法怎么做的呢?

哈夫变换方法是:

利用直线参数方程:

建立一个对应的哈夫空间。

哈夫空间的横坐标是直线相对于坐标横轴的角度,

而纵坐标是坐标原点到直线的垂足长度。

这样一来,每个直角坐标空间的点都对应哈夫空间中的一条正弦曲线,

反之,每个哈夫空间中的点都对应直角坐标空间中的一条直线。

这个变换称为哈夫变换

哈夫变换就是直角坐标空间(也称为笛卡尔空间)与极坐标空间的变换。

哈夫变换将每个边缘点换算成为哈夫空间的正弦曲线,

多个边缘点就有多条正弦曲线,

哈夫空间中的这些正弦曲线的交点,

对应于经过了最多点的一条直线。

下图为哈夫变换得到的哈夫空间结果:

存在一个高耸的塔尖,塔尖这一点的高度就是投票数,说明有最多的点在对应该点的直线上,塔尖这一点在哈夫空间中的角度值、垂足距离值可以首先得到,用参数方程就得到了对应的直线。

在原来边缘点图像中找直线的任务,就转换成在对应的哈夫空间中找最多正弦曲线的交点的任务。

计算机善于找最大值或最小值,

模模糊糊、大约多少的事情计算机不擅长。

如何找最多曲线的交点?

计算机采用投票的方式,

哈夫空间中,正弦曲线经过的每个小格子里都会投上一票,

当所有的边缘点对应的正弦曲线都画完,则投票结束,

数数得票数,就找到了得票最多的那个点。

有了这个点,其对应的直线参数也就找到了,

直线也就识别出来了。

直线识别的结果(白线)叠加在原图上:

之所以划分很多格子,

是因为计算机只能做量化计算。

每个格子的边长称为步长(或周期)。

一个是直线角度的步长,

另一个是垂足距离的步长。

步长越小,计算得越精确,

但是耗时间就越长。

不仅直线可以通过哈夫变换来检测,圆也可以通过哈夫变换来识别。

凡是能够有确定的解析式的曲线,也都可以使用哈夫变换的方法来检测。

哈夫变换还可以识别多条直线、多个圆弧。

哈夫变换是图像处理中从图像中识别几何形状的基本方法之一。

哈夫变换的基本原理在于利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点,从而把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。可以适用于直线、椭圆、圆等。

6

哈夫变换教程视频

来看看哈夫变换的教程视频:

7

哈夫变换的不足

哈夫变换方法存在一个问题:效率低。

因为哈夫变换方法需要将每个点对应的正弦曲线画在哈夫空间中,

一个点就要画出179根线(如果是步长为1度的话),

每个点都这样做一遍,

计算量比较大,程序运行耗时长。

因此哈夫变换方法也被人取了一个绰号:咖啡方法

一杯咖啡慢悠悠地喝完了,

哈夫变换的计算结果才姗姗来迟。

8

哈夫变换改进方法

人们针对哈夫变换方法提出了多种改进措施,

于是产生了随机哈夫变换、快速哈夫变换、随机快速哈夫变换等。

在产生了这些改进的哈夫变换后,

原来的哈夫变换就被定义为:

标准哈夫变换。

随机哈夫变换方法是随机找边缘点来进行哈夫变换,

在不断运行的过程中,就会找到交于一点的直线数量逐渐上升,

当直线数量达到预设的一个数值时,就终止程序,

认为此时已经找到了该直线。

这个方法有一定的风险性,

只要交于一点的直线数量足够的大就好,

风险虽然仍然存在,但是已经很小。

快速哈夫变换方法是将两个点一同拿来做哈夫变换。

因为两点有且仅有一条直线,

因此用该直线在哈夫空间去绘制一个点,

这样计算量就大大降低了。

原来标准哈夫变换方法需要画出整条正弦曲线,

两个点就是两条正弦曲线,

现在只用在哈夫空间画出两个点所在直线的一个点即可。

8

哈夫变换Matlab程序

事先拍摄一张照片,存为灰度图像,名为a1.bmp,将其放在下面的程序同一个文件夹中。打开Matlab,将下面的程序新建一个脚本文件,运行该文件。

%Hough detection

clear;          %清除上次运行的所有变量

close all;     %关闭上次运行的子窗口

%=====下面读取原图并显示

I1 = imread('a1.bmp');     %事先有张灰度图,名为a1.bmp

figure(1),imshow(I1)         %将图像显示出来

I2 = im2double(I1);          %将图片的数据类型从unit8变为double型,只有这样回叙才能进行处理

%=====下面进行Sobel方法的边缘提取并显示

I_edge = edge(I2,'sobel');  %边缘提取,采用Sobel方法

figure(2),imshow(I_edge)   %将结果图像显示出来

%=====输入源图像大小

image_y_max=570;

image_x_max = 760;

%=====输入搜索初始角度

alpha_initial = 100;

%=====输入搜索步长角度

thelta_step = 1;

%=====输入搜索总角度范围

total_angle_for_search = 180;

m = round(total_angle_for_search/thelta_step+1);

%=====初始化hough投票矩阵,未防止计算的lamda距离超出矩阵,设置一个大的矩阵

n=2000;

M_hough=zeros(n,m);

%=====防止距离为负

lamda_initial =round(n/2);

%=====对每个像素操作

for x = 1 : image_x_max - 1

for y = 1 : image_y_max - 1

%=====转换为矩阵下标的坐标系

u = -y + image_y_max;

v=x;

%=====如果有点,就投票

if I_edge(u,v) == 1

%======循环m次,直线旋转投票

for k = 1 : m-1

%=====计算角度

alpha1 = alpha_initial + k*thelta_step;

alpha1 = round(alpha1);

%=====计算距离

lamda1 = x*cos(alpha1*pi/180)+y*sin(alpha1*pi/180);

lamda1 = round(lamda1);

M_hough(lamda_initial + lamda1,k) = M_hough(lamda_initial + lamda1,k) + 1;

end

end

end

end

%=====显示M_hough矩阵

figure(5),mesh(M_hough);

%======取出最大值所在的行、列

[rm,km]=find(M_hough == max(max(M_hough)))

%=====计算该点原距离

rm = rm - lamda_initial;

%draw the line

%=====计算该点原角度

alpha_line = alpha_initial + km*thelta_step

alpha_line_rad = alpha_line*pi/180;

lamda_line = rm/sin(alpha_line_rad);

%=====在原图像上重叠画出该直线

for x=1:image_x_max-1

%=====直线方程式

y = -x*(1/tan(alpha_line_rad))+lamda_line;

%=====只画在图像中的直线

if y <= image_y_max - 1

if y >= 1

v = x;

u = -y + image_y_max;

u = round(u);

I2(u,v) = 255;

end

end

end

%=====显示检测结果

figure(6),imshow(I2);

关于图像上的直线检测,你是否还有更好的办法呢?

echarts怎么控制一个点沿着折线移动_计算机怎么识别图像中的直线?相关推荐

  1. echarts 横坐标显示一个月,excel折线图横坐标最后一个点选择数据选不上是什么原因?...

    excel折线图横坐标最后一个点选择数据选不上是什么原因? 如果你说的是折线图横坐标选中的数据最后一个无法显示在横坐标上 您可以尝试一下 可以右击横坐标轴-设置坐标轴格式-选择大小与属性-对其方式-文 ...

  2. go语言怎么 控制一个变量输入的范围_四周入门Go语言(week01)

    [零]Go语言特点与输入输出 「特点」 1. 风格统一:同一件事只有一种实现方法,不同的人写出的代码风格应一致.例如:定义的变量必须要使用,if语句括号位置固定,只有for循环,fmt包能自动对齐代码 ...

  3. android 一个字符串分两行显示_【Android】DataBindinglt;中gt;

    DataBindingUtil类 DataBinding不仅可以绑定Activity还可以绑定视图内容(View) // 视图static extends ViewDataBinding> T ...

  4. -9 逆序输出一个整数的各位数字_计算机基础知识: 信息数字化

    计算机.数据与信息 无符号位数的表示 (一).四种常用的数制及它们之间的相互转换: 进制 基数 基数个数 权 进数规律 十进制 0.1.2.3.4.5.6.7.8.9 10 10i 逢十进一 二进制 ...

  5. ECharts动态加载数据绘制折线图

    Echarts动态加载数据绘制折线图 ECharts 引入ECharts 步骤 连接数据接口,动态加载图表 动态加载数据,整体代码 折线图绘制 总结 绘制多个图表的方法 ECharts 纯Javasc ...

  6. 解题代码 用jquery控制一个按钮当一次点击完之后5 秒后才能继续点击 验证码的制作...

    解题代码 用jquery控制一个按钮当一次点击完之后5 秒后才能继续点击 复制验证码的制作 转载于:https://www.cnblogs.com/yaomengli/p/6927630.html

  7. 了解单片机及单片机的控制原理和 DX516 的用法,控制一个 LED 灯的亮

    学习内容 单片机基本原理, 如何使用 DX516 仿真器, 如何编程点亮和灭掉一个 LED 灯, 如何进入 KEILC51uV, 调试环境, 如何使用单步,断点,全速,停止的调试方法. ------- ...

  8. 一个按键控制数码管的开和关_一个按键控制一个数码管

    一个按键控制一个数码管 C 程序 我用的 pic 单片机的与 51 也没有多大出入 #include #define key1 RA0 //RA0 脚接按键 key1 unsigned char RG ...

  9. 树莓派 | threading01 - 创建两个子线程同时运行,两个线程各负责控制一个LED灯以不同的频率闪烁

    文章目录 一.前言 二.代码 三.运行 一.前言 Python | threading01 - 创建两个同时运行的子线程 上一次使用了python的多线程库threading创建了两个同时运行的子线程 ...

最新文章

  1. 使用回调函数实现图像阈值分析。程序运行后在屏幕中输入阈值,通过改变滑动条实现不同类型的二值化图。
  2. python之matloplib可视化
  3. VC++深入详解 孙鑫 高清PDF + 配套视频下载
  4. php kafka storm,php的kafka踩坑(二)
  5. debconf-set-selections mysql_docker 静默安装mysql
  6. R 学习 - 箱线图
  7. python如何导入hotp库_Google Authenticator在Python中的实现
  8. 不来看看这些 VUE 的生命周期钩子函数? | 原力计划
  9. luogu P1015 回文数
  10. 搜狗收录之搜狗推送神器
  11. Bootstrap broker localhost9092 (id -1 rack null) disconnected
  12. “创业吃过饼,国企养过老,android开发零基础
  13. B550M主板组建raid
  14. infra-structure Ad Hoc
  15. iOS开发最新最全微信第三方登录接入流程
  16. 电子邮件及PE工作盘
  17. 食物与体质 营养食谱
  18. cocos studio
  19. 监听页面关闭和刷新的总结
  20. CC2530接入OneNET-实现数据上传和命令下发

热门文章

  1. 2019日历全年一张_带上这份2019全年活动日历,旅行打卡不迷路
  2. java中的md5加密_java中的MD5加密
  3. java getIV_Java SAP CRM get_children 方法里面参数 iv_as_copy 有什么用? _好机友
  4. 人工智能之语音识别技术(三)
  5. 一文看懂Python的控制结构:for、while、if…都有了
  6. 13 个 Python 新手练级项目
  7. qt mysql 注册码_QT连接Oracle数据库并实现登录验证的操作步骤
  8. o型圈沟槽设计_深圳综合O型密封圈ID544.4MM*8.6MM报价-星湖蓝海科技
  9. python自动发邮件富文本_django 实现后台从富文本提取纯文本
  10. 目前最常用的计算机机箱类型为_常用的计算机设备