【笔记】opencv图像轮廓 获得平均灰度值在原图上画轮廓 观察灰度图的分解
調整大小:
image = cv2.resize(image,dst=None,fx=0.5,fy = 0.5,dsize=None) img = cv2.resize(img,dst=None,fx=0.5,fy = 0.5,dsize=None)畫輪廓
獲得平均灰度值的辦法:
**
template = cv2.imread('pl2.jpg') #獲得灰度圖 template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) h, w = template_gray.shape[:2] # template_gray 為灰度圖 m = np.reshape(template_gray, [1, w*h]) mean = m.sum()/(w*h) # 圖像平均灰度值發現使用template_gray.shape[2]會報錯,認為原因應該是灰度圖是二維的,shape只有圖像的尺寸,而無第三個通道數。
reshape函數:
numpy.arange(n).reshape(a, b) 依次生成n個自然數,并且以a行b列的數組形式顯示
mat (or array).reshape(c, -1) 必須是矩陣格式或者數組格式,才能使用 .reshape(c, -1) 函數, 表示將此矩陣或者數組重組,以 c行d列的形式表示
arr.shape # (a,b)
arr.reshape(m,-1) #改變維度為m行、d列 (-1表示列數自動計算,d= ab /m )
arr.reshape(-1,m) #改變維度為d行、m列 (-1表示行數自動計算,d= ab /m )
-1的作用就在此: 自動計算d:d=數組或者矩陣里面所有的元素個數/c, d必須是整數,不然報錯)mat (or array).reshape(c, -1) 必須是矩陣格式或者數組格式,才能使用 .reshape(c, -1) 函數, 表示將此矩陣或者數組重組,以 c行d列的形式表示
arr.shape # (a,b)
arr.reshape(m,-1) #改變維度為m行、d列 (-1表示列數自動計算,d= ab /m )
arr.reshape(-1,m) #改變維度為d行、m列 (-1表示行數自動計算,d= ab /m )
-1的作用就在此: 自動計算d:d=數組或者矩陣里面所有的元素個數/c, d必須是整數,不然報錯)
上面的代碼中reshape的第一個參數為1,可見它將矩陣轉化為一行,輸出m得到:
[[67 68 70 … 86 84 82]]
輸出平均灰度mean:
166.6545988023952
函數cv2.threshold()
這個函數有四個參數,第一個原圖像,第二個進行分類的閾值,第三個是高于(低于)閾值時賦予的新值,第四個是一個方法選擇參數,常用的有:
? cv2.THRESH_BINARY(黑白二值)示閾值的二值化操作,大于閾值使用maxval表示,小于閾值使用0表示
? cv2.THRESH_BINARY_INV(黑白二值反轉)表示閾值的二值化翻轉操作,大于閾值的使用0表示,小于閾值的使用最大值表示
? cv2.THRESH_TRUNC (得到的圖像為多像素值) 表示進行截斷操作,大于閾值的使用閾值表示,小于閾值的不變
? cv2.THRESH_TOZERO 表示進行化零操作,大于閾值的不變,小于閾值的使用0表示
? cv2.THRESH_TOZERO_INV 表示進行化零操作的翻轉,大于閾值的使用0表示,小于閾值的不變
將上面的參數0換成cv2.THRESH_TRUNC之后:
換成cv2.THRESH_BINARY_INV:
可見對于最后輪廓的提取并沒有什么影響。
將第三個參數由原來的255換成100:
255為白色,100為上面的灰色,如果換成0圖片變成一片黑:
即
且可以看到輪廓也沒有被提取出來,可見第三個參數對于結果也很重要。
下面提取輪廓:
# 對模板圖片進行二值化 cv2.imshow("a",template_gray) template_thresh = cv2.threshold(template_gray, mean, 255,0)[1] cv2.imshow('template_thresh', template_thresh)# 輪廓檢測 cv2.RETR_EXTERNAL--檢測外側輪廓 contours, hierarchy = cv2.findContours(template_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # print(contours) # 輪廓繪制 res = cv2.drawContours(template.copy(), contours, -1, (0, 0, 255), 1) cv2.imshow('res', res) cv2.waitKey(0) cv2.destroyAllWindows()cv2.findContours
注意cv2.findContours的返回值現在只有兩個,多寫會報錯。
counters是返回的輪廓
findContours( InputArray image, int mode,int method, Point offset = Point());
第一個參數:
image 8位單通道,所有非0值被處理為1,0值不變,也就是說灰度圖會被自動處理為二值圖,一般都是先處理為二值圖之后再作為參數使用
第二個參數:
RETR_LIST 從解釋的角度來看,這中應是最簡單的。它只是提取所有的輪廓,而不去創建任何父子關系。
RETR_EXTERNAL 如果你選擇這種模式的話,只會返回最外邊的的輪廓,所有的子輪廓都會被忽略掉。
RETR_CCOMP 在這種模式下會返回所有的輪廓并將輪廓分為兩級組織結構。
RETR_TREE 這種模式下會返回所有輪廓,并且創建一個完整的組織結構列表。它甚至會告訴你誰是爺爺,爸爸,兒子,孫子等
注意:后一個輪廓跟父子輪廓無關
第三個參數:
cv2.CHAIN_APPROX_NONE,,表示邊界所有點都會被儲存;而如果設為cv2.CHAIN_APPROX_SIMPLE 會壓縮輪廓,將輪廓上冗余點去掉,比如說四邊形就會只儲存四個角點。
之前上面代碼的運行結果:
將第三個參數cv2.CHAIN_APPROX_SIMPLE改為cv2.CHAIN_APPROX_NONE之后結果:
表示沒有看出什么差別。
返回的第一個參數:返回的輪廓(opencv4中取消了返回的原始圖像)
第二個參數:圖像的拓撲信息(輪廓層次)
該返回值返回的是一組輪廓信息,每個輪廓都是由若干個點所構成的。例如,contours[i]是第i個輪廓(下標從0開始),contours[i][j]是第i個輪廓內的第j個點。
返回值contours的type屬性是list類型,list的每個元素都是圖像的一個輪廓,用Numpy中的ndarray結構表示。
使用如下語句,可以獲取輪廓內第0個輪廓中具體點的位置屬性: print(contours[0])#打印第0個輪廓中的像素點
cv2.drawContours()
cv2.drawContours()被用來繪制輪廓。第一個參數是一張圖片,可以是原圖或者其他。第二個參數是輪廓,也可以說是cv2.findContours()找出來的點集,一個列表。第三個參數是對輪廓(第二個參數)的索引,當需要繪制獨立輪廓時很有用,若要全部繪制可設為-1。接下來的參數是輪廓的顏色和厚度。
(0,0,255)表示的是紅色,如果換成(0, 230, 255),可以看見顏色變成了淡黃
平均灰度值的獲得非常重要,即這句話:
template_thresh = cv2.threshold(template_gray, mean, 255,0)[1]
mean是平均灰度值。如果數值不對,無法提取輪廓,現在換成另一個數字150嘗試一下:(計算出來的數值是166)
可以看到旁邊出現了一些其他的輪廓,即并沒有正確框住輪廓。可見這個值對于結果非常重要。
完整代碼:
實例二:
img = cv2.imread("p7.jpg")gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,newi = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) hire,counters = cv2.findContours(newi,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) res = cv2.drawContours(img,hire,-1,(0,0,255),2) cv2.imshow("i",res)cv2.waitKey()
框矩形:
threshold函數的閾值設置非常重要,這里設置的是210
另一種框矩形法:(不能用平均灰度,否則無法框出矩形)
最小矩形框
img = cv2.imread("pl2.jpg")gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) h, w = gray.shape[:2] # template_gray 為灰度圖 m = np.reshape(gray, [1, w*h]) mean = m.sum()/(w*h) # 圖像平均灰度值 t,newi = cv2.threshold(gray,185,255,cv2.THRESH_BINARY)cv2.imshow("io",newi) hire,counters = cv2.findContours(newi,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) rect = cv2.minAreaRect(hire[0]) print(rect) points = cv2.boxPoints(rect) points = np.int0(points) #取整 image = cv2.drawContours(img,[points],0,(0,0,255),2) cv2.imshow("i",img) cv2.imshow("it",image)
(選圖很重要,不然根本出不來)
由于原圖中本來就有紅色的邊框,故改閾值:
t,newi = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
現在進行凸包操作:
此時能完全剛好框住。如果不設置為0的話會發現沒有全部框住:
遍歷所有輪廓
由于圖有問題,畫的輪廓也有問題
換了一張圖測試,效果好多了:
灰度圖分解
效果:
其中7最接近原始圖像。第七位二進制值在八位二進制值中權值最高,與原圖相關度最高
代碼:
newpic =np.zeros((h,w,8),dtype=np.uint8):用于提取各個位平面的提取矩陣,8表示有8個通道,八個通道分別用來提取灰度圖像的八個位位平面,newpic[:,:,0]用來提取灰度圖像的第0個位平面
mask = h[:,:,i]>0將h中大于0的值處理為邏輯真,h[mask]=255,將h中對應mask中邏輯值為真的位置上的值替換為255
只框超過一定大小的輪廓:
img = cv2.imread("shu.png")gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) h, w = gray.shape[:2] # template_gray 為灰度圖 ret,binaryimg = cv2.threshold(gray,100,255,cv2.THRESH_BINARY) countimg = [] contours,hierarchy = cv2.findContours(binaryimg,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) n = len(contours) for i in range(n):temp = np.zeros(img.shape, np.uint8)countimg.append(temp)if cv2.contourArea(contours[i]) > 20000:countimg[i] = cv2.drawContours(img.copy(),contours,i,(0,0,255),3)cv2.resize(countimg[i],dst=None,fx = 0.5,fy=0.5,dsize=None)cv2.imshow("conter"+str(i),countimg[i])指定hsv范圍框白色物體
試了好多次hsv的值終于框出來了,取值也太難了吧。中途因為取值問題壓根無法獲得邊緣。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6aMVJq1E-1614539904373)(C:\Users\14172\AppData\Roaming\Typora\typora-user-images\image-20210301024314126.png)]
img = cv2.imread("shu.png")gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) h, w = gray.shape[:2] # template_gray 為灰度圖 ret,binaryimg = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV) countimg = [] lowhsv = np.array([0,0,100]) highhsv = np.array([180,40,255]) mask = cv2.inRange(hsv,lowerb=lowhsv,upperb=highhsv) median = cv2.medianBlur(mask,5) cannypic = cv2.Canny(median,30,255) cv2.imshow("f",cannypic) #contours,hierarchy = cv2.findContours(binaryimg,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) contours,hierarchy = cv2.findContours(cannypic,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE) n = len(contours) print(n) for i in range(n):temp = np.zeros(img.shape, np.uint8)countimg.append(temp)if cv2.contourArea(contours[i]) > 10000:countimg[i] = cv2.drawContours(img.copy(),contours,i,(0,0,255),3)countimg[i] = cv2.resize(countimg[i],dst=None,fx = 0.5,fy=0.5,dsize=None)cv2.imshow("conter"+str(i),countimg[i])總結
以上是生活随笔為你收集整理的【笔记】opencv图像轮廓 获得平均灰度值在原图上画轮廓 观察灰度图的分解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【笔记】opencv的python实现·
- 下一篇: 【笔记】opencv图像运算 图像加密