web-dev-qa-db-ja.com

コンピュータービジョン-OpenCVによる凸包と凸欠陥のフィルタリング

デジタル信号の処理に問題があります。ここに提示されているソリューションと同様に、指先を検出しようとしています: JavaCVを使用した手と指の検出

しかし、私はJavaCVを使用していませんが、AndroidのOpenCVを使用しています。これは少し異なります。チュートリアルで提示されているすべてのステップを実行できましたが、凸包と凸欠陥のフィルタリングです。これは私の画像は次のようになります:

Resolution 640x480

これは別の解像度の画像です:

Resolution 320x240

はっきりとわかるように、黄色の点(凸包)が多く、赤色の点(凸効果)も多くあります。 2つの黄色の点の間に赤い点がない場合がありますが、これはかなり奇妙です(どのように凸包を計算するのですか?)

私が必要なのは、以前に提供されたリンクのように、OpenCVのデータ構造を使用して類似のフィルタリング関数を作成することです。

凸包はMatOfIntのタイプです...凸欠陥はMatOfInt4のタイプです...

愚かなOpenCVが同じデータを含む異なるタイプのデータを異なる方法で使用するため、私はいくつかの追加のデータ構造も作成しました...

convexHullMatOfInt = new MatOfInt();
convexHullPointArrayList = new ArrayList<Point>();
convexHullMatOfPoint = new MatOfPoint();
convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();

これが私がこれまでに行ったことですが、うまく機能していません。問題はおそらくデータを間違った方法で変換することです:

凸包と凸欠陥の作成:

public void calculateConvexHulls()
{
    convexHullMatOfInt = new MatOfInt();
    convexHullPointArrayList = new ArrayList<Point>();
    convexHullMatOfPoint = new MatOfPoint();
    convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();

    try {
        //Calculate convex hulls
        if(aproximatedContours.size() > 0)
        {
            Imgproc.convexHull( aproximatedContours.get(0), convexHullMatOfInt, false);

            for(int j=0; j < convexHullMatOfInt.toList().size(); j++)
                convexHullPointArrayList.add(aproximatedContours.get(0).toList().get(convexHullMatOfInt.toList().get(j)));
            convexHullMatOfPoint.fromList(convexHullPointArrayList);
            convexHullMatOfPointArrayList.add(convexHullMatOfPoint);    
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        Log.e("Calculate convex hulls failed.", "Details below");
        e.printStackTrace();
    }
}

public void calculateConvexityDefects()
{
    mConvexityDefectsMatOfInt4 = new MatOfInt4();

    try {
        Imgproc.convexityDefects(aproximatedContours.get(0), convexHullMatOfInt, mConvexityDefectsMatOfInt4);

        if(!mConvexityDefectsMatOfInt4.empty())
        {
            mConvexityDefectsIntArrayList = new int[mConvexityDefectsMatOfInt4.toArray().length];
            mConvexityDefectsIntArrayList = mConvexityDefectsMatOfInt4.toArray();
        }
    } catch (Exception e) {
        Log.e("Calculate convex hulls failed.", "Details below");
        e.printStackTrace();
    }
}

フィルタリング:

public void filterCalculatedPoints()
    {
        ArrayList<Point> tipPts = new ArrayList<Point>();
        ArrayList<Point> foldPts = new ArrayList<Point>();
        ArrayList<Integer> depths = new ArrayList<Integer>();

        fingerTips = new ArrayList<Point>();

        for (int i = 0; i < mConvexityDefectsIntArrayList.length/4; i++)
        {
            tipPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i]));
            tipPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i+1]));
            foldPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i+2]));
            depths.add(mConvexityDefectsIntArrayList[4*i+3]);
        }

        int numPoints = foldPts.size();
        for (int i=0; i < numPoints; i++) {
            if ((depths.get(i).intValue()) < MIN_FINGER_DEPTH)
                continue;

            // look at fold points on either side of a tip
            int pdx = (i == 0) ? (numPoints-1) : (i - 1);
            int sdx = (i == numPoints-1) ? 0 : (i + 1);

            int angle = angleBetween(tipPts.get(i), foldPts.get(pdx), foldPts.get(sdx));
            if (angle >= MAX_FINGER_ANGLE)   // angle between finger and folds too wide
                continue; 

            // this point is probably a fingertip, so add to list
            fingerTips.add(tipPts.get(i));
        }
    }

結果(白い点-フィルタリング後の指先):

enter image description here

フィルタリングのための適切な関数を書くのを手伝ってくれませんか?

2013年8月14日更新

輪郭近似には標準のopenCV関数を使用しています。解像度の変更や手からカメラまでの距離に応じて近似値を変更する必要がありますが、これは非常に困難です。解像度が小さい場合、指はより少ないピクセルで構成されているため、近似値は低いほうがよいでしょう。距離も同じです。高く保つと指が完全に失われます。したがって、問題を解決するには近似は適切なアプローチではないと思いますが、小さい値は計算を高速化するのに役立ちます。

Imgproc.approxPolyDP(frame, frame, 2 , true); 

高い値を使用すると、結果は下の画像のようになります。これは、距離と解像度が変わらない場合にのみ適しています。 また、ハルポイントと欠陥ポイントのデフォルトのメソッドには、渡す最小の引数(最小角度、距離など)がないことにも驚いています...

下の画像は、解像度や手とカメラの距離に関係なく、常に実現したい効果を示しています。また、Palmを閉じるときに黄色のポイントを表示したくない...

すべてを要約すると、私は知りたいです:

  • ポイントをフィルタリングする方法
  • 常に機能する解像度と距離に依存しない近似を行う方法
  • 誰かがOpenCVで使用されているデータ構造についていくつかの資料(グラフィック表現、説明)を知っているか持っている場合、私はそれを読んで喜んでいます。 (Mat、MatOfInt、MatOfPoint、MatOfPoint2、MatOfPoint4など)

enter image description here

46
Marek

低解像度での凸包は、全体として手の位置を特定するために使用できます。指には役立ちませんが、関心領域と適切なスケールを提供します。

次に、より高い解像度の分析を近似輪郭に適用します。最後の2つの「長さと角度」の基準を満たさないポイントをスキップするのは簡単ですが、「完全にスキップする」のではなく「平均化する」こともできます。 」.

コード例は、凸状の欠陥を計算してから削除する1つのパスです..これは論理エラーです..進むにつれてポイントを削除する必要があります..(a)1つのパスですべてを実行する方が速くて簡単です( b)削除すると以前の計算が変更されるため、最初のパスでポイントを削除して後で追加し直す必要がなくなります。

この基本的なテクニックは非常にシンプルなので、基本的なオープンPalmで機能します。ただし、本質的には手やジェスチャーを理解しないため、スケール、角度、長さのパラメーターを調整しても、「これまでのところ」しか得られません。

テクニックへの参照:フィルターの長さと角度の「凸欠陥」Simen Andresenブログ http://simena86.github.io/blog/2013/08/12/hand-tracking-and-recognition-with-opencv/

Kinect SDKベースのC#ライブラリと指方向検出の追加 http://candescentnui.codeplex.com/http://blog.candescent.ch/2011/11/improving-finger-detection .html

「自己成長し組織化された神経ガス」(SGONG)ニコスパパマルコス教授 http://www.papamarkos.gr/uploaded-files/Hand%20gesture%20recognition%20using%20a%20neural%20network%20shape%20fitting %20technique.pdf

「Leap Motion」の創設者である商用製品のDavid HolzとMichael Buckwald http://www.engadget.com/2013/03/11/leap-motion-michael-buckwald-interview/

1
jayprich

あなたはその点を逃したと思います:

オリジナルではなく輪郭の低ポリゴン近似を利用することで、船体の作成と欠陥分析が高速化されます。

0
weeska