Python 计算机视觉(十四)—— OpenCV 进行霍夫变换
參考的一些文章以及論文我都會(huì)給大家分享出來 —— 鏈接就貼在原文,論文我上傳到資源中去,大家可以免費(fèi)下載學(xué)習(xí),如果當(dāng)天資源區(qū)找不到論文,那就等等,可能正在審核,審核完后就可以下載了。大家一起學(xué)習(xí),一起進(jìn)步!加油!!
目錄
前言
(1)讀取圖像信息
(2)霍夫變換的目的及應(yīng)用
1. 霍夫變換
2. 霍夫線變換
(1)基本概念
(2)代碼實(shí)現(xiàn)
3. 霍夫圓變換
(1)基本概念
(2)代碼實(shí)現(xiàn)
4. 將所有圖像繪制到一張圖中
5. 總體代碼
結(jié)束語
前言
(1)讀取圖像信息
經(jīng)典操作,不必多說:
""" Author:XiaoMa date:2021/11/13 """ import cv2 import matplotlib.pyplot as plt import numpy as npimg0 = 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)典的霍夫變換是被用來檢測(cè)圖像中的直線,后來擴(kuò)展到任何形狀的檢測(cè)識(shí)別中,多為直線和橢圓。所以利用霍夫變換我們可以提取圖像中的直線以及其他形狀類型的線條。
1. 霍夫變換
? ? ? ?霍夫變換是圖像處理中的一種特征提取技術(shù),它通過一種投票算法檢測(cè)具有特定形狀的物體。該過程在一個(gè)參數(shù)空間中通過計(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í),那么這條直線可以通過這些點(diǎn)中的任意一個(gè)點(diǎn)的某一個(gè)(r_i, theta_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)說明這兩個(gè)點(diǎn)在同一條直線上:
(2)代碼實(shí)現(xiàn)
本例中使用到了邊緣檢測(cè)來減少計(jì)算,如果有小伙伴對(duì)邊緣檢測(cè)不熟悉可以去參考我之前的文章:
Python 計(jì)算機(jī)視覺(十)—— OpenCV 圖像銳化及邊緣檢測(cè)
如果對(duì)函數(shù)的參數(shù)有疑問的話可以參考官網(wǎng):OpenCV
對(duì)于下面的代碼,我都添加注釋了,應(yīng)該講清楚了,如果有注釋的不清楚的地方,可以在評(píng)論區(qū)指出來,大家一起討論
#霍夫直線檢測(cè) ##首先進(jìn)行邊緣檢測(cè),來減少空間中其他的點(diǎn)帶來的計(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í)解釋過了 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)基本概念
? ? ? ?一般來說,表示一個(gè)圓需要知道它的半徑以及圓心,這樣我們需要 (x, y, r) 三個(gè)參數(shù),如果只是靠這種方法識(shí)別圓,那么對(duì)于計(jì)算機(jī)來說計(jì)算效率會(huì)下降。
? ? ? ?在 OpenCV 中是使用了霍夫梯度的方法,利用邊界梯度信息。首先使用 Canny() 進(jìn)行邊緣檢測(cè),對(duì)邊緣的每一個(gè)非 0 通過 Sobel() 進(jìn)行局部梯度計(jì)算(Sobel() 算子也在前面的文章中介紹過了),得到的梯度方向就是圓切線的方向,得到3個(gè)切線就可以確定圓心了。
(2)代碼實(shí)現(xiàn)
已添加注釋:
#霍夫圓檢測(cè) dp = 1 #檢測(cè)內(nèi)測(cè)圓心的累加器圖像的分辨率與輸入圖像之比的倒數(shù) minDist = 700 #兩個(gè)圓之間圓心之間的最小距離 param1 = 100 #前面提到過 Canny 邊緣檢測(cè),這個(gè)參數(shù)表示傳遞給邊緣檢測(cè)的高閾值 param2 = 80 #檢測(cè)階段圓心的累加器閾值,簡(jiǎn)單來說該參數(shù)越大檢測(cè)到的圓越完美,但數(shù)目越少,反之亦然 minRadius = 10 #最小圓的半徑 maxRadius = 20 #最大圓的半徑 cirlces = cv2.HoughCircles(img2, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius) #函數(shù)的參數(shù)前面解釋過了 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. 總體代碼
修改圖像路徑就可以用了,但還是建議小伙伴們一步步來。
""" Author:XiaoMa date:2021/11/13 """ import cv2 import matplotlib.pyplot as plt import numpy as npimg0 = 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è),來減少空間中其他的點(diǎn)帶來的計(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í)解釋過了 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 #前面提到過 Canny 邊緣檢測(cè),這個(gè)參數(shù)表示傳遞給邊緣檢測(cè)的高閾值 param2 = 80 #檢測(cè)階段圓心的累加器閾值,簡(jiǎn)單來說該參數(shù)越大檢測(cè)到的圓越完美,但數(shù)目越少,反之亦然 minRadius = 10 #最小圓的半徑 maxRadius = 20 #最大圓的半徑 cirlces = cv2.HoughCircles(img2, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius) #函數(shù)的參數(shù)前面解釋過了 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é)束語
? ? ? ?本文主要總結(jié)了霍夫變換的基本概念和代碼實(shí)現(xiàn),包括線變換和圓變換,建議大家多嘗試,一些參數(shù)什么的多修改多試試。本篇文章主要參考的是《Python計(jì)算機(jī)視覺》這邊書,清華大學(xué)出版的,大家感興趣可以找來看看。
總結(jié)
以上是生活随笔為你收集整理的Python 计算机视觉(十四)—— OpenCV 进行霍夫变换的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 计算机视觉(十三)—— 图
- 下一篇: 机器学习实战(一)—— K-近邻算法(K