web-dev-qa-db-ja.com

OpenCV 2.4での輪郭と境界矩形の処理-python 2.7

私はopenCvとpythonを使用しており、構造解析と形状記述子を扱っています。このブログを見つけました: http://opencvpython.blogspot.it/2012/06 /contours-2-brotherhood.html それは非常に有用であり、黒と白の画像を使用して境界矩形を描画しようとしましたが、動作します。しかし、今、たとえば黄色の画像などから抽出した画像から問題は、白黒画像が均一ではなく、ノイズがあり、コードが形状全体を認識しないなどの問題です。

origianl image

black and white image

final image

そして、これはコードです:

import numpy as np
import cv2

im = cv2.imread('shot.bmp')
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
COLOR_MIN = np.array([20, 80, 80],np.uint8)
COLOR_MAX = np.array([40, 255, 255],np.uint8)
frame_threshed = cv2.inRange(hsv_img, COLOR_MIN, COLOR_MAX)
imgray = frame_threshed
ret,thresh = cv2.threshold(frame_threshed,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[0]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.waitKey()
cv2.destroyAllWindows()
19
Gianfra

元の画像はかなりノイズが多いので、簡単な解決策はcv2.medianBlur()を使用してノイズの一部を削除することです。これにより、元の画像の小さなノイズ領域が削除され、輪郭が1つだけ残ります。コードの最初の数行は次のようになります。

_im = cv2.imread('shot.bmp')
im = cv2.medianBlur(im,5)    # 5 is a fairly small kernel size
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
_

ただし、この方法は、カーネルサイズを手動で指定する必要があるため、最も堅牢ではありません。また、コードの行_cnt=contours[0]_は、対象の輪郭が輪郭のリストのfirであると想定しています。 1つの輪郭のみです。より堅牢な方法は、largest輪郭に興味があると仮定することです。これにより、中程度のノイズでも補正できます。

これを行うには、次の行を追加します。

_# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
_

行の後:

_contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
_

このコードの結果:

_import numpy as np
import cv2

im = cv2.imread('shot.bmp')
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
COLOR_MIN = np.array([20, 80, 80],np.uint8)
COLOR_MAX = np.array([40, 255, 255],np.uint8)
frame_threshed = cv2.inRange(hsv_img, COLOR_MIN, COLOR_MAX)
imgray = frame_threshed
ret,thresh = cv2.threshold(frame_threshed,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.waitKey()
cv2.destroyAllWindows()
_

これらのメソッドは両方とも、正しい境界ボックスで結果を提供します。

Bounding Box Result

N.B。
OpenCV 3.xの時点で、findContours()メソッドは3つの結果を返します( here に見られるように)。したがって、追加の戻り値はのようにキャッチ:

__, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPL‌​E)
_
38
Aurelius