python : 輪郭の抽出 Opencv

Opencvを使った輪郭(面積、領域)の抽出についてです。

使う画像は、前に色の抽出で使った、下記画像の

赤丸を抽出する方法でやります。

f:id:Kangkang1981:20200310225956j:plain

まずはモジュールのimport

import cv2 #opencvのインポート

import numpy as np #色フィルターで使うのでこのインポート

色フィルタで赤丸の抽出

frame=cv2.imread('lena_color.jpg')

#赤のフィルター
redLower = np.array([0, 0, 200]) # 抽出する色の下限(BGR)
redUpper = np.array([100, 100, 255]) # 抽出する色の上限(BGR)
red_mask = cv2.inRange(frame, redLower, redUpper) # BGRからマスクを作成
result_red = cv2.bitwise_and(frame, frame, mask=red_mask) # 元画像とマスクを合成

ここの説明は前に一度説明しているので、このリンクをご参照ください。

f:id:Kangkang1981:20200310230554j:plain

輪郭の抽出を行う際は通常1チャンネルの画像(白黒画像)で行うため、

grayの処理をして、その後、二極化を行います。

 

gray画像を作成

gray_red = cv2.cvtColor(result_red, cv2.COLOR_BGR2GRAY)

二極化画像を作成
ret2,th_red = cv2.threshold(gray_red,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

cimg = th_red

f:id:Kangkang1981:20200322220239j:plain

 

輪郭抽出の関数はこれ

contours, hierarchy =cv2.findContours(cimg,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

ついでに何個抽出できたか見ておきます(この場合は2個)

print(len(contours))

#for文でfindContoursの関数で取得したものを一つずつ見ていきます

enumerateというのを使うとインデックスを1つずつ見ていきます。
for i, cnt in enumerate(contours):
# 輪郭の面積を計算する。
   area = cv2.contourArea(cnt)

#範囲を決めてやらないと、ドット1つのものでも抽出してしまうので、
   if area > 100 and area < 10000:

#drawContoursで下記のように指定(書き込む画像、インデックス、インデックス数、色、太さ)
      cv2.drawContours(frame, contours, i, (255,255,255), 2)
      print('contour: {}, area: {}'.format(i, area))

cv2.imwrite('lena_contour.jpg',frame)

f:id:Kangkang1981:20200322220803j:plain

 

全プログラムは下記です。

import cv2
import numpy as np

frame=cv2.imread('lena_color.jpg')

#青のフィルター BGRのBlueのフィルター
blueLower = np.array([150, 0, 0])    # 抽出する色の下限(BGR)
blueUpper = np.array([255, 100, 100])    # 抽出する色の上限(BGR)
blue_mask = cv2.inRange(frame, blueLower, blueUpper) # BGRからマスクを作成
result_blue = cv2.bitwise_and(frame, frame, mask=blue_mask) # 元画像とマスクを合成


#緑のフィルター BGRのGreenのフィルター
greenLower = np.array([0, 150, 0])    # 抽出する色の下限(BGR)
greenUpper = np.array([100, 255, 100])    # 抽出する色の上限(BGR)
green_mask = cv2.inRange(frame, greenLower, greenUpper) # BGRからマスクを作成
result_green = cv2.bitwise_and(frame, frame, mask=green_mask) # 元画像とマスクを合成

#赤のフィルター
redLower = np.array([0, 0, 200])    # 抽出する色の下限(BGR)
redUpper = np.array([100, 100, 255])    # 抽出する色の上限(BGR)
red_mask = cv2.inRange(frame, redLower, redUpper) # BGRからマスクを作成
result_red = cv2.bitwise_and(frame, frame, mask=red_mask) # 元画像とマスクを合成

#gray画像を作成
gray_red = cv2.cvtColor(result_red, cv2.COLOR_BGR2GRAY)
#二極化
ret2,th_red = cv2.threshold(gray_red,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

cimg = th_red

contours, hierarchy = cv2.findContours(cimg,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))

for i, cnt in enumerate(contours):
        # 輪郭の面積を計算する。
        area = cv2.contourArea(cnt)
        # 抽出する範囲を指定
        if area > 100 and area < 10000:
            #frme画像に書き込む
            cv2.drawContours(frame, contours, i, (255,255,255), 2)
            #インデックスNoと面積を確認
            print('contour: {}, area: {}'.format(i, area))

cv2.imshow('lena_red',result_red)
cv2.imshow('th_red',th_red)
cv2.imshow('frame',frame)

cv2.imwrite('lena_th_red.jpg',th_red)
cv2.imwrite('lena_contour.jpg',frame)
            

#キー入力を待つ
cv2.waitKey(0)
#全ての開いたウインドウ閉じる
cv2.destroyAllWindows()

 

 

今までにpythonについて書いた記事はここにリンク を貼ってあります。

興味があればぜひご覧ください。