Java 计算机视觉-用OpenCV过滤凸包和凸面缺陷

Java 计算机视觉-用OpenCV过滤凸包和凸面缺陷,java,android,opencv,computer-vision,Java,Android,Opencv,Computer Vision,我有处理数字信号的问题。我正在尝试检测指尖,类似于这里介绍的解决方案: 然而,我不是在使用JavaCV,而是在android上使用OpenCV,这有点不同。 我已经设法完成了教程中介绍的所有步骤,但是过滤了凸面外壳和凸面缺陷。我的图像是这样的: 以下是另一分辨率的图像: 正如您可以清楚地看到的,有许多黄点(凸面外壳)和许多红点(凸面缺陷)。有时在两个黄点之间没有红点,这很奇怪(凸包是如何计算的?) 我需要的是创建类似于前面提供的链接中的过滤函数,但使用OpenCV的数据结构 凸面外壳是马蹄鱼

我有处理数字信号的问题。我正在尝试检测指尖,类似于这里介绍的解决方案:

然而,我不是在使用JavaCV,而是在android上使用OpenCV,这有点不同。 我已经设法完成了教程中介绍的所有步骤,但是过滤了凸面外壳和凸面缺陷。我的图像是这样的:

以下是另一分辨率的图像:

正如您可以清楚地看到的,有许多黄点(凸面外壳)和许多红点(凸面缺陷)。有时在两个黄点之间没有红点,这很奇怪(凸包是如何计算的?)

我需要的是创建类似于前面提供的链接中的过滤函数,但使用OpenCV的数据结构

凸面外壳是马蹄鱼的一种。。。 凸性缺陷是马托芬4的一种类型

我还创建了一些额外的数据结构,因为愚蠢的OpenCV使用不同类型的数据,包含相同的数据,使用不同的方法

convexHullMatOfInt = new MatOfInt();
convexHullPointArrayList = new ArrayList<Point>();
convexHullMatOfPoint = new MatOfPoint();
convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();
如果我使用高值,那么结果就像下图所示,只有在距离和分辨率不变的情况下才是好的另外,对于外壳点和缺陷点的默认方法没有可传递的有用参数(最小角度、距离等),我感到非常惊讶。

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

总而言之,我想知道:

  • 如何过滤点
  • 如何使分辨率和距离无关的近似始终有效
  • 如果有人知道或有一些关于OpenCV中使用的数据结构的资料(图形表示、解释),我很乐意阅读。(Mat、MatOfInt、MatOfPoint、MatOfPoint2、MatOfPoint4等)

我想你没有抓住那一点:

通过利用轮廓的低多边形近似,而不是原始轮廓,可以加速船体创建和缺陷分析


低分辨率下的凸包可以用来识别手的整体位置,它对手指没有用处,但提供了感兴趣的区域和适当的比例

然后,应将更高分辨率的分析应用于近似轮廓,可以很容易地跳过后两个中未通过“长度和角度”标准的任何点,尽管您可能希望“平均”,而不是“完全跳过”

您的代码示例是计算凸面缺陷然后删除它们的一次过程。。那是一个逻辑错误。。您需要边走边删除点。。(a) 在一次过程中完成所有操作更快更简单(b)它避免了在第一次过程中删除点,并避免了在以后重新添加点,因为任何删除操作都会更改以前的计算

这项基本技术非常简单,因此适用于基本的开放式手掌。但它本质上并不理解一只手或一个手势,所以调整比例、角度和长度参数只会让你“走得更远”

技术参考: 滤波器长度和角度“凸度缺陷” 西门·安德烈森博客

基于Kinect SDK的C#库,添加了手指方向检测

“自我生长和组织的神经气体”(SGONG) 尼科斯·帕帕马科斯教授

商品
David Holz&Michael Buckwald是“Leap Motion”的创始人

I do approximation(更新后的帖子),但即使这样,结果也不可接受(有时我的指尖上仍然有不止一个点。而且近似大小应该取决于分辨率和手到相机的距离,这很难实现。在这个问题上,我真的需要帮助,你能帮我吗?第一个github页面已关闭。这是报告:
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));
        }
    }
Imgproc.approxPolyDP(frame, frame, 2 , true);