Python 計(jì)算機(jī)視覺編程進(jìn)階之OpenCV 進(jìn)行霍夫變換
參考的一些文章以及論文我都會(huì)給大家分享出來(lái) —— 鏈接就貼在原文,論文我上傳到資源中去,大家可以免費(fèi)下載學(xué)習(xí),如果當(dāng)天資源區(qū)找不到論文,那就等等,可能正在審核,審核完后就可以下載了。大家一起學(xué)習(xí),一起進(jìn)步!加油??!
前言
(1)讀取圖像信息
經(jīng)典操作,不必多說(shuō):
"""
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)霍夫變換的目的及應(yīng)用
經(jīng)典的霍夫變換是被用來(lái)檢測(cè)圖像中的直線,后來(lái)擴(kuò)展到任何形狀的檢測(cè)識(shí)別中,多為直線和橢圓。所以利用霍夫變換我們可以提取圖像中的直線以及其他形狀類型的線條。
1. 霍夫變換
霍夫變換是圖像處理中的一種特征提取技術(shù),它通過(guò)一種投票算法檢測(cè)具有特定形狀的物體。該過(guò)程在一個(gè)參數(shù)空間中通過(guò)計(jì)算累計(jì)結(jié)果的局部最大值得到一個(gè)符合該特定形狀的集合作為霍夫變換的結(jié)果。
霍夫變換運(yùn)用兩個(gè)坐標(biāo)空間的變換將在一個(gè)空間中具有相同形狀的曲線或者直線映射到另外一個(gè)空間的坐標(biāo)點(diǎn)上形成峰值,從而把檢測(cè)任意形狀的問題轉(zhuǎn)化為統(tǒng)計(jì)峰值的問題。
2. 霍夫線變換
(1)基本概念
我們一般理解的在笛卡爾坐標(biāo)系中表示直線的方式有點(diǎn)線式和兩點(diǎn)式,然而在霍夫變換中,考慮的卻是另外一種方式:使用 (r, theta) 表示一條直線,其中 r 代表原點(diǎn)到這條直線的距離,theta 表示該直線的垂線與 x 軸的夾角。

那么我們?cè)趺礄z測(cè)直線呢?首先我們?yōu)槊恳粋€(gè)點(diǎn)假設(shè) n 個(gè)方向的直線,一般 n 為180,這樣檢測(cè)直線的角度精度為 1 度,分別計(jì)算這 n 條直線的(r, theta)坐標(biāo),得到 n 個(gè)坐標(biāo)點(diǎn)。那么判斷 N 個(gè)坐標(biāo)點(diǎn)就得到 N*n 個(gè) (r, theta)坐標(biāo),其中 theta 是離散的角度,有180個(gè)取值。當(dāng)多個(gè)點(diǎn)在同一條直線上時(shí),那么這條直線可以通過(guò)這些點(diǎn)中的任意一個(gè)點(diǎn)的某一個(gè)(r_i, theta_i)表示出來(lái)(每一個(gè)點(diǎn)取到特定的 theta 時(shí)得到的 r 相等或者相近)。比如空間中有三個(gè)點(diǎn),下圖表示了判斷這三個(gè)點(diǎn)共線的方式:

可以看出當(dāng) Angel(theta) 為 60 時(shí)距離 (r) 大致都為80.7,由此可以判斷這三個(gè)點(diǎn)都在直線(80.7,60)上。
我們也可以繪制一幅 r-theta 坐標(biāo)系,每一個(gè)點(diǎn)的 theta 為橫坐標(biāo)軸,r 為縱坐標(biāo),當(dāng)不同的點(diǎn)出現(xiàn)交點(diǎn)說(shuō)明這兩個(gè)點(diǎn)在同一條直線上:

(2)代碼實(shí)現(xiàn)
本例中使用到了邊緣檢測(cè)來(lái)減少計(jì)算,如果有小伙伴對(duì)邊緣檢測(cè)不熟悉可以去參考我之前的文章:
Python 計(jì)算機(jī)視覺編程進(jìn)階之OpenCV 圖像銳化及邊緣檢測(cè)
如果對(duì)函數(shù)的參數(shù)有疑問的話可以參考官網(wǎng):OpenCV
對(duì)于下面的代碼,我都添加注釋了,應(yīng)該講清楚了,如果有注釋的不清楚的地方,可以在評(píng)論區(qū)指出來(lái),大家一起討論
#霍夫直線檢測(cè)
##首先進(jìn)行邊緣檢測(cè),來(lái)減少空間中其他的點(diǎn)帶來(lái)的計(jì)算量的問題
img2 = cv2.GaussianBlur(img1, (5, 5), 0) #高斯模糊為邊緣檢測(cè)做準(zhǔn)備
img3 = cv2.Canny(img2, 50, 120) #使用Canny算子進(jìn)行邊緣檢測(cè)
cv2.imshow("W2", img3)
cv2.waitKey(delay = 0)
rho = 1 #距離分辨率
theta = np.pi/180 #角度分辨率
threshold = 10 #霍夫空間中多少個(gè)曲線相交表示一個(gè)正式的交點(diǎn)
min_line_len = 50 #最少需要多少個(gè)像素點(diǎn)才構(gòu)成一條直線
max_line_gap = 50 #線段之間的最大間隔像素點(diǎn)數(shù)
lines = cv2.HoughLinesP(img3, rho, theta, threshold, maxLineGap = max_line_gap) #所以這個(gè)函數(shù)中的參數(shù)都已經(jīng)在前面賦值時(shí)解釋過(guò)了
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)
得到的邊緣檢測(cè)圖像為:

得到的霍夫直線檢測(cè)的圖像為:

當(dāng)然霍夫直線檢測(cè)用在其他的比如建筑等方面才是好鋼用在刀刃上,這里作為示范用了人像。
3. 霍夫圓變換
(1)基本概念
一般來(lái)說(shuō),表示一個(gè)圓需要知道它的半徑以及圓心,這樣我們需要 (x, y, r) 三個(gè)參數(shù),如果只是靠這種方法識(shí)別圓,那么對(duì)于計(jì)算機(jī)來(lái)說(shuō)計(jì)算效率會(huì)下降。
在 OpenCV 中是使用了霍夫梯度的方法,利用邊界梯度信息。首先使用 Canny() 進(jìn)行邊緣檢測(cè),對(duì)邊緣的每一個(gè)非 0 通過(guò) Sobel() 進(jìn)行局部梯度計(jì)算(Sobel() 算子也在前面的文章中介紹過(guò)了),得到的梯度方向就是圓切線的方向,得到3個(gè)切線就可以確定圓心了。
(2)代碼實(shí)現(xiàn)
已添加注釋:
#霍夫圓檢測(cè)
dp = 1 #檢測(cè)內(nèi)測(cè)圓心的累加器圖像的分辨率與輸入圖像之比的倒數(shù)
minDist = 700 #兩個(gè)圓之間圓心之間的最小距離
param1 = 100 #前面提到過(guò) Canny 邊緣檢測(cè),這個(gè)參數(shù)表示傳遞給邊緣檢測(cè)的高閾值
param2 = 80 #檢測(cè)階段圓心的累加器閾值,簡(jiǎn)單來(lái)說(shuō)該參數(shù)越大檢測(cè)到的圓越完美,但數(shù)目越少,反之亦然
minRadius = 10 #最小圓的半徑
maxRadius = 20 #最大圓的半徑
cirlces = cv2.HoughCircles(img2, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius) #函數(shù)的參數(shù)前面解釋過(guò)了
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)

可以看出對(duì)人像的檢測(cè)局限于頭部,哈哈哈哈,建議大家多改幾次參數(shù)進(jìn)行嘗試,會(huì)得到不一樣的體驗(yàn),也可以多換幾張圖進(jìn)行測(cè)試。
4. 將所有圖像繪制到一張圖中
都是一些常規(guī)問題,沒啥好注釋的
#將所有圖像繪制在一張圖紙上
img0 = cv2.imread("E:\From Zhihu\For the desk\cvfourteen1.jpg") #再次讀取原圖,前面的圖像已經(jīng)進(jìn)行了變換
plt.rcParams['font.family'] = 'SimHei' #將全局中文字體改為黑體
imgs = [img0, img1, img2, img3, img4, img5]
title = ['原圖', '灰度圖', '高斯模糊', '邊緣檢測(cè)', '霍夫直線檢測(cè)', '霍夫圓檢測(cè)']
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. 總體代碼
修改圖像路徑就可以用了,但還是建議小伙伴們一步步來(lái)。
"""
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)
#霍夫直線檢測(cè)
##首先進(jìn)行邊緣檢測(cè),來(lái)減少空間中其他的點(diǎn)帶來(lái)的計(jì)算量的問題
img2 = cv2.GaussianBlur(img1, (5, 5), 0) #高斯模糊為邊緣檢測(cè)做準(zhǔn)備
img3 = cv2.Canny(img2, 50, 120) #使用Canny算子進(jìn)行邊緣檢測(cè)
cv2.imshow("W2", img3)
cv2.waitKey(delay = 0)
rho = 1 #距離分辨率
theta = np.pi/180 #角度分辨率
threshold = 10 #霍夫空間中多少個(gè)曲線相交表示一個(gè)正式的交點(diǎn)
min_line_len = 50 #最少需要多少個(gè)像素點(diǎn)才構(gòu)成一條直線
max_line_gap = 50 #線段之間的最大間隔像素點(diǎn)數(shù)
lines = cv2.HoughLinesP(img3, rho, theta, threshold, maxLineGap = max_line_gap) #所以這個(gè)函數(shù)中的參數(shù)都已經(jīng)在前面賦值時(shí)解釋過(guò)了
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)
#霍夫圓檢測(cè)
dp = 1 #檢測(cè)內(nèi)測(cè)圓心的累加器圖像的分辨率與輸入圖像之比的倒數(shù)
minDist = 700 #兩個(gè)圓之間圓心之間的最小距離
param1 = 100 #前面提到過(guò) Canny 邊緣檢測(cè),這個(gè)參數(shù)表示傳遞給邊緣檢測(cè)的高閾值
param2 = 80 #檢測(cè)階段圓心的累加器閾值,簡(jiǎn)單來(lái)說(shuō)該參數(shù)越大檢測(cè)到的圓越完美,但數(shù)目越少,反之亦然
minRadius = 10 #最小圓的半徑
maxRadius = 20 #最大圓的半徑
cirlces = cv2.HoughCircles(img2, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius) #函數(shù)的參數(shù)前面解釋過(guò)了
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") #再次讀取原圖,前面的圖像已經(jīng)進(jìn)行了變換
plt.rcParams['font.family'] = 'SimHei' #將全局中文字體改為黑體
imgs = [img0, img1, img2, img3, img4, img5]
title = ['原圖', '灰度圖', '高斯模糊', '邊緣檢測(cè)', '霍夫直線檢測(cè)', '霍夫圓檢測(cè)']
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()
結(jié)束語(yǔ)
本文主要總結(jié)了霍夫變換的基本概念和代碼實(shí)現(xiàn),包括線變換和圓變換,建議大家多嘗試,一些參數(shù)什么的多修改多試試。本篇文章主要參考的是《Python計(jì)算機(jī)視覺》這邊書,清華大學(xué)出版的,大家感興趣可以找來(lái)看看。
到此這篇關(guān)于Python 計(jì)算機(jī)視覺編程進(jìn)階之OpenCV 進(jìn)行霍夫變換的文章就介紹到這了,更多相關(guān)Python OpenCV 霍夫變換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文帶你解密Python迭代器的實(shí)現(xiàn)原理
這篇文章主要為大家詳細(xì)介紹了Python中迭代器的實(shí)現(xiàn)原理,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定的幫助,需要的可以參考一下2022-12-12
Pytorch實(shí)現(xiàn)的手寫數(shù)字mnist識(shí)別功能完整示例
這篇文章主要介紹了Pytorch實(shí)現(xiàn)的手寫數(shù)字mnist識(shí)別功能,結(jié)合完整實(shí)例形式分析了Pytorch模塊手寫字識(shí)別具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-12-12
python構(gòu)建基礎(chǔ)的爬蟲教學(xué)
在本篇內(nèi)容里小編給大家分享的是關(guān)于python構(gòu)建基礎(chǔ)的爬蟲教學(xué)內(nèi)容,需要的朋友們學(xué)習(xí)下。2018-12-12
教你使用TensorFlow2識(shí)別驗(yàn)證碼
驗(yàn)證碼是根據(jù)隨機(jī)字符生成一幅圖片,然后在圖片中加入干擾象素,本文主要介紹了 TensorFlow2識(shí)別驗(yàn)證碼,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06
一文詳解Python中的Map,Filter和Reduce函數(shù)
這篇文章主要介紹了一文詳解Python中的Map,Filter和Reduce函數(shù),本文重點(diǎn)介紹Python中的三個(gè)特殊函數(shù)Map,Filter和Reduce,以及如何使用它們進(jìn)行代碼編程2022-08-08
Python+Selenium實(shí)現(xiàn)自動(dòng)填寫問卷
本文主要介紹了Python+Selenium實(shí)現(xiàn)自動(dòng)填寫問卷,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
基于python中pygame模塊的Linux下安裝過(guò)程(詳解)
下面小編就為大家?guī)?lái)一篇基于python中pygame模塊的Linux下安裝過(guò)程(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11

