Python圖像處理之Hough圓形檢測(cè)
hough檢測(cè)原理
點(diǎn)擊圖像處理之Hough變換檢測(cè)直線查看
下面直接描述檢測(cè)圓形的方法
基于Hough變換的圓形檢測(cè)方法
對(duì)于一個(gè)半徑為r,圓心為(a,b)的圓,我們將其表示為:
(x−a)2+(y−b)2=r2
此時(shí) x=[x,y]^T,a=[a,b,r]^T,其參數(shù)空間為三維。顯然,圖像空間上的一點(diǎn) (x,y),在參數(shù)空間中對(duì)應(yīng)著一個(gè)圓錐,如下圖所示。
而圖像空間的一個(gè)圓就對(duì)應(yīng)著這一簇圓錐相交的一個(gè)點(diǎn),這個(gè)特定點(diǎn)在參數(shù)空間的三維參數(shù)一定,就表示一定半徑一定圓心坐標(biāo)的圖像空間的那個(gè)圓。
上述方法是經(jīng)典的Hough圓檢測(cè)方法的原理,它具有精度高,抗干擾能力強(qiáng)等優(yōu)點(diǎn),但由于該方法的參數(shù)空間為三維,要在三維空間上進(jìn)行證據(jù)累計(jì)的話,需要的時(shí)間和空間都是龐大的,在實(shí)際應(yīng)用中不適用。為加快Hough變換檢測(cè)圓的速度,學(xué)者們進(jìn)行了大量研究,也出現(xiàn)了很多改進(jìn)的Hough變換檢測(cè)圓的方法。如利用圖像梯度信息的Hough變換,對(duì)圓的標(biāo)準(zhǔn)方程對(duì)x求導(dǎo)得到下式:
從上式看出,此時(shí)的參數(shù)空間從半徑r,圓心(a,b)三維,變成了只有圓心(a,b)的二維空間,利用這種方法檢測(cè)圓其計(jì)算量明顯減少了。但這種改進(jìn)的Hough變換檢測(cè)圓的方法其檢測(cè)精度并不高,原因在于,此種方法利用了邊界斜率。從本質(zhì)上講,邊界斜率其實(shí)是用曲線在某一點(diǎn)的弦的斜率來(lái)代替的,這種情況下,要保證不存在誤差,只有在弦長(zhǎng)為零的情況。但在數(shù)字圖像中,曲線的表現(xiàn)形式是離散的,其在某一點(diǎn)處的斜率指的是此點(diǎn)右向n步斜率或是左向n步斜率。如果弦長(zhǎng)過(guò)小了,斜率的量化誤差就會(huì)增大。這種方法比較適用于干擾較少的完整圓形目標(biāo)。
主要代碼
def AHTforCircles(edge,center_threhold_factor = None,score_threhold = None,min_center_dist = None,minRad = None,maxRad = None,center_axis_scale = None,radius_scale = None,halfWindow = None,max_circle_num = None): if center_threhold_factor == None: center_threhold_factor = 10.0 if score_threhold == None: score_threhold = 15.0 if min_center_dist == None: min_center_dist = 80.0 if minRad == None: minRad = 0.0 if maxRad == None: maxRad = 1e7*1.0 if center_axis_scale == None: center_axis_scale = 1.0 if radius_scale == None: radius_scale = 1.0 if halfWindow == None: halfWindow = 2 if max_circle_num == None: max_circle_num = 6 min_center_dist_square = min_center_dist**2 sobel_kernel_y = np.array([[-1.0, -2.0, -1.0], [0.0, 0.0, 0.0], [1.0, 2.0, 1.0]]) sobel_kernel_x = np.array([[-1.0, 0.0, 1.0], [-2.0, 0.0, 2.0], [-1.0, 0.0, 1.0]]) edge_x = convolve(sobel_kernel_x,edge,[1,1,1,1],[1,1]) edge_y = convolve(sobel_kernel_y,edge,[1,1,1,1],[1,1]) center_accumulator = np.zeros((int(np.ceil(center_axis_scale*edge.shape[0])),int(np.ceil(center_axis_scale*edge.shape[1])))) k = np.array([[r for c in range(center_accumulator.shape[1])] for r in range(center_accumulator.shape[0])]) l = np.array([[c for c in range(center_accumulator.shape[1])] for r in range(center_accumulator.shape[0])]) minRad_square = minRad**2 maxRad_square = maxRad**2 points = [[],[]] edge_x_pad = np.pad(edge_x,((1,1),(1,1)),'constant') edge_y_pad = np.pad(edge_y,((1,1),(1,1)),'constant') Gaussian_filter_3 = 1.0 / 16 * np.array([(1.0, 2.0, 1.0), (2.0, 4.0, 2.0), (1.0, 2.0, 1.0)]) for i in range(edge.shape[0]): for j in range(edge.shape[1]): if not edge[i,j] == 0: dx_neibor = edge_x_pad[i:i+3,j:j+3] dy_neibor = edge_y_pad[i:i+3,j:j+3] dx = (dx_neibor*Gaussian_filter_3).sum() dy = (dy_neibor*Gaussian_filter_3).sum() if not (dx == 0 and dy == 0): t1 = (k/center_axis_scale-i) t2 = (l/center_axis_scale-j) t3 = t1**2 + t2**2 temp = (t3 > minRad_square)&(t3 < maxRad_square)&(np.abs(dx*t1-dy*t2) < 1e-4) center_accumulator[temp] += 1 points[0].append(i) points[1].append(j) M = center_accumulator.mean() for i in range(center_accumulator.shape[0]): for j in range(center_accumulator.shape[1]): neibor = \ center_accumulator[max(0, i - halfWindow + 1):min(i + halfWindow, center_accumulator.shape[0]), max(0, j - halfWindow + 1):min(j + halfWindow, center_accumulator.shape[1])] if not (center_accumulator[i,j] >= neibor).all(): center_accumulator[i,j] = 0 # 非極大值抑制 plt.imshow(center_accumulator,cmap='gray') plt.axis('off') plt.show() center_threshold = M * center_threhold_factor possible_centers = np.array(np.where(center_accumulator > center_threshold)) # 閾值化 sort_centers = [] for i in range(possible_centers.shape[1]): sort_centers.append([]) sort_centers[-1].append(possible_centers[0,i]) sort_centers[-1].append(possible_centers[1,i]) sort_centers[-1].append(center_accumulator[sort_centers[-1][0],sort_centers[-1][1]]) sort_centers.sort(key=lambda x:x[2],reverse=True) centers = [[],[],[]] points = np.array(points) for i in range(len(sort_centers)): radius_accumulator = np.zeros( (int(np.ceil(radius_scale * min(maxRad, np.sqrt(edge.shape[0] ** 2 + edge.shape[1] ** 2)) + 1))),dtype=np.float32) if not len(centers[0]) < max_circle_num: break iscenter = True for j in range(len(centers[0])): d1 = sort_centers[i][0]/center_axis_scale - centers[0][j] d2 = sort_centers[i][1]/center_axis_scale - centers[1][j] if d1**2 + d2**2 < min_center_dist_square: iscenter = False break if not iscenter: continue temp = np.sqrt((points[0,:] - sort_centers[i][0] / center_axis_scale) ** 2 + (points[1,:] - sort_centers[i][1] / center_axis_scale) ** 2) temp2 = (temp > minRad) & (temp < maxRad) temp = (np.round(radius_scale * temp)).astype(np.int32) for j in range(temp.shape[0]): if temp2[j]: radius_accumulator[temp[j]] += 1 for j in range(radius_accumulator.shape[0]): if j == 0 or j == 1: continue if not radius_accumulator[j] == 0: radius_accumulator[j] = radius_accumulator[j]*radius_scale/np.log(j) #radius_accumulator[j]*radius_scale/j score_i = radius_accumulator.argmax(axis=-1) if radius_accumulator[score_i] < score_threhold: iscenter = False if iscenter: centers[0].append(sort_centers[i][0]/center_axis_scale) centers[1].append(sort_centers[i][1]/center_axis_scale) centers[2].append(score_i/radius_scale) centers = np.array(centers) centers = centers.astype(np.float64) return centers
代碼效果
到此這篇關(guān)于Python圖像處理之Hough圓形檢測(cè)的文章就介紹到這了,更多相關(guān)Python圓形檢測(cè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)App自動(dòng)簽到領(lǐng)取積分功能
這篇文章主要介紹了Python實(shí)現(xiàn)App自動(dòng)簽到領(lǐng)取積分功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09PYQT5設(shè)置textEdit自動(dòng)滾屏的方法
今天小編就為大家分享一篇PYQT5設(shè)置textEdit自動(dòng)滾屏的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-06-06Python Tkinter Entry和Text的添加與使用詳解
這篇文章主要介紹了Python Tkinter Entry和Text的添加與使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03python使用opencv驅(qū)動(dòng)攝像頭的方法
今天小編就為大家分享一篇python使用opencv驅(qū)動(dòng)攝像頭的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08Python基礎(chǔ) while循環(huán)與break、continue關(guān)鍵字
今天再帶著大家講述一下while循環(huán)。那么for循環(huán)和while循環(huán),到底有什么區(qū)別呢?下面文章就來(lái)詳細(xì)介紹,感興趣的小伙伴可以參考一下2021-10-10Python按照l(shuí)ist dict key進(jìn)行排序過(guò)程解析
這篇文章主要介紹了Python按照l(shuí)ist dict key進(jìn)行排序過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Python通過(guò)命令提示符安裝matplotlib
這篇文章主要給大家介紹了關(guān)于Python通過(guò)命令提示符安裝matplotlib的相關(guān)資料,文中還介紹了離線安裝這一種方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-11-11Python使用pytorch動(dòng)手實(shí)現(xiàn)LSTM模塊
這篇文章主要介紹了Python使用pytorch動(dòng)手實(shí)現(xiàn)LSTM模塊,LSTM是RNN中一個(gè)較為流行的網(wǎng)絡(luò)模塊。主要包括輸入,輸入門,輸出門,遺忘門,激活函數(shù),全連接層(Cell)和輸出2022-07-07