今天,我們將開始由3部分構成的形狀檢測分析系列教程。
通過此係列教程,我們將學到如何:
- 計算輪廓/形狀的中心;
- 僅使用輪廓特徵識別出不同的形狀,如:圓、正方形、長方形、三角形和五角形。
- 標記形狀顏色
儘管今天的內容比較基礎(相對於最近 PyImageSearch 部落格討論的更加高階的概念來說),但是也經常有人問我下邊這個問題:
如何用 Python 和 OpenCV 計算輪廓的中心?
在今天的教程中,我將會回答這個問題。
在以後的教程中,我們將在輪廓知識的基礎上進行影像的形狀識別。
使用 OpenCV 計算輪廓中心
從上圖中,你能看見幾種不同的由圖畫紙裁出的形狀。注意,這些形狀並不完美——矩形不夠方,圓形不夠圓。它們都是先經手工描畫然後再裁出來的,這意味著每種形狀都存在著偏差。
明確了這一點之後,今天教程的目標是:(1)檢測出影像中的每一種形狀的輪廓(2)計算輪廓的中心——也叫形心。
為了達成以上目標,我們需要對影像進行以下預處理:
- 轉換成灰度圖;
- 濾波以減少高頻噪聲,使輪廓檢測更加精確;
- 影像二值化。邊緣檢測和閾值化經常被用於此過程,本教程採用閾值化。
開始寫程式碼之前,請確保你的系統已經安裝了 imutils Python 包[ 譯註:該包為作者開發的一系列用 OpenCV 執行基本影像處理操作的簡便函式]。
1 |
$ pip install imutils |
讓我們繼續!
新建一個檔案,命名為 center_of_shape.py
,然後開始寫程式碼吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# import the necessary packages import argparse import imutils import cv2 # construct the argument parse and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to the input image") args = vars(ap.parse_args()) # load the image, convert it to grayscale, blur it slightly, # and threshold it image = cv2.imread(args["image"]) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] |
第2-4行程式碼匯入必需的包,第7-10行程式碼解析命令列引數。此處只需要一個 --image
引數: 磁碟中待處理影像的路徑。
隨後程式從磁碟載入影像,然後進行預處理,執行灰度變換,5×5 核心的高斯平滑,最後閾值化(14-17行)。
閾值化操作後的輸出如下圖所示
注意閾值化後形狀被表示成黑色背景上的白色前景。
下一步是使用輪廓檢測去定位這些白色區域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# import the necessary packages import argparse import imutils import cv2 # construct the argument parse and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to the input image") args = vars(ap.parse_args()) # load the image, convert it to grayscale, blur it slightly, # and threshold it image = cv2.imread(args["image"]) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] # find contours in the thresholded image cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if imutils.is_cv2() else cnts[1] |
第 20-21 行程式碼呼叫 cv2.findContours
函式,該函式返回影像上每一個白塊對應的邊界點集合(即輪廓)。第22行基於我們使用 OpenCV 2.4 版本還是3.0 版本而取不同的元組值。獲取更多 cv2.findContours
函式返回簽名在不同 OpenCV 版本間的改變,請移步此文。[譯註:OpenCV 2.4 版本的 cv2.findContours
函式返回的是一個二元元組,元組的第一個元素(索引 0)是輪廓列表。而在 OpenCV 3.0 版本中,該函式返回的是一個三元元組,元組的第二個元素(索引 1)才是輪廓列表]
我們已經準備去處理每一條輪廓:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# import the necessary packages import argparse import imutils import cv2 # construct the argument parse and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to the input image") args = vars(ap.parse_args()) # load the image, convert it to grayscale, blur it slightly, # and threshold it image = cv2.imread(args["image"]) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] # find contours in the thresholded image cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if imutils.is_cv2() else cnts[1] # loop over the contours for c in cnts: # compute the center of the contour M = cv2.moments(c) cX = int(M["m10"] / M["m00"]) cY = int(M["m01"] / M["m00"]) # draw the contour and center of the shape on the image cv2.drawContours(image, [c], -1, (0, 255, 0), 2) cv2.circle(image, (cX, cY), 7, (255, 255, 255), -1) cv2.putText(image, "center", (cX - 20, cY - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) # show the image cv2.imshow("Image", image) cv2.waitKey(0) |
第25行開始遍歷輪廓,然後在第27行計算輪廓區域影像的矩。
在計算機視覺和影像處理領域,影像的矩經常被用來描述影像中某個物件的形狀。這些矩描述了形狀的基本統計特徵,包括物件的面積、形心(即物件的中心座標 (x, y)
)、取向連同其他有用的特徵。
我們只對影像的中心感興趣,所以在第28-29行計算輪廓的中心。
隨後,第32-34行完成以下任務:
- 呼叫
cv2.drawContours
函式繪製包圍當前形狀的輪廓; - 在形狀的中心
(cX, cY)
處繪製一個白色的小圓; - 在白色小圓的附近寫上文字
center
。
要執行指令碼,開啟終端然後執行以下命令:
1 |
$ python center_of_shape.py --image shapes_and_colors.png |
執行結果如下圖所示:
注意每一個形狀都被成功地檢測到,然後計算出輪廓中心並繪製在影像上。
總結
在這次教程中,我們學習瞭如何使用 OpenCV 和 Python 去計算輪廓的中心。
此教程是由三部分構成的形狀分析系列教程的第一部分。
在下週的教程中,我們將學習如何識別影像中的形狀。
然後,在兩週以後,我們將學習如何分析每一個形狀的顏色並將其標記在形狀上(即標記“紅”、“綠”、“藍”等等)。
為了確保這些教程寫成的時候您能被通知到,請按照以下形式輸入您的郵箱地址![譯註:原部落格提供程式碼下載和郵件提醒功能。戳我訪問原文。]