1. 引言
今天我們將重點(diǎn)討論霍夫變換,這是一種非常經(jīng)典的線檢測(cè)的算法,通過(guò)將圖像中的點(diǎn)映射到參數(shù)空間中的線來(lái)實(shí)現(xiàn)。霍夫變換可以檢測(cè)任何方向的線,并且可以在具有大量噪聲的圖像中很好地工作。
閑話少說(shuō),我們直接開(kāi)始吧!
2. 基礎(chǔ)知識(shí)
為了理解霍夫變換的工作原理,首先我們需要了解直線是如何在極坐標(biāo)系中定義的。直線由ρ(距原點(diǎn)的垂直距離)和θ(垂直線與軸線的夾角)來(lái)描述,如下圖所:
因此,該直線的方程式為:
我們可以將其轉(zhuǎn)化下表述形式,得到如下公式:
從上面的方程中,我們可以看出,所有具有相同ρ和θ值的點(diǎn)構(gòu)成一條直線。我們算法的基礎(chǔ)是針對(duì)θ的所有可能值計(jì)算圖像中每個(gè)點(diǎn)的ρ值。
3. 算法原理
霍夫變換的處理步驟如下:
1)首先我們創(chuàng)建一個(gè)參數(shù)空間(又叫做霍夫空間)。參數(shù)空間是ρ和θ的二維矩陣,其中θ的范圍在0–180之間。
2)使用諸如Canny邊緣之類的邊緣檢測(cè)算法檢測(cè)圖像的邊緣之后運(yùn)行該算法。值為255的像素被認(rèn)為是邊緣。
3)接著我們逐像素掃描圖像以找到這些邊緣像素,并通過(guò)使用從0到180的θ值來(lái)計(jì)算每個(gè)像素的ρ。對(duì)于同一直線上的像素,θ和rho的值將是相同的。我們?cè)诨舴蚩臻g中以1的權(quán)重對(duì)其投票。
4)最后,投票超過(guò)一定閾值的ρ和θ的值被視為直線。
代碼處理過(guò)程如下:
def hough(img):
# Create a parameter space
# Here we use a dictionary
H=dict()
# We check for pixels in image which have value more than 0(not black)
co=np.where(img>0)
co=np.array(co).T
for point in co:
for t in range(180):
# Compute rho for theta 0-180
d=point[0]*np.sin(np.deg2rad(t))+point[1]*np.cos(np.deg2rad(t))
d=int(d)
# Compare with the extreme cases for image
if d<int(np.ceil(np.sqrt(np.square(img.shape[0]) + np.square(img.shape[1])))):
if (d,t) in H:
# Upvote
H[(d,t)] += 1
else:
# Create a new vote
H[(d,t)] = 1
return H
4. 算法應(yīng)用
在本文中,我們將檢測(cè)圖像中對(duì)象(書(shū)籍)的角點(diǎn)。這似乎是一項(xiàng)簡(jiǎn)單的任務(wù),然而,它將讓我們深入了解使用霍夫變換檢測(cè)直線的過(guò)程。
4.1 彩色圖到HSV空間
由于直接RGB圖像做這項(xiàng)任務(wù)略有難度,我們不妨將該圖像轉(zhuǎn)換為HSV顏色空間,以便在HSV范圍內(nèi)輕松獲取我們的目標(biāo)。
核心代碼如下:
img = cv2.imread("book.jpeg")
scale_percent = 30 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
# resize image
img = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
得到結(jié)果如下所示:
4.2 高斯模糊
我們應(yīng)用高斯模糊來(lái)平滑圖像中由于噪聲而產(chǎn)生的粗糙邊緣,進(jìn)而可以突出我們圖像中的目標(biāo),代碼如下:
# Apply gaussian blur to he mask
blur = cv2.GaussianBlur(hsv, (9, 9), 3)
結(jié)果如下所示:
4.3 二值化和腐蝕操作
接著我們使用inRange
函數(shù)來(lái)得到二值化圖像。這使我們能夠擺脫圖像中其他周圍的物體。代碼如下:
# Define the color range for the ball (in HSV format)
lower_color = np.array([0, 0, 24],np.uint8)
upper_color = np.array([179, 255, 73],np.uint8)
# Define the kernel size for the morphological operations
kernel_size = 7
# Create a mask for the ball color using cv2.inRange()
mask = cv2.inRange(blur, lower_color, upper_color)
得到結(jié)果如下:
我們觀察上圖,存在或多或少的縫隙,我們不妨使用腐蝕操作來(lái)填補(bǔ)這些縫隙。代碼如下:
# Apply morphological operations to the mask to fill in gaps
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size))
mask = cv2.dilate(mask, kernel,iterations=1)
結(jié)果如下:
4.4 邊緣檢測(cè)
邊緣檢測(cè)canny
主要用于檢測(cè)邊緣。這主要是因?yàn)槟繕?biāo)和周圍背景之間的高對(duì)比度。代碼如下:
# Use canny edges to get the edges of the image mask
edges = cv2.Canny(mask,200, 240, apertureSize=3)
結(jié)果如下圖所示:
4.5 霍夫變換
當(dāng)我們進(jìn)行canny
邊緣檢測(cè)時(shí),我們得到了很多邊緣。因此,當(dāng)我們運(yùn)行霍夫算法時(shí),這些邊為同一條邊貢獻(xiàn)了許多條候選線。為了解決這個(gè)問(wèn)題,我們對(duì)霍夫空間中ρ和θ的相鄰值進(jìn)行聚類,并對(duì)它們的值進(jìn)行平均,得到它們的上投票數(shù)之和。這導(dǎo)致了描繪相同邊緣的線條的合并,代碼如下:
# Get the hough space, sort and select to 20 values
hough_space = dict(sorted(hough(edges).items(), key=lambda item: item[1],reverse=True)[:20])
# Sort the hough space w.r.t rho and theta
sorted_hough_space_unfiltered = dict(sorted(hough_space.items()))
# Get the unique rhoand theta values
unique_=unique(sorted_hough_space_unfiltered)
# Sort according to value and get the top 4 lines
unique_=dict(sorted(unique_.items(), key=lambda item: item[1],reverse=True)[:4])
得到結(jié)果如下:
4.6 計(jì)算角點(diǎn)
根據(jù)在霍夫空間中獲得的直線,我們可以使用線性代數(shù)對(duì)其進(jìn)行角點(diǎn)求解。這可以求出我們兩條直線的交叉點(diǎn),也就是書(shū)的角點(diǎn),代碼如下:
# Create combinations of lines
line_combinations = list(combinations(unique_.items(), 2))
intersection=[]
filter_int=[]
for (key1, value1), (key2, value2) in line_combinations:
try:
# Solve point of intersection of two lines
intersection.append(intersection_point(key1[0],np.deg2rad(key1[1]), key2[0],np.deg2rad(key2[1])))
except:
print("Singular Matrix")
for x,y in intersection:
if x>0 and y>0:
# Get the valid cartesan co ordinates
cv2.circle(img, (x, y), 5, (0, 0, 0), -1)
cv2.putText(img, '{},{}'.format(x,y), (x-10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1)
filter_int.append([x,y])
最終輸出如下圖所示:
5. 總結(jié)
盡管該算法現(xiàn)已集成在各種各樣的圖像處理庫(kù),但本文通過(guò)自己實(shí)現(xiàn)它,我們可以深入了解在創(chuàng)建如此復(fù)雜的算法時(shí)所面臨的挑戰(zhàn)和局限性。
嗯嗯,您學(xué)廢了嘛?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-740211.html
代碼鏈接:戳我文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-740211.html
到了這里,關(guān)于霍夫變換直線檢測(cè)原理和應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!