Python 计算机视觉编程进阶之OpenCV 进行霍夫变换

 更新时间:2021年11月24日 10:18:26   作者:一马归一码  
霍夫变换(Hough)是一个非常重要的检测间断点边界形状的方法。它通过将图像坐标空间变换到参数空间,来实现直线与曲线的拟合,通过本篇文章我们来详细了解它

参考的一些文章以及论文我都会给大家分享出来 —— 链接就贴在原文,论文我上传到资源中去,大家可以免费下载学习,如果当天资源区找不到论文,那就等等,可能正在审核,审核完后就可以下载了。大家一起学习,一起进步!加油!!

前言

(1)读取图像信息

经典操作,不必多说:

"""
Author:XiaoMa
date:2021/11/13
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np
 
img0 = cv2.imread("E:\From Zhihu\For the desk\cvfourteen1.jpg")
img1 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)
h, w = img0.shape[:2]
print(h, w)
cv2.imshow("W0", img0)
cv2.imshow("W1", img1)
cv2.waitKey(delay = 0)

525 787

(2)霍夫变换的目的及应用

经典的霍夫变换是被用来检测图像中的直线,后来扩展到任何形状的检测识别中,多为直线和椭圆。所以利用霍夫变换我们可以提取图像中的直线以及其他形状类型的线条。

1. 霍夫变换

霍夫变换是图像处理中的一种特征提取技术,它通过一种投票算法检测具有特定形状的物体。该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换的结果。

霍夫变换运用两个坐标空间的变换将在一个空间中具有相同形状的曲线或者直线映射到另外一个空间的坐标点上形成峰值,从而把检测任意形状的问题转化为统计峰值的问题。

2. 霍夫线变换

(1)基本概念

我们一般理解的在笛卡尔坐标系中表示直线的方式有点线式和两点式,然而在霍夫变换中,考虑的却是另外一种方式:使用 (r, theta) 表示一条直线,其中 r 代表原点到这条直线的距离,theta 表示该直线的垂线与 x 轴的夹角。

那么我们怎么检测直线呢?首先我们为每一个点假设 n 个方向的直线,一般 n 为180,这样检测直线的角度精度为 1 度,分别计算这 n 条直线的(r, theta)坐标,得到 n 个坐标点。那么判断 N 个坐标点就得到 N*n 个 (r, theta)坐标,其中 theta 是离散的角度,有180个取值。当多个点在同一条直线上时,那么这条直线可以通过这些点中的任意一个点的某一个(r_i, theta_i)表示出来(每一个点取到特定的 theta 时得到的 r 相等或者相近)。比如空间中有三个点,下图表示了判断这三个点共线的方式:

可以看出当 Angel(theta) 为 60 时距离 (r) 大致都为80.7,由此可以判断这三个点都在直线(80.7,60)上。

我们也可以绘制一幅 r-theta 坐标系,每一个点的 theta 为横坐标轴,r 为纵坐标,当不同的点出现交点说明这两个点在同一条直线上:

(2)代码实现

本例中使用到了边缘检测来减少计算,如果有小伙伴对边缘检测不熟悉可以去参考我之前的文章:

Python 计算机视觉编程进阶之OpenCV 图像锐化及边缘检测

如果对函数的参数有疑问的话可以参考官网:OpenCV

对于下面的代码,我都添加注释了,应该讲清楚了,如果有注释的不清楚的地方,可以在评论区指出来,大家一起讨论

#霍夫直线检测
##首先进行边缘检测,来减少空间中其他的点带来的计算量的问题
img2 = cv2.GaussianBlur(img1, (5, 5), 0)   #高斯模糊为边缘检测做准备
img3 = cv2.Canny(img2, 50, 120)            #使用Canny算子进行边缘检测
cv2.imshow("W2", img3)
cv2.waitKey(delay = 0)
rho = 1                    #距离分辨率
theta = np.pi/180          #角度分辨率
threshold = 10             #霍夫空间中多少个曲线相交表示一个正式的交点
min_line_len = 50          #最少需要多少个像素点才构成一条直线
max_line_gap = 50          #线段之间的最大间隔像素点数
lines = cv2.HoughLinesP(img3, rho, theta, threshold, maxLineGap = max_line_gap)    #所以这个函数中的参数都已经在前面赋值时解释过了
img4 = np.zeros_like(img3)
for line in lines:
    for x1, y1, x2, y2 in line:
        cv2.line(img4, (x1, y1), (x2, y2), 255, 1)        #绘制直线
cv2.imshow("W3", img4)
cv2.waitKey(delay = 0)

得到的边缘检测图像为:

得到的霍夫直线检测的图像为:

当然霍夫直线检测用在其他的比如建筑等方面才是好钢用在刀刃上,这里作为示范用了人像。

3. 霍夫圆变换

(1)基本概念

一般来说,表示一个圆需要知道它的半径以及圆心,这样我们需要 (x, y, r) 三个参数,如果只是靠这种方法识别圆,那么对于计算机来说计算效率会下降。

在 OpenCV 中是使用了霍夫梯度的方法,利用边界梯度信息。首先使用 Canny() 进行边缘检测,对边缘的每一个非 0 通过 Sobel() 进行局部梯度计算(Sobel() 算子也在前面的文章中介绍过了),得到的梯度方向就是圆切线的方向,得到3个切线就可以确定圆心了。

(2)代码实现

已添加注释:

#霍夫圆检测
dp = 1              #检测内测圆心的累加器图像的分辨率与输入图像之比的倒数
minDist = 700       #两个圆之间圆心之间的最小距离
param1 = 100        #前面提到过 Canny 边缘检测,这个参数表示传递给边缘检测的高阈值
param2 = 80         #检测阶段圆心的累加器阈值,简单来说该参数越大检测到的圆越完美,但数目越少,反之亦然
minRadius = 10      #最小圆的半径
maxRadius = 20      #最大圆的半径
cirlces = cv2.HoughCircles(img2, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius)  #函数的参数前面解释过了
cirlces = np.uint16(np.around(cirlces))
for i in cirlces[0, :]:
    cv2.circle(img0, (i[0], i[1]), i[2], (0, 0, 255), 1)
    cv2.circle(img0, (i[0], i[1]), 2, (0, 0, 255), 1)
cv2.imshow("W4", img0)
cv2.waitKey(delay = 0)

可以看出对人像的检测局限于头部,哈哈哈哈,建议大家多改几次参数进行尝试,会得到不一样的体验,也可以多换几张图进行测试。

4. 将所有图像绘制到一张图中

都是一些常规问题,没啥好注释的

#将所有图像绘制在一张图纸上
img0 = cv2.imread("E:\From Zhihu\For the desk\cvfourteen1.jpg")   #再次读取原图,前面的图像已经进行了变换
plt.rcParams['font.family'] = 'SimHei'       #将全局中文字体改为黑体
imgs = [img0, img1, img2, img3, img4, img5]
title = ['原图', '灰度图', '高斯模糊', '边缘检测', '霍夫直线检测', '霍夫圆检测']
for i in range(6):
    imgs[i] = cv2.cvtColor(imgs[i], cv2.COLOR_BGR2RGB)
    plt.subplot(2, 3, i + 1)
    plt.imshow(imgs[i])
    plt.title(title[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

5. 总体代码

修改图像路径就可以用了,但还是建议小伙伴们一步步来。

"""
Author:XiaoMa
date:2021/11/13
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np
 
img0 = cv2.imread("E:\From Zhihu\For the desk\cvfourteen1.jpg")
#img0 = cv2.resize(img0, dsize = None, fx = 0.5, fy = 0.5)
img1 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)
h, w = img0.shape[:2]
print(h, w)
cv2.imshow("W0", img0)
cv2.imshow("W1", img1)
cv2.waitKey(delay = 0)
#霍夫直线检测
##首先进行边缘检测,来减少空间中其他的点带来的计算量的问题
img2 = cv2.GaussianBlur(img1, (5, 5), 0)   #高斯模糊为边缘检测做准备
img3 = cv2.Canny(img2, 50, 120)            #使用Canny算子进行边缘检测
cv2.imshow("W2", img3)
cv2.waitKey(delay = 0)
rho = 1                    #距离分辨率
theta = np.pi/180          #角度分辨率
threshold = 10             #霍夫空间中多少个曲线相交表示一个正式的交点
min_line_len = 50          #最少需要多少个像素点才构成一条直线
max_line_gap = 50          #线段之间的最大间隔像素点数
lines = cv2.HoughLinesP(img3, rho, theta, threshold, maxLineGap = max_line_gap)    #所以这个函数中的参数都已经在前面赋值时解释过了
img4 = np.zeros_like(img3)
for line in lines:
    for x1, y1, x2, y2 in line:
        cv2.line(img4, (x1, y1), (x2, y2), 255, 1)        #绘制直线
cv2.imshow("W3", img4)
cv2.waitKey(delay = 0)
#霍夫圆检测
dp = 1              #检测内测圆心的累加器图像的分辨率与输入图像之比的倒数
minDist = 700       #两个圆之间圆心之间的最小距离
param1 = 100        #前面提到过 Canny 边缘检测,这个参数表示传递给边缘检测的高阈值
param2 = 80         #检测阶段圆心的累加器阈值,简单来说该参数越大检测到的圆越完美,但数目越少,反之亦然
minRadius = 10      #最小圆的半径
maxRadius = 20      #最大圆的半径
cirlces = cv2.HoughCircles(img2, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius)  #函数的参数前面解释过了
cirlces = np.uint16(np.around(cirlces))
img5 = img0
for i in cirlces[0, :]:
    cv2.circle(img5, (i[0], i[1]), i[2], (0, 0, 255), 1)
    cv2.circle(img5, (i[0], i[1]), 2, (0, 0, 255), 1)
cv2.imshow("W4", img5)
cv2.waitKey(delay = 0)
#将所有图像绘制在一张图纸上
img0 = cv2.imread("E:\From Zhihu\For the desk\cvfourteen1.jpg")   #再次读取原图,前面的图像已经进行了变换
plt.rcParams['font.family'] = 'SimHei'       #将全局中文字体改为黑体
imgs = [img0, img1, img2, img3, img4, img5]
title = ['原图', '灰度图', '高斯模糊', '边缘检测', '霍夫直线检测', '霍夫圆检测']
for i in range(6):
    imgs[i] = cv2.cvtColor(imgs[i], cv2.COLOR_BGR2RGB)
    plt.subplot(2, 3, i + 1)
    plt.imshow(imgs[i])
    plt.title(title[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

结束语

本文主要总结了霍夫变换的基本概念和代码实现,包括线变换和圆变换,建议大家多尝试,一些参数什么的多修改多试试。本篇文章主要参考的是《Python计算机视觉》这边书,清华大学出版的,大家感兴趣可以找来看看。

到此这篇关于Python 计算机视觉编程进阶之OpenCV 进行霍夫变换的文章就介绍到这了,更多相关Python OpenCV 霍夫变换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 适合Python项目的五大SQL连接器

    适合Python项目的五大SQL连接器

    这篇文章,将要介绍当前流行的、适合大多数Python程序员的、五大Python SQL数据库连接器,并讨论它们安装和各种的优缺点。需要的喷朋友可以参考下面文章的具体内容
    2021-09-09
  • Pytorch中torch.flatten()和torch.nn.Flatten()实例详解

    Pytorch中torch.flatten()和torch.nn.Flatten()实例详解

    这篇文章主要给大家介绍了关于Pytorch中torch.flatten()和torch.nn.Flatten()的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-02-02
  • Python3爬虫发送请求的知识点实例

    Python3爬虫发送请求的知识点实例

    在本篇文章里小编给大家分享的是一篇关于Python3爬虫发送请求的知识点实例,需要的朋友们可以学习下。
    2020-07-07
  • 详解Anaconda 的安装教程

    详解Anaconda 的安装教程

    这篇文章主要介绍了Anaconda 的安装教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • 在Python中合并字典模块ChainMap的隐藏坑【推荐】

    在Python中合并字典模块ChainMap的隐藏坑【推荐】

    在Python中,当我们有两个字典需要合并的时候,可以使用字典的 update 方法,接下来通过本文给大家介绍在Python中合并字典模块ChainMap的隐藏坑,感兴趣的朋友一起看看吧
    2019-06-06
  • 20个Python常用技巧分享

    20个Python常用技巧分享

    Python的可读性和简单性是其广受欢迎的两大原因,本文介绍20个常用的Python技巧来提高代码的可读性,并能帮助你节省大量时间,下面的技巧将在你的日常编码练习中非常实用
    2023-04-04
  • Python中的多行注释文档编写风格汇总

    Python中的多行注释文档编写风格汇总

    在Python中利用多行注释编写小型的程序文档说明非常方便,而约定俗成的格式也多种多样,这里我们就进行一下最常见的Python中的多行注释文档编写风格汇总:
    2016-06-06
  • python:接口间数据传递与调用方法

    python:接口间数据传递与调用方法

    今天小编就为大家分享一篇python:接口间数据传递与调用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • python Tkinter是什么

    python Tkinter是什么

    大家好,本篇文章主要讲的是 python Tkinter是什么,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • Pytest自定义用例执行顺序(推荐)

    Pytest自定义用例执行顺序(推荐)

    github 上有个 pytest-ordering 插件可以控制用例的执行顺序,本文给大家介绍了Pytest自定义用例执行顺序,需要的朋友可以参考下
    2021-12-12

最新评论