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

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

不过,我不是使用JavaCV,但Android的OpenCV略有不同。 我已经设法完成了本教程中提出的所有步骤,但过滤了凸包和凹凸缺陷。 这就是我的形象:

分辨率640x480

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

分辨率320x240

正如你可以清楚地看到的那样,有许多黄点(凸包),还有许多红点(凸起的缺陷)。 有时在2个黄点之间没有红点,这是相当奇怪的(如何计算凸包?)

我需要的是像之前提供的链接创build类似的过滤function,但使用OpenCV的数据结构。

凸包是MatOfInt的types…凸包的缺陷是MatOfInt4的types…

我也创build了一些额外的数据结构,因为愚蠢的OpenCV使用不同types的数据包含相同的数据,在不同的方法…

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

这是我到目前为止所做的,但它不是很好。 问题可能是以错误的方式转换数据:

创build凸包和凸面缺陷:

 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)); } } 

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

在这里输入图像说明

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

更新14.08.2013

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

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

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

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

总结一下,我想知道:

  • 如何过滤点
  • 我怎么能做决议和距离独立近似将永远工作
  • 如果有人知道或有一些关于OpenCV中使用的数据结构的材料(graphics表示,解释),我很乐意阅读。 (Mat,MatOfInt,MatOfPoint,MatOfPoint2,MatOfPoint4等)

在这里输入图像说明

低分辨率的凸包可以用来识别整个手的位置,对于手指没有用处,但确实提供了感兴趣的区域和合适的尺度。

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

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

这个基本的技术是非常简单的,所以适用于一个基本的手掌。 它本质上并不了解一个手或一个手势,所以调整规模,angular度和长度参数只会让你“到目前为止”。

参考技术:filter长度和angular度“凸起缺陷”西门子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/

我想你错过了这一点:

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