用OpenCV过滤凸包和凸面缺陷

我遇到了处理数字信号的问题。 我试图检测指尖,类似于这里介绍的解决方案:使用JavaCV的手和手指检测。

不过,我不是使用JavaCV,而是使用Android的OpenCV,这有点不同。 我设法完成了本教程中介绍的所有步骤,但是过滤了凸包和凸面缺陷。 这就是我的形象:

分辨率640x480

这是另一个分辨率的图像:

分辨率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));
        }
    }

结果(白点 - 过滤后的指尖):

在这里输入图像描述

你能帮我写适当的过滤功能吗?

更新14.08.2013

我使用标准openCV函数进行轮廓逼近。 我不得不通过分辨率变化来改变近似值,并且手到相机的距离很难做到。 如果分辨率较小,则手指由较少的像素组成,因此近似值应该是较好的。 与距离相同。 保持高度会导致完全失去手指。 所以我认为近似不是很好的解决问题的方法,但是小的值可能有助于加速计算:

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

如果我使用较高的值,那么结果就像下面的图片,只有在距离和分辨率不会改变的情况下才是好的。 此外,我很惊讶,船体点和缺陷点的默认方法没有有用的参数来传递(最小角度,距离等)...

下图显示了我希望始终实现的效果,与分辨率或手对摄像机的距离无关。 当我闭上手掌时,我也不想看到任何黄色点...

总结一切,我想知道:

  • 如何过滤点
  • 我怎样才能做解决方案和距离独立的近似,将始终工作
  • 如果有人知道或有一些关于OpenCV中使用的数据结构的材料(图形表示,解释),我很乐意阅读它。 (Mat,MatOfInt,MatOfPoint,MatOfPoint2,MatOfPoint4等)
  • 在这里输入图像描述


    低分辨率的凸包可用于识别整个手的位置,但对手指无用,但确实提供了感兴趣的区域和合适的比例。

    然后应该将较高分辨率的分析应用于您的近似轮廓,可以轻松地跳过任何未通过最后两个“长度和角度”标准的点,尽管您可能希望“平均进入”而不是“完全跳过” ”。

    你的代码示例是计算凸性缺陷并将其移除的一个单一过程。这是一个逻辑错误..你需要删除点,因为你去...(一)它更快,更简单地做一切都在一遍( b)它避免了第一次移除点并且不得不稍后添加它们,因为任何移除都​​会改变先前的计算。

    这种基本技术非常简单,适用于基本的手掌。 它本质上并不了解一个手或一个手势,因此调整比例,角度和长度参数只会让你“至今”。

    技术参考:过滤器长度和角度“凸起缺陷”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)Nikos Papamarkos教授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/


    我想你错过了这一点:

    通过利用轮廓的低多边形逼近而不是原始轮廓来加快船体创建和缺陷分析。

    链接地址: http://www.djcxy.com/p/58719.html

    上一篇: filtering convex hulls and convexity defects with OpenCV

    下一篇: Shape context matching in OpenCV