通常提取物體的輪廓時,影像都存在噪聲,提取效果并不理想,如提取下圖的輪廓時,

提取代碼:
import cv2
img = cv2.imread("mouse.png")
cv2.imshow("origin",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary = cv2.threshold(gray,128,255,cv2.THRESH_BINARY)
cv2.imshow("binary",binary)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,contours,-1,(0,0,255),3)
cv2.imshow("result", img)
cv2.waitKey(0)
提取效果:

可以看出存在非常嚴重的噪聲干擾,因此,提取輪廓之前需要過濾噪聲的干擾,
首先,進行對影像進行均值濾波(低通濾波),去除噪聲
blured = cv2.blur(img,(5,5))
cv2.imshow("blur",blured)

使用floodfill來去掉目標周圍的背景,泛洪填充類始于ps的魔棒工具,這里用來清除背景,
mask = np.zeros((h+2, w+2), np.uint8) #掩碼長和寬都比輸入影像多兩個像素點,泛洪填充不會超出掩碼的非零邊緣
#進行泛洪填充
cv2.floodFill(blured, mask, (10,10), (255,255,255), (2,2,2),(3,3,3),8)
cv2.imshow("floodfill", blured)

floodFill函式決議
- img:為待使用泛洪演算法的影像
- mask:為掩碼層,使用掩碼可以規定是在哪個區域使用該演算法,如果是對于完整影像都要使用,則掩碼層大小為原圖行數+2,列數+2.是一個二維的0矩陣,邊緣一圈會在使用演算法是置為1,而只有對于掩碼層上對應為0的位置才能泛洪,所以掩碼層初始化為0矩,【dtype:np.uint8】
- seed:為泛洪演算法的種子點,也是根據該點的像素判斷決定和其相近顏色的像素點,是否被泛洪處理,
- newvalue:是對于泛洪區域新賦的值(B,G,R)
- (loDiff1,loDiff2,loDiff3):是相對于seed種子點像素可以往下的像素值,即seed(B0,G0,R0),泛洪區域下界為(B0-loDiff1,G0-loDiff2,R0-loDiff3)
- (upDiff1,upDiff2,upDiff3):是相對于seed種子點像素可以往上的像素值,即seed(B0,G0,R0),泛洪區域上界為(B0+upDiff1,G0+upDiff2,R0+upDiff3)
- flag:為泛洪演算法的處理模式:
- 低八位 控制演算法的連通性,是以seed點為中心,接著判斷周圍的幾個像素點,再將泛洪區域像素點周圍的幾個像素點進行考慮, 一般為4,8;默認為4
- 中間八位 與掩碼層賦值密切相關,一般使用(255<<8)使中間8位全位1,則值為255,也就是掩碼層對應原圖的泛洪區域的部分被由原來的初值0賦值成255,如果中間8位為0,則賦值為1.
- 高八位 由opencv宏引數指定
- cv2.FLOODFILL_FIXED_RANGE:改變影像,填充newvalue
- cv2.FLOODFILL_MASK_ONLY:不改變原影像,也就是newvalue引數失去作用,而是改變對應區域的掩碼,設為中間八位的值
然后轉換成灰度圖
1 gray = cv2.cvtColor(blured,cv2.COLOR_BGR2GRAY)
2 cv2.imshow("gray", gray)
此時目標影像周圍有寫不光滑,還有一些噪聲,因此進行開閉運算,得到比較光滑的目標
1 #定義結構元素
2 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(50, 50))
3 #開閉運算,先開運算去除背景噪聲,再繼續閉運算填充目標內的孔洞
4 opened = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)
5 closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel)
6 cv2.imshow("closed", closed)
接著轉換成二值圖以便于獲取影像的輪廓
最后進行輪廓提取,抓取到目標
1 #找到輪廓
2 _,contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
3 #繪制輪廓
4 cv2.drawContours(img,contours,-1,(0,0,255),3)
5 #繪制結果
6 cv2.imshow("result", img)
全部代碼:
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread("temp.jpg") #載入影像
h, w = img.shape[:2] #獲取影像的高和寬
cv2.imshow("Origin", img) #顯示原始影像
blured = cv2.blur(img,(5,5)) #進行濾波去掉噪聲
cv2.imshow("Blur", blured) #顯示低通濾波后的影像
mask = np.zeros((h+2, w+2), np.uint8) #掩碼長和寬都比輸入影像多兩個像素點,滿水填充不會超出掩碼的非零邊緣
#進行泛洪填充
cv2.floodFill(blured, mask, (w-1,h-1), (255,255,255), (2,2,2),(3,3,3),8)
cv2.imshow("floodfill", blured)
#得到灰度圖
gray = cv2.cvtColor(blured,cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
#定義結構元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(50, 50))
#開閉運算,先開運算去除背景噪聲,再繼續閉運算填充目標內的孔洞
opened = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel)
cv2.imshow("closed", closed)
#求二值圖
ret, binary = cv2.threshold(closed,250,255,cv2.THRESH_BINARY)
cv2.imshow("binary", binary)
#找到輪廓
_,contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#繪制輪廓
cv2.drawContours(img,contours,-1,(0,0,255),3)
#繪制結果
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/332188.html
標籤:其他
上一篇:python錯誤日志——神秘錯誤
下一篇:常見的transforms
