我写了一个手指拼写 https://en.wikipedia.org/wiki/Fingerspelling解释器应用程序,所以我遇到了您面临的许多稳健性问题。经过几周的实验,我确定了一个包含几种不同方法的解决方案,但采用的最重要的方法是基于颜色的分割。
基于颜色(肤色)的分割可能非常强大,但过于简单的实现必然缺乏您所寻求的稳健性。首先,每个人的肤色不同。因此,通过其他机制来识别基线肤色非常重要。一种方法是使用面部检测器(例如级联分类器)来查找主体的面部,然后相应地“调整”滤波器范围。
我个人使用级联分类器首先找到闭合的拳头形状,然后对 1)仅包括拳头的紧密边界框和 2)整个图像之间的 HSV 直方图进行归一化和差分。然后,我设置一个查找表 (LUT),将每个通道的每个值映射到 0 到 255 之间的值,表示像素代表皮肤的概率。
根据我的经验,most提高我的手部追踪逻辑性能的一个重要因素是当我想到不丢弃信息的想法时。您可能会想简单地使用一些最佳范围来设置阈值以生成二值图像,但了解一个像素有 40% 的机会是皮肤而另一个像素有 60% 的机会是有价值的。一旦达到阈值,您所拥有的就只有 1 和 0。
当然,如果您打算使用基于轮廓的姿势分类,则可能需要在某个点进行阈值处理。但如果您确实想构建强大的手势识别软件,您可能需要使用卷积神经网络 (CNN) https://en.wikipedia.org/wiki/Convolutional_neural_network来执行分类。预测可以非常快地完成,并且它对背景噪声、翻译等非常鲁棒......希望这有帮助!
编辑:让我澄清一下我关于“标准化和区分 HSV 直方图”的评论。首先,这样做的理由是能够利用OpenCV的LUT(查找表) http://docs.opencv.org/2.4.11/modules/core/doc/operations_on_arrays.html#lut而不是使用基于范围的阈值。LUT
非常高效,并且比基于范围的阈值更灵活。例如,假设您想要的色调包含两个不同范围内的值(例如:0-30 和 150-180)。基于 LUT 的方法可以轻松处理这个问题,因为每个单独的值都可以独立映射。
所以一旦你建立了LUT,你只需要运行LUT
在每帧的 HSV 图像上。这是一个非常有效的解决方案。
就我而言,为了构建 LUT,我采取了以下步骤:
- 转换为 HSV 颜色空间。
- 获取拳头周围紧密边界框的投资回报率。
- 为 ROI 和整个图像的每个通道构建直方图。
- 缩小(标准化)完整图像通道直方图,以便比例与 ROI 直方图相匹配(即:将每个完整图像直方图乘以 ROI_area/full_image_area)。
- 从 ROI 直方图中减去(差值)完整图像直方图。 (具有较大正值的条目将对应于 ROI 中常见的通道值,但不是完整图像。)
- 然后,我平滑差异直方图以减少噪声和“过度拟合”。
- 最后,我使用 OpenCV 将差异直方图标准化为 0.0 和 1.0 之间的值
normalize
功能与NORM_MINMAX
.
- 然后可以将差异直方图合并在一起以生成 3 通道 LUT。
我个人在使用 LUT 后不会对值进行阈值设置。相反,我只是使用结果数据来计算“颜色质量中心”,我用它来保持 ROI 以手为中心。然后,我可以将相同的基于 LUT 的值发送到 CNN 进行分类。
请注意,虽然这种方法非常适合我的目的,但如果您执行阈值处理,它仍然不会完美;将会有一些前景被检测为背景,反之亦然。我加入了一些基于边缘检测的逻辑,以帮助减少米色墙壁(我家里常见的故障模式)造成的误报,但现实是,如果有一种真正可靠的方法可以从背景中干净地分割出一只手,那么这种方法就真正可靠改变背景和照明条件,我还没有找到。因此,我的建议是从视觉皮层获取提示,并允许来自更高抽象级别的信息来帮助过滤噪音。 (换句话说,研究一下 CNN——它们真的很了不起。)