首页 文章

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

提问于
浏览
46

我有处理数字信号的问题 . 我试图检测指尖,类似于此处提供的解决方案:Hand and finger detection using JavaCV .

但是,我没有使用JavaCV而是使用OpenCV for android,这有点不同 . 我已经设法完成了本教程中介绍的所有步骤,但过滤了凸包和凸性缺陷 . 这是我的图像的样子:

Resolution 640x480

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

Resolution 320x240

你可以清楚地看到,有许多黄点(凸壳)和许多红点(凸面效应) . 有时在2个黄点之间没有红点,这很奇怪(如何计算凸包?)

我需要的是创建类似于之前提供的链接的simillar过滤功能,但使用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);

如果我使用高值,那么结果就像下面的图像一样,只有当距离和分辨率不会改变时才会有效 . Also, I am quite surprised that default methods for hulls points and defects points doesn't have useful arguments to pass (min angle, distance etc)...

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

为了总结一切,我想知道:

  • 如何过滤积分

  • 如何才能使分辨率和距离无关近似始终有效

  • 如果有人知道或有一些关于OpenCV中使用的数据结构的材料(图形表示,解释),我很乐意阅读它 . (Mat,MatOfInt,MatOfPoint,MatOfPoint2,MatOfPoint4等)

enter image description here

2 回答

相关问题