python opencv轮廓检测_OpenCV 轮廓检测的实现方法
輪廓概述
輪廓可以簡(jiǎn)單認(rèn)為成將連續(xù)的點(diǎn)(連著邊界)連在一起的曲線,具有相同的顏色或者灰度。輪廓在形狀分析和物體的檢測(cè)和識(shí)別中很有用。
為了更加準(zhǔn)確,要使用二值化圖像。在尋找輪廓之前,要進(jìn)行閾值化處理或者 Canny 邊界檢測(cè)。
查找輪廓的函數(shù)會(huì)修改原始圖像。如果你在找到輪廓之后還想使用原始圖像的話,你應(yīng)該將原始圖像存儲(chǔ)到其他變量中。
在 OpenCV 中,查找輪廓就像在黑色背景中超白色物體,要找的物體應(yīng)該是白色而背景應(yīng)該是黑色。
輪廓檢測(cè)的作用:
1.可以檢測(cè)圖圖像或者視頻中物體的輪廓
2.計(jì)算多邊形邊界,形狀逼近和計(jì)算感興趣區(qū)域
先看一個(gè)較為簡(jiǎn)單的輪廓檢測(cè):
import cv2
import numpy as np
# 創(chuàng)建一個(gè)200*200的黑色空白圖像
img = np.zeros((200, 200), dtype=np.uint8)
# 利用numpy數(shù)組在切片上賦值的功能放置一個(gè)白色方塊
img[50:150, 50:150] = 255
# 對(duì)圖像進(jìn)行二值化操作
# threshold(src, thresh, maxval, type, dst=None)
# src是輸入數(shù)組,thresh是閾值的具體值,maxval是type取THRESH_BINARY或者THRESH_BINARY_INV時(shí)的最大值
# type有5種類型,這里取0: THRESH_BINARY ,當(dāng)前點(diǎn)值大于閾值時(shí),取maxval,也就是前一個(gè)參數(shù),否則設(shè)為0
# 該函數(shù)第一個(gè)返回值是閾值的值,第二個(gè)是閾值化后的圖像
ret, thresh = cv2.threshold(img, 127, 255, 0)
# findContours()有三個(gè)參數(shù):輸入圖像,層次類型和輪廓逼近方法
# 該函數(shù)會(huì)修改原圖像,建議使用img.copy()作為輸入
# 由函數(shù)返回的層次樹很重要,cv2.RETR_TREE會(huì)得到圖像中輪廓的整體層次結(jié)構(gòu),以此來建立輪廓之間的‘關(guān)系'。
# 如果只想得到最外面的輪廓,可以使用cv2.RETE_EXTERNAL。這樣可以消除輪廓中其他的輪廓,也就是最大的集合
# 該函數(shù)有三個(gè)返回值:修改后的圖像,圖像的輪廓,它們的層次
image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
img = cv2.drawContours(color, contours, -1, (0, 255, 0), 2)
cv2.imshow("contours", color)
cv2.waitKey()
cv2.destroyAllWindows()
上面是找到一個(gè)正方形的輪廓,下面看如何找到不規(guī)則的多邊形輪廓:
import cv2
import numpy as np
# pyrDown():brief Blurs an image and downsamples it.
# 將圖像高斯平滑,然后進(jìn)行降采樣
img = cv2.pyrDown(cv2.imread("hammer.jpg", cv2.IMREAD_UNCHANGED))
# 依然是二值化操作
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)
# 計(jì)算圖像的輪廓
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# find bounding box coordinates
# 先計(jì)算出一個(gè)簡(jiǎn)單的邊界狂,也就是一個(gè)矩形啦
# 就是將輪廓信息轉(zhuǎn)換為(x,y)坐標(biāo),并加上矩形的高度和寬度
x, y, w, h = cv2.boundingRect(c)
# 畫出該矩形
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
# find minimum area
# 然后計(jì)算包圍目標(biāo)的最小矩形區(qū)域
# 這里先計(jì)算出最小矩形區(qū)域,然后計(jì)算區(qū)域的頂點(diǎn),此時(shí)頂點(diǎn)坐標(biāo)是浮點(diǎn)型,但是像素坐標(biāo)是整數(shù)
# 需要將浮點(diǎn)型轉(zhuǎn)換成矩形
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
# draw contours
# 畫出最小矩形
# drawContours()也會(huì)修改源圖像
# 第二個(gè)參數(shù)保存輪廓的數(shù)組,也就是保存著很多輪廓
# 第三個(gè)參數(shù)是要繪制的輪廓數(shù)組的索引:-1是繪制所有的輪廓,否則只繪制[box]中指定的輪廓
# 顏色和thickness(密度,就是粗細(xì))放在最后兩個(gè)參數(shù)
cv2.drawContours(img, [box], 0, (0, 0, 255), 3)
# calculate center and radius of minimum enclosing circle
# 最后檢查的邊界輪廓為最小閉圓
# minEnclosingCircle()會(huì)返回一個(gè)二元數(shù)組,第一個(gè)是圓心坐標(biāo)組成的元祖,第二個(gè)元素是元的半徑
(x, y), radius = cv2.minEnclosingCircle(c)
# cast to integers
center = (int(x), int(y))
radius = int(radius)
# draw the circle
img = cv2.circle(img, center, radius, (255, 0, 0), 3)
# 繪制輪廓
cv2.drawContours(img, contours, -1, (255, 0, 0), 1)
cv2.imshow("contours", img)
cv2.waitKey()
cv2.destroyAllWindows()
凸輪廓與Douglas-Peucker算法
import cv2
import numpy as np
img = cv2.pyrDown(cv2.imread("hammer.jpg", cv2.IMREAD_UNCHANGED))
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)
# 創(chuàng)建與源圖像一樣大小的矩陣
black = cv2.cvtColor(np.zeros((img.shape[1], img.shape[0]), dtype=np.uint8), cv2.COLOR_GRAY2BGR)
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
# 得到輪廓的周長(zhǎng)作為參考
epsilon = 0.01 * cv2.arcLength(cnt,True)
# approxPolyDP()用來計(jì)算近似的多邊形框。有三個(gè)參數(shù)
# cnt為輪廓,epsilon為ε——表示源輪廓與近似多邊形的最大差值,越小越接近
# 第三個(gè)是布爾標(biāo)記,用來表示這個(gè)多邊形是否閉合
approx = cv2.approxPolyDP(cnt,epsilon,True)
# convexHull()可以從輪廓獲取凸形狀
hull = cv2.convexHull(cnt)
# 源圖像輪廓-綠色
cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2)
# 近似多邊形-藍(lán)色
cv2.drawContours(black, [approx], -1, (255, 0, 0), 2)
# 凸包-紅色
cv2.drawContours(black, [hull], -1, (0, 0, 255), 2)
cv2.imshow("hull", black)
cv2.waitKey()
cv2.destroyAllWindows()
本來也有疑問,有了一個(gè)精確的輪廓,為什么還需要一個(gè)近似的多邊形?
書中給出答案,近似多邊形是由一組直線構(gòu)成,這樣可以便于后續(xù)的操作和處理。
想來也是,直線構(gòu)成的區(qū)域總是比無限個(gè)曲率的曲線構(gòu)成的區(qū)域方便處理。
直線和圓檢測(cè)
直線檢測(cè)可以通過HoughLinesP函數(shù)完成,HoughLinesP是標(biāo)準(zhǔn)Hough變換經(jīng)過優(yōu)化,使用概率Hough變換。
import cv2
import numpy as np
img = cv2.imread('lines.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,120)
# 最小直線長(zhǎng)度,小于該長(zhǎng)度會(huì)被消除
minLineLength = 20
# 最大線段間隙,一條直線的間隙長(zhǎng)度大于這個(gè)值會(huì)被認(rèn)為是兩條直線
maxLineGap = 5
# HoughLinesP()會(huì)接受一個(gè)由Canny邊緣檢測(cè)濾波器處理過的單通道二值圖像
# 不一定需要Canny濾波器,但是輸入是去噪且只有邊緣的圖像,效果會(huì)很好
# 第一個(gè)參數(shù)是輸入圖像
# 第二、第三個(gè)參數(shù)是線段的幾何表示rho和theta,一般取1和np.pi/180
# 第四個(gè)參數(shù)是閾值,低于該閾值的直線會(huì)被忽略
# 第五第六已經(jīng)解釋
lines = cv2.HoughLinesP(edges,1,np.pi/180,20,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imshow("edges", edges)
cv2.imshow("lines", img)
cv2.waitKey()
cv2.destroyAllWindows()
圓檢測(cè)可以通過HoughCircles函數(shù)檢測(cè)。
import cv2
import numpy as np
planets = cv2.imread('planet_glow.jpg')
gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray_img, 5)
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# 與直線檢測(cè)類似,需要圓心距的最小距離和圓的最小以及最大半徑
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,120,param1=100,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)
cv2.imwrite("planets_circles.jpg", planets)
cv2.imshow("HoughCirlces", planets)
cv2.waitKey()
cv2.destroyAllWindows()
有一個(gè)問題,該方法檢測(cè)出來的第二行的第一個(gè)星球的圓檢測(cè)與書中不一樣。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
總結(jié)
以上是生活随笔為你收集整理的python opencv轮廓检测_OpenCV 轮廓检测的实现方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两步路轨迹文件位置_最新Uber ATG
- 下一篇: linux管理外部工具,linux –