OpenCV / C ++は、それらの間の距離に基づいて近くの輪郭を接続します


15

輪郭を接続するかどうかを指定するそれらの間の距離に基づいて、画像内の近くの輪郭を接続する必要があります。

今、同じ問題に関する質問があります/programming/8973017/opencv-c-obj-c-connect-nearby-contoursが、ここで彼はすべての輪郭を単一の輪郭にマージしています。これは欲しくない。このためのopencvの機能はないと思いますが、そのアルゴリズムを提案できます。私のアプリケーションは次のようになります:

私は手を検出しているので、皮膚検出アルゴリズムを使用してそれらを特定しましたが、私の皮膚は白くなく、ひょっとすると肘の輪郭が壊れていることもあります。だから私は近くの輪郭を接続したいがそれらのすべてではない(両方の私の手が輪郭にあるので)(手によって私は肩から手のひらまでを意味するからです)。

さらに、いくつかのエッジ検出を使用することで、手の境界を取得し、この境界内のこのパッチの一部が皮膚として検出されたかどうかを検出すると、この境界内の領域全体が皮膚として検出されますが、これを行う方法がわかりません部。

どんな助けでもありがたいです。前もって感謝します

サンプル画像:

ここに画像の説明を入力してください

この画像では、距離が40ピクセル未満のポイント(8つの接続)を接続したいので、左手を単一の輪郭として取得します

私の目的は、手の輪郭のみを取得することです(他の領域は気にしません)


手であなたは実際に腕を意味します。肌を検出するために使用する色相を調整して、肌の色に合わせることができませんか?
ワスピーター2012年

私はそれを実行し、それは細かい出力を与えます(私の肌が照らされているとき)。したがって、夕方には図のようになります。とにかく、近くのブロブをつなぐ方法があるのではないかと思いました。
Roney Island、


スタック交換へようこそ。SEはフォーラムではありません!これは質問に対する答えではありません。質問について質問がある場合は、コメントとして記入してください。
Dipan Mehta

どのように皮膚を検出しますか?
nkint 2013年

回答:


10

手の速度や正確な輪郭が気にならない場合は、以下が簡単な解決策です。

この方法は次のとおりです。各輪郭を取得して、他の輪郭までの距離を求めます。距離が50未満の場合、それらは近くにあり、それらをまとめます。そうでない場合、それらは異なるものとして配置されます。

したがって、各輪郭までの距離をチェックすることは、時間のかかるプロセスです。数秒かかります。だから、リアルタイムでそれを行うことはできません。

また、輪郭を結合するために、それらを1つのセットに入れ、そのセットの凸包を描画しました。したがって、得られる結果は、実際には手の凸包であり、実際の手ではありません。

以下は、OpenCV-Pythonでのコードの一部です。私は最適化を行っていません。それが機能することを望んでいるだけです。問題が解決した場合は、最適化を行ってください。

import cv2
import numpy as np

def find_if_close(cnt1,cnt2):
    row1,row2 = cnt1.shape[0],cnt2.shape[0]
    for i in xrange(row1):
        for j in xrange(row2):
            dist = np.linalg.norm(cnt1[i]-cnt2[j])
            if abs(dist) < 50 :
                return True
            elif i==row1-1 and j==row2-1:
                return False

img = cv2.imread('dspcnt.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
contours,hier = cv2.findContours(thresh,cv2.RETR_EXTERNAL,2)

LENGTH = len(contours)
status = np.zeros((LENGTH,1))

for i,cnt1 in enumerate(contours):
    x = i    
    if i != LENGTH-1:
        for j,cnt2 in enumerate(contours[i+1:]):
            x = x+1
            dist = find_if_close(cnt1,cnt2)
            if dist == True:
                val = min(status[i],status[x])
                status[x] = status[i] = val
            else:
                if status[x]==status[i]:
                    status[x] = i+1

unified = []
maximum = int(status.max())+1
for i in xrange(maximum):
    pos = np.where(status==i)[0]
    if pos.size != 0:
        cont = np.vstack(contours[i] for i in pos)
        hull = cv2.convexHull(cont)
        unified.append(hull)

cv2.drawContours(img,unified,-1,(0,255,0),2)
cv2.drawContours(thresh,unified,-1,255,-1)

以下は私が得た結果です:

ここに画像の説明を入力してください

ここに画像の説明を入力してください


これはどのようにC ++で実行できますか?私はfindContour部分まで持っていますが、その後、上に示すように(外接する長方形ではなく)輪郭を多角形でラップすることができないようです。
Elionardo Feliciano

私はあなたのアプローチに感謝し、私のケースに適用しようとしましたが、残念ながらそれはPythonでは非常に遅いです(私のラップトップにはCore i7QMと8GB RAMがあります)。MSERを使用して領域を検出し、どの領域のペアが「隣接」しているかを判別する必要があります。しきい値10でアルゴリズムを試してみました...隣接する領域を返すには数年かかります。
ジム・レイナー2014

4

接続の問題を修正するには、閉じる操作を試すことができます。

cv::Mat structuringElement = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(40, 40));
cv::morphologyEx( inputImage, outputImage, cv::MORPH_CLOSE, structuringElement );

これで期待通りの結果が得られるとは思えませんが、試してみることができます。


2

画像を「オーバーセグメンテーション」しているようです。bjnoernzが示唆したように、形態学的操作が役立ちます。特に、ウォーターシェディングのアプローチは、(上記のpythonの例のように)距離をチェックするだけではなく、目的のものに近づく必要があります。http://cmm.ensmp.fr/~beucher/wtshed.htmlを参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.