參考的一些文章以及論文我都會給大家分享出來 —— 鏈接就貼在原文,論文我上傳到資源中去,大家可以免費下載學習,如果當天資源區找不到論文,那就等等,可能正在審核,審核完后就可以下載了。大家一起學習,一起進步!加油!!
前言
(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 霍夫變換內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/qq_52309640/article/details/120941305