python opencv 數米粒

1.介紹

opencv入門之數米粒:給出一幅米粒圖數出圖中米粒數目以及最大米粒位置。在原圖上畫出最大米粒的位置。並輸出最大米粒的面積和最大米粒的周長。使用pycharm編碼,親測功能強大。
米粒分佈原圖

2.思路

首先利用opencv輪廓檢測函數來分別提取每一個米粒,並計算出每個米粒的面積,然後對最大米粒求周長,最後在原圖上標記最大米粒的位置,並且輸出米粒信息。

3.預處理

opencv輪廓檢測函數所需要的圖像爲二值化圖片,所以在進行輪廓檢測前,需要對圖像進行預處理。預處理過程爲:

(1).對圖片進行灰度化:

  • #打開圖片 img=cv2.imread(‘Img/rice.jpg’,0) (-1爲原圖,0爲強制灰度圖,1爲強制彩圖)
  • 灰度化函數gray=cv2.cvtColor(frame,cv2.COLOR_RGB2GRAY)

(2)獲取去背景的米粒圖
利用腐蝕膨脹,對原圖進行5次腐蝕,然後進行5次膨脹,得到背景圖
原圖減去背景圖可以得到去背景的米粒圖

  • 腐蝕:就像土壤侵蝕一樣,這個操作會把前景物體的邊界腐蝕掉(但是前景仍然 是白色)。這是怎麼做到的呢?卷積核沿着圖像滑動,如果與卷積覈對應的原圖 像的所有像素值都是 1,那麼中心元素就保持原來的像素值,否則就變爲零。

import import cv2
import numpy as np

#打開圖片
img=cv2.imread('Img/rice.jpg',0)

#構造模板,5次腐蝕
kernel=np.ones((5,5),np.uint8)#構造5x5卷積核
erosion=cv2.erode(img,kernel,iterations=5)#進行5次腐蝕
  • 膨脹:與腐蝕相反,與卷積覈對應的原圖像的像素值中只要有一個是 1,中心元 素的像素值就是 1。所以這個操作會增加圖像中的白色區域(前景)。一般在去 噪聲時先用腐蝕再用膨脹。因爲腐蝕在去掉白噪聲的同時,也會使前景對象變 小。
dilation=cv2.dilate(erosion,kernel,iterations=5) #進行5次膨脹
  • 獲取去背景的米粒圖
    用原圖減去5次腐蝕,5次膨脹後的背景圖
#原圖減去背景得到米粒形狀
backImg=dilation
rice=img-backImg

去背景米粒效果圖:
去背景

(3)圖像二值化

  • 簡單閾值
    與名字一樣,這種方法非常簡單。但像素值高於閾值時,我們給這個像素 賦予一個新值(可能是白色),否則我們給它賦予另外一種顏色(也許是黑色)。 這個函數就是 cv2.threshhold()。這個函數的第一個參數就是原圖像,原圖 像應該是灰度圖。第二個參數就是用來對像素值進行分類的閾值。第三個參數 就是當像素值高於(有時是小於)閾值時應該被賦予的新的像素值。OpenCV 提供了多種不同的閾值方法,這是有第四個參數來決定的。這些方法包括:
    cv2.THRESH_BINARY
    cv2.THRESH_BINARY_INV
    cv2.THRESH_TOZERO
    cv2.THRESH_TOZERO_INV

  • OSTU全局閾值
    這裏用到到的函數還是 cv2.threshold(),但是需要多傳入一個參數 (flag):cv2.THRESH_OTSU。這時要把閾值設爲 0。然後算法會找到最 優閾值,這個最優閾值就是返回值 retVal。如果不使用 Otsu 二值化,返回的 retVal 值與設定的閾值相等。

#OSTU二值化,th1返回閾值,ret1返回二值化的結果圖像
th1,ret1=cv2.threshold(rice,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

二值化效果圖如下
二值化

4.輪廓分析

輪廓可以簡單認爲成將連續的點(連着邊界)連在一起的曲線,具有相同 的顏色或者灰度。輪廓在形狀分析和物體的檢測和識別中很有用。 python3.x-opencv開發指導用書
(1) 輪廓提取

  • 爲了更加準確,要使用二值化圖像。在尋找輪廓之前,要進行閾值化處理 或者 Canny 邊界檢測。
  • 查找輪廓的函數會修改原始圖像。如果你在找到輪廓之後還想使用原始圖 像的話,你應該將原始圖像存儲到其他變量中。
  • 在 OpenCV 中,查找輪廓就像在黑色背景中超白色物體。你應該記住, 要找的物體應該是白色而背景應該是黑色。

**#輪廓檢測,注意輸出結果應有3個,其他著作上爲2個輸出結果,親測錯誤**
ret1,contours,hierarchy=cv2.findContours(ret1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

(2)輪廓數據

  • 輪廓面積
    輪廓的面積可以使用函數 cv2.contourArea() 計算得到,也可以使用矩 (0 階矩),M[‘m00’]。
cv2.contourArea(cnt)
  • 輪廓周長
    也被稱爲弧長。可以使用函數 cv2.arcLength() 計算得到。這個函數 的第二參數可以用來指定對象的形狀是閉合的(True),還是打開的(一條曲 線)。
cv2.arcLength(cnt,True)

(3)輸出結果
遍歷所有輪廓,比較輪廓數據,得出最大輪廓,並在原圖上標註。
函數 cv2.drawContours() 可以被用來繪製輪廓。它可以根據你提供 的邊界點繪製任何形狀。它的第一個參數是原始圖像,第二個參數是輪廓,一 個 Python 列表。第三個參數是輪廓的索引(在繪製獨立輪廓是很有用,當設 置爲 -1 時繪製所有輪廓)。接下來的參數是輪廓的顏色和厚度等。

#遍歷得到最大面積的米粒
maxC=-1
maxS=-1
for cnt in contours:
    tempS=cv2.contourArea(cnt)
    if maxS<tempS:
        maxS=tempS
        maxC=tempC=cv2.arcLength(cnt,True)
        contour=cnt

#在img中畫出最大面積米粒
cv2.drawContours(img,[contour],-1,(0,0,255,),1)

改變參數可以獲取更好的效果

這裏寫圖片描述


整體代碼

import cv2
import numpy as np

#打開圖片
img=cv2.imread('Img/rice.jpg',0)

#構造模板,5次腐蝕,5次膨脹,得到背景
kernel=np.ones((5,5),np.uint8)
erosion=cv2.erode(img,kernel,iterations=5)
dilation=cv2.dilate(erosion,kernel,iterations=5)

#原圖減去背景得到米粒形狀
backImg=dilation
rice=img-backImg

#OSTU二值化
th1,ret1=cv2.threshold(rice,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

#輪廓檢測
ret1,contours,hierarchy=cv2.findContours(ret1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

#遍歷得到最大面積的米粒
maxC=-1
maxS=-1
for cnt in contours:
    tempS=cv2.contourArea(cnt)
    if maxS<tempS:
        maxS=tempS
        maxC=tempC=cv2.arcLength(cnt,True)
        contour=cnt

#在img中畫出最大面積米粒
cv2.drawContours(img,[contour],-1,(0,0,255,),1)

cv2.imshow('image',rice)
print('面積最大:',maxS)
print('對應米粒周長:',maxC)
cv2.waitKey(0)
cv2.destroyAllWindows()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章