Python+Opencv实现多种形状的检测
目錄
- 一、Hough變換是什么?
- 二、Hough變換原理簡介
- 三、Hough變換實現(xiàn)步驟
- 四、Hough變換直線檢測代碼實現(xiàn)及效果展示
- 五、Hough變換圓形檢測代碼實現(xiàn)及效果展示
- 六、基于Hough的橢圓檢測代碼實現(xiàn)及效果展示
- 七、輪廓檢測不同形狀代碼實現(xiàn)及效果展示
- 八、獲取圖像中的黑色形狀塊
- 九、移除圖中的圓和橢圓
- 十、思維擴展
- 參考資料
- 注意事項
一、Hough變換是什么?
??Hough變換是由 P.V.C.Hough提出的一種算法,這種算法可以快速、準確的檢測出圖片中的直線、圓和橢圓等多種形狀。在計算機視覺領(lǐng)域中得到了廣泛的使用。
二、Hough變換原理簡介
??Hough變換是一種特征提取算法,它已經(jīng)被廣泛的應用在機器視覺、圖像分析和影像處理等多個方面。Hough變換的主要用途包括尋找圖像中直線、圓或橢圓等在圖像中的具體位置,其主要的原理是將圖像轉(zhuǎn)換到Hough變換空間中,將直角坐標系中的點轉(zhuǎn)換到極坐標系中,通過數(shù)學關(guān)系的推導,我們可以得到直角坐標系中的直線對應到極坐標系中就是多條曲線的交點,即圖像空間中的直線檢測問題轉(zhuǎn)化到Hough空間就成了檢測曲線的匯集點點的問題。
??Hough變換的基本思想是基于點和線的對偶關(guān)系,圖像空間XY中,所有通過點(x,y)的點所表示的方程為:y=px+q\mathrm{y}=p x+qy=px+q;其中P表示的是直線的斜率,q表示直線的截距,也可以表示為q=?px+yq=-p x+yq=?px+y;如下圖所示,圖像空間中過(xi,yj)\left(x_{i}, y_{j}\right)(xi?,yj?)點的直線方程可以表示成yi=pxi+qy_{i}=p x_{i}+qyi?=pxi?+q;也可以在參數(shù)空間中表示為q=?pxi+yiq=-p x_{i}+y_{i}q=?pxi?+yi?。
??通過上圖我們可以得出圖像空間中共線的點和參數(shù)空間中的相交的線具有一一對應的關(guān)系;參數(shù)空間中相交于同一點的所有直線和圖像空間中貢獻的點相互對應,這就是所謂的點和線之間的對偶關(guān)系。Hough變換就是按照這種關(guān)系來將圖像空間中的檢測問題轉(zhuǎn)變成參數(shù)空間中尋找交叉點,然后在參數(shù)空間中執(zhí)行簡單的累計統(tǒng)計來完成直線的檢測任務(wù)。當直線接近于豎直方向時,此時我們用極坐標方程來表示該直線。具體的方程可以表示為λ=xcos?θ+ysin?θ\lambda=x \cos \theta+y \sin \thetaλ=xcosθ+ysinθ;根據(jù)上式,我們可以得出對于極坐標系中的任意一組點(λ,θ)(\lambda, \theta)(λ,θ)都對應這一條直線,即這里將點和線的對偶關(guān)系轉(zhuǎn)變成了點和正弦曲線的對偶關(guān)系。如下圖所示,圖a表示的是圖像空間中的5個坐標點,它們和圖b中的5條曲線相互對應,θ∈[?90,+90],λ∈[?2N2,+2N2]\theta \in[-90,+90], \quad \lambda \in\left[-\frac{\sqrt{2} N}{2},+\frac{\sqrt{2} N}{2}\right]θ∈[?90,+90],λ∈[?22?N?,+22?N?],其中N表示圖像的寬度。即圖像空間中的的點和參數(shù)空間中的曲線相互對應,圖b中的曲線1、3、5這3條曲線都經(jīng)過K點,對應到圖像空間中表示1、3、5處于同一條直線上面;圖a中的2、3、4這3個點處于同一條直線上,對應于參數(shù)空間中表示它們所對應的曲線2、3、4都通過同一點L。
三、Hough變換實現(xiàn)步驟
- 步驟1-首先建立一個二維數(shù)組,其對應的參數(shù)空間為,這個數(shù)組其實就相當于一個累加器;
- 步驟2-然后使用順序搜索的方式在圖像中的所有目標像素中進行快速的搜索,針對圖像中的每一個像素而言,在參數(shù)空間中根據(jù)式λ=xcos?θ+ysin?θ\lambda=x \cos \theta+y \sin \thetaλ=xcosθ+ysinθ計算出一個對應的位置,在累加器對應的位置上執(zhí)行一次加1操作;
- 步驟3-然后求出累加器中的最大值,也就是參數(shù)空間中的最大值,其對應的位置為(λ′,θ′)\left(\lambda^{\prime}, \theta^{\prime}\right)(λ′,θ′);
- 步驟4-最后將獲得的參數(shù)空間位置(λ′,θ′)\left(\lambda^{\prime}, \theta^{\prime}\right)(λ′,θ′)輸入到式λ=xcos?θ+ysin?θ\lambda=x \cos \theta+y \sin \thetaλ=xcosθ+ysinθ中,從而找到該空間所對應的圖像空間中的直線參數(shù),即我們需要檢測的結(jié)果。
四、Hough變換直線檢測代碼實現(xiàn)及效果展示
# coding=utf-8# 導入python庫 import cv2 import numpy as np import matplotlib.pyplot as plt# 讀取圖片 img = cv2.imread('test3.jpg') # 彩色圖片灰度化 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 執(zhí)行邊緣檢測 edges = cv2.Canny(gray,100,200) # 顯示原始結(jié)果cv2.imwrite('edges.png',edges) cv2.imshow('edge', edges) # plt.subplot(121) # plt.imshow(edges)# 執(zhí)行Hough直線檢測 lines = cv2.HoughLines(edges,1,np.pi/180,160) lines1 = lines[:,0,:] for rho,theta in lines1:a = np.cos(theta)b = np.sin(theta)x0 = a*rhoy0 = b*rhox1 = int(x0 + 1000*(-b))y1 = int(y0 + 1000*(a))x2 = int(x0 - 1000*(-b))y2 = int(y0 - 1000*(a)) cv2.line(img,(x1,y1),(x2,y2),(255,0,0),1)cv2.imwrite('line.png',img) cv2.imshow('line', img) cv2.waitKey(0) cv2.destroyAllWindows() # plt.subplot(122) # plt.imshow(img)
??上圖展示了Hough變換直線檢測的結(jié)果。第1列表示的是原始的輸入圖片;第2列表示的是邊緣檢測的結(jié)果;第3列表示Hough直線檢測結(jié)果。我們可以發(fā)現(xiàn)Hough變換準確的檢測到圖片中的所有直線。需要主要的是用戶需要根據(jù)自己的需要對邊緣檢測的參數(shù)進行調(diào)節(jié)。
五、Hough變換圓形檢測代碼實現(xiàn)及效果展示
# coding=utf-8 # 導入python包 import numpy as np import argparse import cv2# 構(gòu)建并解析參數(shù) ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required = True, help = "Path to the image") args = vars(ap.parse_args())# 讀取彩色圖片 image = cv2.imread(args["image"]) output = image.copy() # 將其轉(zhuǎn)換為灰度圖片 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 應用hough變換進行圓檢測 circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)# 確保至少發(fā)現(xiàn)一個圓 if circles is not None:# 進行取整操作circles = np.round(circles[0, :]).astype("int")# 循環(huán)遍歷所有的坐標和半徑for (x, y, r) in circles:# 繪制結(jié)果cv2.circle(output, (x, y), r, (0, 255, 0), 4)cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)# 顯示結(jié)果cv2.imshow("output", np.hstack([image, output]))cv2.waitKey(0)
??上圖展示了Hough變換圓形檢測的結(jié)果。每一行表示一個測試圖片,第1列表示的是原始的輸入圖片,第2列表示的是Hough檢測的結(jié)果。通過上圖我們可以獲得一些信息,即Hough變換不僅能夠處理簡單的情況,也能很好的處理復雜的情況。需要注意的是用戶需要根據(jù)自己的輸入圖片去調(diào)節(jié)cv2.HoughCircles函數(shù)中的一些關(guān)鍵參數(shù)。
六、基于Hough的橢圓檢測代碼實現(xiàn)及效果展示
# coding=utf-8import matplotlib.pyplot as plt from skimage import data,draw,color,transform,feature#加載圖片,轉(zhuǎn)換成灰度圖并檢測邊緣 image_rgb = data.coffee()[0:220, 160:420] #裁剪原圖像,不然速度非常慢 image_gray = color.rgb2gray(image_rgb) edges = feature.canny(image_gray, sigma=2.0, low_threshold=0.55, high_threshold=0.8)#執(zhí)行橢圓變換 result =transform.hough_ellipse(edges, accuracy=20, threshold=250,min_size=100, max_size=120) result.sort(order='accumulator') #根據(jù)累加器排序#估計橢圓參數(shù) best = list(result[-1]) #排完序后取最后一個 yc, xc, a, b = [int(round(x)) for x in best[1:5]] orientation = best[5]#在原圖上畫出橢圓 cy, cx =draw.ellipse_perimeter(yc, xc, a, b, orientation) image_rgb[cy, cx] = (0, 0, 255) #在原圖中用藍色表示檢測出的橢圓# #分別用白色表示canny邊緣,用紅色表示檢測出的橢圓,進行對比 # edges = color.gray2rgb(edges) # edges[cy, cx] = (250, 0, 0) fig2, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, figsize=(8, 4))ax1.set_title('Original picture') ax1.imshow(image_rgb)ax2.set_title('Detect result') ax2.imshow(edges)plt.show()
??上圖展示了Hough變換橢圓檢測的結(jié)果。第1列表示的是原始的輸入圖片,圖中的藍線表示檢測的結(jié)果;第2列表示檢測的結(jié)果,并將其繪制在一張存在的圖片中。圖中可以看出Hough變換可以很好的檢測出圖片中的橢圓。
七、輪廓檢測不同形狀代碼實現(xiàn)及效果展示
# coding=utf-8 # 導入python包 import cv2# 讀取彩色圖片 img = cv2.imread('rect1.png') # 轉(zhuǎn)換為灰度圖片 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 進行二值化處理 ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)# 尋找輪廓 _,contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 繪制不同的輪廓 draw_img0 = cv2.drawContours(img.copy(),contours,0,(0,255,255),3) draw_img1 = cv2.drawContours(img.copy(),contours,1,(255,0,255),3) draw_img2 = cv2.drawContours(img.copy(),contours,2,(255,255,0),3) draw_img3 = cv2.drawContours(img.copy(), contours, -1, (0, 0, 255), 3)# 打印結(jié)果 print ("contours:類型:",type(contours)) print ("第0 個contours:",type(contours[0])) print ("contours 數(shù)量:",len(contours))print ("contours[0]點的個數(shù):",len(contours[0])) print ("contours[1]點的個數(shù):",len(contours[1]))# 顯示并保存結(jié)果 cv2.imshow("img", img) cv2.imshow("draw_img0", draw_img0) cv2.imshow("draw_img1", draw_img1) cv2.imshow("draw_img2", draw_img2) cv2.imwrite("rect_result.png", draw_img3) cv2.imshow("draw_img3", draw_img3)cv2.waitKey(0) cv2.destroyAllWindows()
??上圖展示了利用輪廓檢測不同形狀的結(jié)果。每一行展示了一個測試圖片,第1列展示的是輸入圖片,第2類展示的是輸出結(jié)果。通過上圖我們可以看到輪廓檢測算法可以準確的檢測到圖中的所有輪廓并準確的將他們繪制出來。這在現(xiàn)實場景中具有很廣泛的應用價值。
八、獲取圖像中的黑色形狀塊
# coding=utf-8 # 導入python包 import numpy as np import argparse import imutils import cv2# 構(gòu)建并解析參數(shù) ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", help = "path to the image file") args = vars(ap.parse_args())# 讀取圖片 image = cv2.imread(args["image"])# 尋找到圖片中的黑色形狀塊 lower = np.array([0, 0, 0]) upper = np.array([15, 15, 15]) shapeMask = cv2.inRange(image, lower, upper)# 在mask中尋找輪廓 cnts = cv2.findContours(shapeMask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) print("I found {} black shapes".format(len(cnts))) cv2.imwrite("Mask.png", shapeMask) cv2.imshow("Mask", shapeMask)# 循環(huán)遍歷所有的輪廓 for c in cnts:# draw the contour and show itcv2.drawContours(image, [c], -1, (0, 255, 0), 2) cv2.imwrite("shape1.png", image) cv2.imshow("Image", image) cv2.waitKey(0)
??上圖展示了使用python+opencv自動檢測到圖像中的黑色形狀塊,第1列表示的是原始的輸入圖片,和代碼中的image對應;第2列表示的是獲取到的掩模,對應于代碼中的shapeMask;第3列表示的是檢測的結(jié)果,對應于代碼中的image。通過上圖我們可以發(fā)現(xiàn)該算法能夠準確的檢測出這些不同的形狀塊。
九、移除圖中的圓和橢圓
# coding=utf-8 # 導入python包 import numpy as np import imutils import cv2def is_contour_bad(c):# 近似輪廓peri = cv2.arcLength(c, True)approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 判斷當前的輪廓是不是矩形return not len(approx) == 4# 首先讀取圖片;然后進行顏色轉(zhuǎn)換;最后進行邊緣檢測 image = cv2.imread("remove.png") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) edged = cv2.Canny(gray, 50, 100) cv2.imshow("Original", image)# 尋找圖中的輪廓并設(shè)置mask cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) mask = np.ones(image.shape[:2], dtype="uint8") * 255# 循環(huán)遍歷所有的輪廓 for c in cnts:# 檢測該輪廓的類型,在新的mask中繪制結(jié)果if is_contour_bad(c):cv2.drawContours(mask, [c], -1, 0, -1)# 移除不滿足條件的輪廓并顯示結(jié)果 image = cv2.bitwise_and(image, image, mask=mask) cv2.imwrite("Mask.png", mask) cv2.imshow("Mask", mask) cv2.imwrite("result.png", image) cv2.imshow("After", image) cv2.waitKey(0)十、思維擴展
??在現(xiàn)實場景中,我們經(jīng)常會遇到檢測圖片中具有不同形狀的目標的任務(wù)。本文主要關(guān)注的是直線、圓、橢圓、三角形等,對于那些不規(guī)則的形狀而言,其實Opencv中已經(jīng)內(nèi)嵌了其它的函數(shù),聰明的你一定可以找到這個函數(shù)完成一些更加復雜的形狀檢測任務(wù)。
參考資料
[1] 參考鏈接
注意事項
[1] 該博客是本人原創(chuàng)博客,如果您對該博客感興趣,想要轉(zhuǎn)載該博客,請與我聯(lián)系(qq郵箱:1575262785@qq.com),我會在第一時間回復大家,謝謝大家的關(guān)注.
[2] 由于個人能力有限,該博客可能存在很多的問題,希望大家能夠提出改進意見。
[3] 如果您在閱讀本博客時遇到不理解的地方,希望您可以聯(lián)系我,我會及時的回復您,和您交流想法和意見,謝謝。
[4] 本文測試的圖片可以通過該鏈接進行下載。網(wǎng)盤鏈接- 提取碼:oluh 。
[5] 本人業(yè)余時間承接各種本科畢設(shè)設(shè)計和各種小項目,包括圖像處理(數(shù)據(jù)挖掘、機器學習、深度學習等)、matlab仿真、python算法及仿真等,有需要的請加QQ:1575262785詳聊!!!
總結(jié)
以上是生活随笔為你收集整理的Python+Opencv实现多种形状的检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UC云怎么提升存储空间
- 下一篇: 微信猎手怎么用?微信猎手使用详细教程