我有适用于 Windows 和 MacOSX 的 Kinect 和驱动程序。是否有使用 OpenCV API 从 Kinect 流式传输的手势识别示例?我试图在 Xbox Kinect 上但在 Windows 和 MacOSX 上实现类似于 DaVinci 原型。
3 回答
您链接中的演示似乎没有使用真正的手势识别。它只是区分两个不同的手位置(打开/关闭),这更容易,并跟踪手的位置。考虑到他在演示中握住双手的方式(在身体前面,当它们打开时面向 kinect),这可能就是他正在做的事情。由于您没有准确说明您使用的是哪种语言,我将在 openCV 中使用 C 函数名称,但它们在其他语言中应该是相似的。我还将假设您能够从 kinect 获取深度图(如果您使用 libfreenect,可能通过回调函数)。
深度阈值仅选择足够接近的点(手)。您可以自己实现,也可以直接使用 openCV 来获得二值图像(带有 CV_THRESH_BINARY 的 cvThreshold())。显示阈值化后获得的图像,并调整阈值以适合您的配置(尽量避免离 kinect 太近,因为该区域干扰较多)。
使用 cvFindContour() 获取手的轮廓
这是基础。现在你有了手的轮廓,根据你想要做什么,你可以采取不同的方向。如果您只想在手打开和关闭之间进行检测,您可以这样做:
使用 cvConvexHull2() 获取手的凸包
使用 cvConvexityDefect() 在轮廓和之前获得的凸包上获取凸性缺陷。
分析凸面缺陷:如果有大的缺陷,手是张开的(因为手指之间的形状是凹的),如果没有,手是闭合的。
但你也可以做手指检测!这就是我上周所做的,不需要更多的努力,并且可能会提升你的演示!一种便宜但非常可靠的方法是:
用多边形近似手部轮廓。在轮廓上使用 cvApproxPoly()。您必须调整准确度参数以使多边形尽可能简单,但不会将手指混合在一起(大约 15 个应该很好,但使用 cvDrawContours() 将其绘制在图像上以检查您获得的内容) .
分析轮廓以找到尖锐的凸角。你必须手动完成。这是最棘手的部分,因为:
- openCV 中使用的数据结构起初可能有点令人困惑。如果您对 CvSeq 结构感到困惑,那么 cvCvtSeqToArray() 可能会有所帮助。
- 你终于可以做一些(基本的)数学来找到凸角。请记住,您可以使用点积来确定角度的锐度,并使用矢量积来区分凸角和凹角。
在这里,尖锐的凸角触手可及!
这是一种检测手指的简单算法,但有很多方法可以增强它。例如,您可以尝试在深度图上应用中值滤波器以“平滑”所有内容,或者尝试使用更准确的多边形近似,然后过滤轮廓以合并要在指尖上关闭的点等.
祝好运并玩得开心点!
mage dest = new Image(this.bitmap.Width, this.bitmap.Height); CvInvoke.cvThreshold(src, dest, 220, 300, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY); 位图 nem1 = 新位图(dest.Bitmap);this.bitmap = nem1; 图形 g = Graphics.FromImage(this.bitmap);
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);
}
我按照你的算法做了,但它不起作用是什么?
我认为不会这么简单,主要是因为来自 kinect 的深度图像数据不是那么敏感。因此,在 1m 到 1.5m 的距离之后,所有手指都将被合并,因此您将无法获得清晰的轮廓来检测手指