web-dev-qa-db-ja.com

輪郭内の領域を取得しますOpencvPython?

以下のような画像を作成するために、適応しきい値処理手法を使用しました。

enter image description here

私が使用したコードは次のとおりです。

image = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 45, 0)

次に、このコードを使用して輪郭を取得します。

cnt = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]

私の目標は、外側の輪郭内のすべてのピクセルを使用してマスクを生成することです。そのため、オブジェクト内のすべてのピクセルを白で塗りつぶしたいと思います。これどうやってするの?

以下のコードを試してマスクを作成しましたが、結果のマスクは、適応しきい値を適用した後の画像と変わらないようです。

mask = np.zeros(image.shape[:2], np.uint8)
cv2.drawContours(mask, cnt, -1, 255, -1)
16
user1835351

あなたが持っているものはほとんど正しいです。しきい値処理された画像を見ると、それが機能しない理由は、靴のオブジェクトの画像にギャップがあるためです。具体的には、靴の周囲がすべて接続されていることを期待しているということです。これが発生した場合、最も外部の輪郭(コードが実行していること)を抽出する場合、オブジェクトの外周を表す輪郭は1つだけにする必要があります。輪郭を塗りつぶすと、靴は完全にしっかりしているはずです。

靴の周囲が完全で壊れていないため、白い領域が切断されます。 findContoursを使用してすべての輪郭を検索する場合、白い形状のそれぞれの輪郭のみが検索され、最も外周は検索されません。そのため、findContoursを使用しようとすると、元の画像と同じ結果が得られます。これは、画像内の各白い領域の周囲を見つけて、これらの領域を次のように塗りつぶすだけだからです。 findContours


あなたがする必要があるのは、画像が完全に閉じられていることを確認することです。 morphology を使用して、切断されたすべての領域をまとめて閉じてから、この新しいイメージに対してfindContours呼び出しを実行することをお勧めします。具体的には、バイナリの形態学的クロージングを実行します。これが行うことは、互いに接近している切断された白い領域を取り、それらが接続されていることを確認することです。形態学的な閉鎖を使用し、おそらく7 x7の正方形の構造要素のようなものを使用して靴を閉じます。この構造化要素は、白い領域が接続されていると見なすための、白い領域間の最小の分離と考えることができます。

そのため、次のようなことを行います。

import numpy as np
import cv2 
image = cv2.imread('...') # Load your image in here
# Your code to threshold
image = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 45, 0)    

# Perform morphology
se = np.ones((7,7), dtype='uint8')
image_close = cv2.morphologyEx(image, cv2.MORPH_CLOSE, se)

# Your code now applied to the closed image
cnt = cv2.findContours(image_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
mask = np.zeros(image.shape[:2], np.uint8)
cv2.drawContours(mask, cnt, -1, 255, -1)

このコードは基本的にしきい値処理された画像を取得し、この画像に形態学的クロージングを適用します。その後、この画像の外部輪郭を見つけて、白で塗りつぶします。 FWIW、しきい値処理された画像をダウンロードして、自分で試しました。これは私があなたのイメージで得るものです:

enter image description here

簡単なアプローチは、前景の穴を閉じて、 cv2.morphologyEx() および_cv2.MORPH_CLOSE_で単一の輪郭を形成することです。

enter image description here

これで外部輪郭が塗りつぶされたので、cv2.findContours()で外側輪郭を見つけ、 cv2.fillPoly() を使用してすべてのピクセルを白で塗りつぶすことができます。

enter image description here

_import cv2

# Load in image, convert to grayscale, and threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Close contour
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)

# Find outer contour and fill with white
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cv2.fillPoly(close, cnts, [255,255,255])

cv2.imshow('close', close)
cv2.waitKey()
_
0
nathancy