您链接中的演示似乎并没有使用真正的手势识别。它只是区分两种不同的手部姿态(张开/闭合),这要容易得多,并跟踪手部位置。根据他在演示中握住手的方式(在身体前面,当他们张开时面对kinect),这可能是他正在做的事情。由于您没有明确使用哪种语言,我将在openCV中使用C函数名称,但在其他语言中应该类似。我还假设您能够从kinect获取深度图(如果您使用libfreenect,则可能通过回调函数)。
根据深度阈值选择仅接近的点(手)。 您可以自己实现,也可以直接使用openCV获取二进制图像(cvThreshold()和CV_THRESH_BINARY)。 显示您在阈值处理后获得的图像,并调整阈值值以适应您的配置(尝试避免靠得太近kinect,因为此区域会产生更多干扰)。
使用cvFindContour()获取手的轮廓
这是基础。现在您已经有了手的轮廓,取决于您想要做什么,可以采取不同的方向。如果您只想检测手的张开和闭合,您可以尝试:
使用cvConvexHull2()获取手的凸包
使用cvConvexityDefect()在轮廓和之前获取的凸包上获取凸性缺陷。
分析凸缺陷:如果存在大的凸缺陷,则手是张开的(因为手指之间的形状是凹的),否则手是闭合的。
但您还可以进行手指检测!这是我上周做的事情,这不需要太多的努力,可能会提高您的演示效果!一个便宜但相当可靠的方法是:
使用cvApproxPoly()函数对手部轮廓进行多边形拟合。您需要调整精度参数,以获得尽可能简单的多边形,但不会使手指混在一起(大约15应该很好,但是使用cvDrawContours()在图像上绘制出来以检查结果)。
分析轮廓以找到锐角凸点。这需要手动完成。这是最棘手的部分,因为:
现在,您就能发现锐角凸点,也就是手指尖了!
这是一种简单的检测手指的算法,但有许多方法可以改进它。例如,您可以尝试在深度映射上应用中值滤波来“平滑”所有内容,或者尝试使用更准确的多边形逼近,但然后过滤轮廓以合并指尖上太靠近的点,等等。
祝您好运并玩得开心!
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);
}
我按照你的算法做了,但它不起作用。出了什么问题?
我认为这不会那么简单,主要是因为Kinect的深度图像数据并不是很敏感。因此,在1米到1.5米的距离之后,所有的手指都会合并在一起,因此您将无法获得清晰的轮廓来检测手指。