我该在哪里学习/找到使用OpenCV从Kinect流式传输手势识别的示例?

7
我有Kinect和Windows、MacOSX的驱动程序。是否有使用OpenCV API流式传输来自Kinect的手势识别示例?我正试图在Windows和MacOSX上实现类似于DaVinci原型Xbox Kinect的东西。

这是一个有趣的问题。我认为如果您将问题分解并重新考虑每个问题的选项,那么找到解决方案的机会将更大。您期望从Kinect中获得什么数据?它只是一个需要处理的视频流吗?在这种情况下,这简化为一般手势识别问题--可能是一个非常活跃的研究领域。还是您希望以某种方式利用设备上的手势识别软件?无论哪种情况,与实现链接中演示的人交谈可能是一个很好的起点。 - mpenkov
你能提供C#的源代码吗?这将非常有帮助。 - Rikki
3个回答

15

您链接中的演示似乎并没有使用真正的手势识别。它只是区分两种不同的手部姿态(张开/闭合),这要容易得多,并跟踪手部位置。根据他在演示中握住手的方式(在身体前面,当他们张开时面对kinect),这可能是他正在做的事情。由于您没有明确使用哪种语言,我将在openCV中使用C函数名称,但在其他语言中应该类似。我还假设您能够从kinect获取深度图(如果您使用libfreenect,则可能通过回调函数)。

  1. 根据深度阈值选择仅接近的点(手)。 您可以自己实现,也可以直接使用openCV获取二进制图像(cvThreshold()和CV_THRESH_BINARY)。 显示您在阈值处理后获得的图像,并调整阈值值以适应您的配置(尝试避免靠得太近kinect,因为此区域会产生更多干扰)。

  2. 使用cvFindContour()获取手的轮廓

这是基础。现在您已经有了手的轮廓,取决于您想要做什么,可以采取不同的方向。如果您只想检测手的张开和闭合,您可以尝试:

  1. 使用cvConvexHull2()获取手的凸包

  2. 使用cvConvexityDefect()在轮廓和之前获取的凸包上获取凸性缺陷。

  3. 分析凸缺陷:如果存在大的凸缺陷,则手是张开的(因为手指之间的形状是凹的),否则手是闭合的。

但您还可以进行手指检测!这是我上周做的事情,这不需要太多的努力,可能会提高您的演示效果!一个便宜但相当可靠的方法是:

  1. 使用cvApproxPoly()函数对手部轮廓进行多边形拟合。您需要调整精度参数,以获得尽可能简单的多边形,但不会使手指混在一起(大约15应该很好,但是使用cvDrawContours()在图像上绘制出来以检查结果)。

  2. 分析轮廓以找到锐角凸点。这需要手动完成。这是最棘手的部分,因为:

    • openCV中使用的数据结构可能有些令人困惑。如果您对CvSeq结构感到太烦恼,可以使用cvCvtSeqToArray()。
    • 最后,您需要做一些(基本)数学运算来找到凸角。请记住,您可以使用点积来确定角度有多锐利,并使用向量积区分凸角和凹角。
  3. 现在,您就能发现锐角凸点,也就是手指尖了!

这是一种简单的检测手指的算法,但有许多方法可以改进它。例如,您可以尝试在深度映射上应用中值滤波来“平滑”所有内容,或者尝试使用更准确的多边形逼近,但然后过滤轮廓以合并指尖上太靠近的点,等等。

祝您好运并玩得开心!


0

mage dest = new Image(this.bitmap.Width, this.bitmap.Height); CvInvoke.cvThreshold(src, dest, 220, 300, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY); Bitmap nem1 = new Bitmap(dest.Bitmap); this.bitmap = nem1; Graphics g = Graphics.FromImage(this.bitmap);

创建一个大小和原始图片一样的图像dest; 使用CvInvoke.cvThreshold对src图像进行二值化处理,阈值为220,最大值为300; 将处理后的bitmap包装成Bitmap对象nem1; 将this.bitmap设置为nem1; 从this.bitmap创建Graphics对象g。

                using (MemStorage storage = new MemStorage()) //allocate storage for contour approximation
                    for (Contour<Point> contours = dest.FindContours(); contours != null; contours = contours.HNext)
                    {
                        g.DrawRectangle(new Pen(new SolidBrush(Color.Green)),contours.BoundingRectangle);
                       // CvInvoke.cvConvexHull2(contours,, Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE, 0);
                        IntPtr seq = CvInvoke.cvConvexHull2(contours,storage.Ptr, Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE, 0);
                       IntPtr defects = CvInvoke.cvConvexityDefects(contours, seq, storage);
                      Seq<Point> tr= contours.GetConvexHull(Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE);

                      Seq<Emgu.CV.Structure.MCvConvexityDefect> te = contours.GetConvexityDefacts(storage, Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE);
                      g.DrawRectangle(new Pen(new SolidBrush(Color.Green)), tr.BoundingRectangle);
                      //g.DrawRectangle(new Pen(new SolidBrush(Color.Green)), te.BoundingRectangle);

                    }

我按照你的算法做了,但它不起作用。出了什么问题?


-1

我认为这不会那么简单,主要是因为Kinect的深度图像数据并不是很敏感。因此,在1米到1.5米的距离之后,所有的手指都会合并在一起,因此您将无法获得清晰的轮廓来检测手指。


2
在1.5米的距离下,我仍然可以看到我的Kinect上的手指。此外,请注意,OP分享的视频中演示者比这更近。最后,这如何回答问题? - Jules Olléon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接