在極坐標中,圓的表示方式為:
x=x0+rcosθ
y=y0+rsinθ
圓心為(x0,y0),r為半徑,θ為旋轉度數,值范圍為0-359
如果給定圓心點和半徑,則其它點是否在圓上,我們就能檢測出來了。在圖像中,我們將每個非0像素點作為圓心點,以一定的半徑進行檢測,如果有一個點在圓上,我們就對這個圓心累加一次。如果檢測到一個圓,那么這個圓心點就累加到最大,成為峰值。因此,在檢測結果中,一個峰值點,就對應一個圓心點。
霍夫圓檢測的函數:
skimage.transform.hough_circle(image, radius)
radius是一個數組,表示半徑的集合,如[3,4,5,6]
返回一個3維的數組(radius index, M, N), 第一維表示半徑的索引,后面兩維表示圖像的尺寸。
例1:繪制兩個圓形,用霍夫圓變換將它們檢測出來。
import numpy as npimport matplotlib.pyplot as pltfrom skimage import draw,transform,featureimg = np.zeros((250, 250,3), dtype=np.uint8)rr, cc = draw.circle_perimeter(60, 60, 50) #以半徑50畫一個圓rr1, cc1 = draw.circle_perimeter(150, 150, 60) #以半徑60畫一個圓img[cc, rr,:] =255img[cc1, rr1,:] =255fig, (ax0,ax1) = plt.subplots(1,2, figsize=(8, 5))ax0.imshow(img) #顯示原圖ax0.set_title('origin image')hough_radii = np.arange(50, 80, 5) #半徑范圍hough_res =transform.hough_circle(img[:,:,0], hough_radii) #圓變換 centers = [] #保存所有圓心點坐標accums = [] #累積值radii = [] #半徑for radius, h in zip(hough_radii, hough_res): #每一個半徑值,取出其中兩個圓 num_peaks = 2 peaks =feature.peak_local_max(h, num_peaks=num_peaks) #取出峰值 centers.extend(peaks) accums.extend(h[peaks[:, 0], peaks[:, 1]]) radii.extend([radius] * num_peaks)#畫出最接近的圓image =np.copy(img)for idx in np.argsort(accums)[::-1][:2]: center_x, center_y = centers[idx] radius = radii[idx] cx, cy =draw.circle_perimeter(center_y, center_x, radius) image[cy, cx] =(255,0,0)ax1.imshow(image)ax1.set_title('detected image')
結果圖如下:原圖中的圓用白色繪制,檢測出的圓用紅色繪制。
例2,檢測出下圖中存在的硬幣。
import numpy as npimport matplotlib.pyplot as pltfrom skimage import data, color,draw,transform,feature,utilimage = util.img_as_ubyte(data.coins()[0:95, 70:370]) #裁剪原圖片edges =feature.canny(image, sigma=3, low_threshold=10, high_threshold=50) #檢測canny邊緣fig, (ax0,ax1) = plt.subplots(1,2, figsize=(8, 5))ax0.imshow(edges, cmap=plt.cm.gray) #顯示canny邊緣ax0.set_title('original iamge')hough_radii = np.arange(15, 30, 2) #半徑范圍hough_res =transform.hough_circle(edges, hough_radii) #圓變換 centers = [] #保存中心點坐標accums = [] #累積值radii = [] #半徑for radius, h in zip(hough_radii, hough_res): #每一個半徑值,取出其中兩個圓 num_peaks = 2 peaks =feature.peak_local_max(h, num_peaks=num_peaks) #取出峰值 centers.extend(peaks) accums.extend(h[peaks[:, 0], peaks[:, 1]]) radii.extend([radius] * num_peaks)#畫出最接近的5個圓image = color.gray2rgb(image)for idx in np.argsort(accums)[::-1][:5]: center_x, center_y = centers[idx] radius = radii[idx] cx, cy =draw.circle_perimeter(center_y, center_x, radius) image[cy, cx] = (255,0,0)ax1.imshow(image)ax1.set_title('detected image')
新聞熱點
疑難解答