web-dev-qa-db-ja.com

PythonでOpenCVを使用して、等高線境界内のピクセル値にアクセスします

Python 2.7.9でOpenCV 3.0.0を使用しています。背景が静止しているビデオ内のオブジェクトを追跡し、そのプロパティの一部を推定しようとしています。画像内の複数の動いているオブジェクトについて、それらを区別し、ビデオの残りのフレーム全体で個別に追跡できるようにしたいと考えています。

私がそれを行うことができると思った1つの方法は、画像をバイナリに変換し、ブロブ(この場合は追跡されたオブジェクト)の輪郭を取得し、オブジェクト境界の座標を取得することでした。次に、グレースケールイメージのこれらの境界座標に移動し、その境界で囲まれたピクセル強度を取得し、他のフレームでこのカラーグラディエント/ピクセル強度を追跡します。この方法では、2つのオブジェクトを互いに分離しておくことができるため、次のフレームではそれらは新しいオブジェクトと見なされません。

輪郭の境界座標がありますが、その境界内のピクセル強度を取得する方法がわかりません。誰かが私を助けてくれませんか?

ありがとう!

11
Kaya311

私たちのコメントに従って、あなたができることはnumpy配列のリストを作成することです。ここで、各要素は各オブジェクトの輪郭の内部を記述する強度です。具体的には、輪郭ごとに、輪郭の内部を塗りつぶすバイナリマスクを作成し、塗りつぶされたオブジェクトの(x,y)座標を見つけて、画像にインデックスを付けて強度を取得します。

コードの設定方法は正確にはわかりませんが、imgと呼ばれるグレースケールの画像があるとします。 cv2.findContoursはグレースケール画像で機能するため、画像をグレースケールに変換する必要がある場合があります。これで、通常cv2.findContoursを呼び出します:

import cv2
import numpy as np

#... Put your other code here....
#....

# Call if necessary
#img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Call cv2.findContours
contours,_ = cv2.findContours(img, cv2.RETR_LIST, cv2.cv.CV_CHAIN_APPROX_NONE)

contoursは3D numpy配列のリストになりました。各配列のサイズはN x 1 x 2です。ここで、Nは各オブジェクトの輪郭点の総数です。

そのため、次のようにリストを作成できます。

# Initialize empty list
lst_intensities = []

# For each list of contour points...
for i in range(len(contours)):
    # Create a mask image that contains the contour filled in
    cimg = np.zeros_like(img)
    cv2.drawContours(cimg, contours, i, color=255, thickness=-1)

    # Access the image pixels and create a 1D numpy array then add to list
    pts = np.where(cimg == 255)
    lst_intensities.append(img[pts[0], pts[1]])

輪郭ごとに、空白の画像を作成し、この空白の画像にfilled-inの輪郭を描画します。 thicknessパラメータを-1に指定することにより、輪郭が占める領域を埋めることができます。輪郭の内部を255に設定します。その後、 numpy.where を使用して、特定の条件に一致する配列内のすべての行と列の場所を検索します。この例では、255に等しい値を検索します。その後、これらのポイントを使用して画像にインデックスを付け、輪郭の内部にあるピクセル強度を取得します。

lst_intensitiesには、1D numpy配列のリストが含まれています。各要素は、各オブジェクトの輪郭の内部に属する強度を示します。各配列にアクセスするには、単純にlst_intensities[i]を実行します。ここで、iはアクセスする輪郭です。

@rayryengからの回答は素晴らしいです!

私の実装からの小さなことの1つは、np.where()が、行インデックスの配列と列インデックスの配列を含むタプルを返すことです。したがって、pts[0]には画像の高さに対応するrow indicesのリストが含まれ、pts[1]には画像の幅に対応するcolumn indicesのリストが含まれます。 img.shape(rows, cols, channels)を返します。したがって、ndarrayをimgの後ろにスライスするのはimg[pts[0], pts[1]]である必要があると思います。

3
Jundong