Python cv2 中的皮肤检测和背景减法

Skin Detection and Background Subtraction in Python cv2

在过去的几天里,我一直在使用 OpenCV 开发一个手势识别程序 Python。理想情况下,我想要一个像 this video 中所示的系统。我已经通读了视频说明中描述的算法,并且我几乎理解了所有内容。然而,我一直无法复制他在背景减除和肤色检测方面的成功。我所有的尝试最终都变得非常嘈杂 and/or 非常依赖照明,这两者都使我的代码暂时无用。

我试过以下方法:

到目前为止,我还没有成功。我已经能够挑选出一些轮廓,但这些轮廓嘈杂且不稳定(根据框架来来去去)。我应该使用他们的另一种方法吗?

背景减法往往会留下很多重影 images.You 应该从基于 HSV 的皮肤检测开始,以排除非皮肤区域。这将消除背景扣除的需要。

然后你可以应用人脸检测来掩盖你的脸,之后,当你只剩下手部轮廓时,你可以使用 approxPolyDP() 来获得简化的多边形。计算此多边形的力矩和凸度将为您提供手势识别的基础

我写了一个 fingerspelling 解释器应用程序,所以我遇到了您面临的许多健壮性问题。经过几周的实验,我确定了一个包含几种不同方法的解决方案,但最重要的方法是基于颜色的分割。

基于颜色(肤色)的分割可能非常强大,但简单的实现必然缺乏您正在寻找的稳健性。首先,每个人的肤色都不一样。因此,通过其他机制识别基线肤色非常重要。一种方法是使用面部检测器(例如级联分类器)找到主体的面部,然后 "tune" 相应地过滤范围。

我个人使用级联分类器首先找到闭合的拳头形状,然后对 1) 仅包括拳头的紧密边界框和 2) 整个图像之间的 HSV 直方图进行归一化和差分。然后我设置了一个查找 table (LUT),将每个通道的每个值映射到 0 到 255 之间的值,表示像素代表皮肤的概率。

根据我的经验, 提高我的手部跟踪逻辑性能的重要因素是当我想到不丢弃信息时。您可能会想简单地使用一些最佳范围来设置阈值以生成二值图像,但知道一个像素有 40% 的机会是皮肤而另一个像素有 60% 的机会是有价值的。一旦你达到阈值,你所拥有的只是一个 1 和一个 0。

当然,如果您打算使用基于轮廓的姿势分类,则可能需要在某些点设置阈值。但是,如果您真的想构建强大的手势识别软件,您可能需要研究使用 Convolutional Neural Net (CNN) 来执行分类。预测可以非常快速地完成,并且它对背景噪音、翻译等非常稳健...希望这对您有所帮助!

编辑:让我澄清一下我对 "normalizing and differencing the HSV histograms" 的评论。首先,这样做的理由是能够利用 OpenCV 的 LUT (lookup table) 而不是使用基于范围的阈值。 LUT 非常有效,并且比基于范围的阈值化更灵活。例如,假设您想要的色调包含两个不同范围内的值(例如:0-30 和 150-180)。基于 LUT 的方法可以轻松解决这个问题,因为每个单独的值都可以独立映射。

所以一旦你建立了LUT,你只需要对每一帧的HSV图像运行 LUT。这是一个非常有效的解决方案。

就我而言,为了构建 LUT,我采取了以下步骤:

  • 转换为 HSV 颜色 space。
  • 获取拳头周围紧边界框的 ROI。
  • 为 ROI 和整个图像的每个通道构建直方图。
  • 缩小(规范化)完整图像通道直方图,使比例与 ROI 直方图的比例相匹配(即:将每个完整图像直方图乘以 ROI_area/full_image_area)。
  • 从 ROI 直方图中减去(差)完整图像直方图。 (具有较大正值的条目将对应于 ROI 中常见的通道值,而不是完整图像。)
  • 然后我平滑差异直方图以减少噪声和"overfitting"。
  • 最后,我使用 OpenCV 的 normalize 函数和 NORM_MINMAX.
  • 将差异直方图标准化为 0.0 和 1.0 之间的值
  • 然后可以将差异直方图合并在一起以生成 3 通道 LUT。

我个人不会在使用 LUT 后设置阈值。相反,我只是使用结果数据来计算 "center of color mass" 种类,我用它来保持 ROI 以手为中心。然后,我可以将相同的基于 LUT 的值发送到 CNN 进行分类。

请注意,虽然这种方法很适合我的目的,但如果您执行阈值处理,它仍然不会完美;会有一些前景被检测为背景,反之亦然。我结合了一些基于边缘检测的逻辑来帮助减少由米色墙壁(我家常见的故障模式)引起的误报,但现实情况是,如果有一种真正可靠的方法可以从背景中干净地分割出一只手,那么它就非常可靠改变背景和照明条件,我还没有找到它。因此,我的建议是从视觉皮层获取线索,允许来自更高抽象层次的信息帮助滤除噪音。 (换句话说,研究 CNN——它们真的很了不起。)