web-dev-qa-db-ja.com

輪郭の内部領域をトリミングする方法は?

私は網膜の眼底画像に取り組んでいます。画像は黒い背景に円形の網膜で構成されています。 OpenCVを使用して、円形のRetina全体を囲むコンターを取得できました。私が必要なのは、黒い背景から円形の網膜を切り取ることです。

20
Gaurav Patil

輪郭内で定義されている情報を実際に切り取るのか、選択した輪郭に関連しない情報をマスクで除外するのかは、質問では不明です。両方の状況で何をすべきかを探ります。


情報を隠す

画像に対して cv2.findContours を実行したとすると、画像で利用可能なすべての輪郭をリストする構造が得られます。また、必要なオブジェクトを囲むために使用された輪郭のindexを知っていることも前提としています。これがidxに格納されていると仮定すると、最初に cv2.drawContours を使用してfilledバージョンを描画しますこの輪郭を空白の画像に重ね、この画像を使用して画像にインデックスを付け、オブジェクトを抽出します。このロジックmasksは無関係な情報を除外し、選択した輪郭内で定義されている重要な情報のみを保持します。これを行うコードは、画像がimgに保存されているグレースケール画像であるとすると、次のようになります。

import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
# contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x
_, contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]

# Show the output image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

実際にトリミングしたい場合...

画像をcropしたい場合は、輪郭で定義された領域の最小スパン境界ボックスを定義する必要があります。バウンディングボックスの左上隅と右下隅を見つけ、インデックスを使用して必要なものを切り抜くことができます。コードは以前と同じですが、追加のトリミング手順があります。

import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
# contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x
_, contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]

# Now crop
(y, x) = np.where(mask == 255)
(topy, topx) = (np.min(y), np.min(x))
(bottomy, bottomx) = (np.max(y), np.max(x))
out = out[topy:bottomy+1, topx:bottomx+1]

# Show the output image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

トリミングコードは、コンターで定義された領域を抽出するためにマスクを定義するときに、コンターの左上隅を定義する最小の水平座標と垂直座標をさらに見つけるように機能します。同様に、輪郭の左下隅を定義する最大の水平座標と垂直座標を見つけます。次に、これらの座標のインデックスを使用して、実際に必要なものをトリミングします。これは、masked画像でトリミングを実行することに注意してください。これは、最大の輪郭に含まれる情報以外のすべてを削除する画像です。

OpenCV 3.xに関する注意

上記のコードは、OpenCV 2.4.xを使用していることを前提としていることに注意してください。 OpenCV 3.xでは、cv2.drawContoursの定義が変更されていることに注意してください。具体的には、出力は3要素のタプル出力で、最初の画像がソース画像で、他の2つのパラメーターはOpenCV 2.4.xと同じです。したがって、上記のコードのcv2.findContoursステートメントを変更して、最初の出力を無視します。

_, contours, _ = cv2.findContours(...) # Your call to find contours
33
rayryeng