教程匯總:python基礎入門系列
假設有這樣一個任務,通過顯微鏡拍下的某藻類細胞的玻片圖,需要統計圖中細胞個數,如果每天都要人工處理這項作業,那么將會浪費大量的時間與人力,我們既然學習了python那么自然可以想辦法自動化高效率(偷懶)的完成這項任務,顯微鏡下藻類細胞圖如下:

影像預處理
這種圖是必須要進行處理過的,濾除掉無關多余資訊才能更有針對性的進行細胞檢測任務,首先想到的便是灰度,二值化處理,上代碼:
import cv2
src=cv2.imread('cell0.jpg')
# 鑒于后續的影像處理操作可能會破壞原圖,我們這里另拷貝一份src來用
img = src.copy()
# 轉灰度圖
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 均值模糊,除去噪音
gray = cv2.blur(gray, (2, 2))
# 二值化
retval,threshold = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
cv2.imshow("gray", gray)
cv2.imshow("threshold", threshold)
cv2.waitKey(0)
cv2.destroyAllWindows()
處理結果如下圖:

物體輪廓檢測
代表細胞的黑點已經處理出來了,那么就要進行輪廓檢測與統計了,這里我們會用到cv2.findContours()函式來查找檢測物體的輪廓,需要注意的是cv2.findContours()函式接受的引數為二值圖,即黑白的(不是灰度圖),所以使用該方法前二值化處理是比不可少的,在之前二值化處理代碼基礎上增加輪廓檢測代碼:
contours,hierarchy = cv2.findContours(threshold,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
注意,findcontours函式會“原地”修改輸入的影像,這一點可通過下面的陳述句驗證:
cv2.imshow("threshold", threshold)
contours,hierarchy = cv2.findContours(threshold,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow("threshold2", threshold)
cv2.findContours()函式
函式的原型為
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
opencv2回傳兩個值:contours,hierarchy,注:opencv3會回傳三個值,分別是img, countours, hierarchy
引數
-
第一個引數是尋找輪廓的影像;
-
第二個引數表示輪廓的檢索模式,有四種(本文介紹的都是新的cv2介面):
cv2.RETR_EXTERNAL 表示只檢測外輪廓
cv2.RETR_LIST 檢測的輪廓不建立等級關系
cv2.RETR_CCOMP 建立兩個等級的輪廓,上面的一層為外邊界,里面的一層為內孔的邊界資訊,如果內孔內還有一個連通物體,這個物體的邊界也在頂層,
cv2.RETR_TREE 建立一個等級樹結構的輪廓, -
第三個引數method為輪廓的近似辦法
cv2.CHAIN_APPROX_NONE 存盤所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE 壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點坐標,例如一個矩形輪廓只需4個點來保存輪廓資訊
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似演算法
回傳值
cv2.findContours()函式回傳兩個值,一個是輪廓本身(contours),還有一個是每條輪廓對應的屬性(hierarchy),
- contours:
我們主要用到第一個回傳值,該引數是一個list,list中每個元素都是影像中的一個輪廓,用numpy中的ndarray表示,這個概念非常重要,在下面drawContours中會看見,通過print (type(contours)) print (type(contours[0])) print (len(contours)) - hierarchy:
此外,該函式還可回傳一個可選的hiararchy結果,這是一個ndarray,其中的元素個數和輪廓個數相同,每個輪廓contours[i]對應4個hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分別表示后一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號,如果沒有對應項,則該值為負數,
通過
可以看出,hierarchy本身包含兩個ndarray,每個ndarray對應一個輪廓,每個輪廓有四個屬性,print (type(hierarchy)) print (hierarchy.ndim) print (hierarchy[0].ndim) print (hierarchy.shape)
輪廓的繪制
我們需要在原圖上繪制出檢測出來的輪廓,方便驗證檢測出來的輪廓是否滿足我們的要求,OpenCV中可以使用cv2.drawContours()函式在影像上繪制輪廓,
函式原型如下:
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
- 第一個引數是指明在哪幅影像上繪制輪廓;
- 第二個引數是輪廓本身,在Python中是一個list,
- 第三個引數指定繪制輪廓list中的哪條輪廓,如果是-1,則繪制其中的所有輪廓,后面的引數很簡單,其中thickness表明輪廓線的寬度,如果是-1(cv2.FILLED),則為填充模式,繪制引數將在以后獨立詳細介紹,
完整代碼如下:
import cv2
#打開圖片
src=cv2.imread('cell0.jpg')
# 鑒于后續的影像處理操作可能會破壞原圖,我們這里另拷貝一份src來用
img = src.copy()
# 轉灰度圖
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 均值模糊,除去噪音
gray = cv2.blur(gray, (2, 2))
# 二值化
retval,threshold = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
#輪廓檢測
contours,hierarchy = cv2.findContours(threshold,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
# 標記圓點輪廓
cv2.drawContours(img,contours,-1,(255,0,0,),1)
# 標記圓點序號
n = 0
for cnt in contours:
font = cv2.FONT_HERSHEY_PLAIN
cv2.putText(img,str(n+1),(contours[n][0][0][0],contours[n][0][0][1]),font,1,(200,200,0),1,cv2.LINE_AA)
n += 1
# 顯示總個數
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'number:'+str(len(contours)-1),(0,30),font,1,(255,0,0),2,cv2.LINE_AA)
cv2.imshow("source",src)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果如下圖:

自適應閾值優化
上面的處理我們只是用了簡單閾值處理也足夠了,可如果是下面這張圖呢:

可以發現圖中邊緣有大面積深色部分,簡單閾值的話勢必會導致出現誤判,通過前面 三、OpenCV影像的預處理——二值化與自適應閾值的章節學習,我們想到了采用自適應閾值來處理,
只需要上面代碼中二值化處理代碼改為下句:
threshold = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 35)
結果如圖:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/312235.html
標籤:其他
