计算机视觉:遮盖人手

11

我想从实时视频流中检测我的手并创建一个手掩模。然而,我的结果很差,就像你在图片中看到的那样。

我的目标是跟踪手部运动,所以我将视频流从BGR转换为HSV颜色空间,然后进行阈值处理,以隔离手部的颜色,接着尝试查找手部轮廓,但最终结果并不是我想要达到的效果。

我该如何改进最终结果?

import cv2
import numpy as np

cam = cv2.VideoCapture(1)
cam.set(3,640)
cam.set(4,480)
ret, image = cam.read()

skin_min = np.array([0, 40, 150],np.uint8)
skin_max = np.array([20, 150, 255],np.uint8)    
while True:
    ret, image = cam.read()

    gaussian_blur = cv2.GaussianBlur(image,(5,5),0)
    blur_hsv = cv2.cvtColor(gaussian_blur, cv2.COLOR_BGR2HSV)

#threshould using min and max values
    tre_green = cv2.inRange(blur_hsv, skin_min, skin_max)
#getting object green contour
    contours, hierarchy = cv2.findContours(tre_green,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

#draw contours
    cv2.drawContours(image,contours,-1,(0,255,0),3)

    cv2.imshow('real', image)
    cv2.imshow('tre_green', tre_green)   

    key = cv2.waitKey(10)
    if key == 27:
        break

这里是带图片的链接:https://picasaweb.google.com/103610822612915300423/February7201303。 新的链接包含了图片轮廓、mask以及原始图片。 https://picasaweb.google.com/103610822612915300423/February7201304

以下是来自上述内容的样例图片:

一个带有手臂和手部的躯干的样例图片


请包含您遇到问题的示例视频,否则猜测您实际正在处理的内容是毫无意义的。 - mmgp
1
我不能上传图片,因为我没有足够的声望点数:( - wind85
1
只需包含一个链接。并且包含到 /video/ 的链接,而不是单独的帧。 - mmgp
@mmgp 我没有录制,它是即时完成的... - wind85
@user1979084 ... 我告诉你的是要记录它... - mmgp
显示剩余16条评论
2个回答

15

有许多方法可以执行像素级阈值来将“皮肤像素”与“非皮肤像素”分离,基本上任何颜色空间都有相关论文(甚至包括RGB)。因此,我的答案仅基于Chai和Ngan的《在视频电话应用中使用皮肤颜色映射进行人脸分割》一文。他们使用了YCbCr颜色空间,并获得了相当不错的结果。该文章还提到了一个对他们有效的阈值:

(Cb in [77, 127]) and (Cr in [133, 173])

Y通道的阈值没有具体说明,但有论文提到Y > 80。对于您的单张图片来说,Y在整个范围内都是可以的,也就是说,实际上区分皮肤颜色并不受Y的影响。

下面是根据所述阈值得到的二进制图像、丢弃小部件后的结果图像:

enter image description here enter image description here enter image description here

import sys
import numpy
import cv2

im = cv2.imread(sys.argv[1])
im_ycrcb = cv2.cvtColor(im, cv2.COLOR_BGR2YCR_CB)

skin_ycrcb_mint = numpy.array((0, 133, 77))
skin_ycrcb_maxt = numpy.array((255, 173, 127))
skin_ycrcb = cv2.inRange(im_ycrcb, skin_ycrcb_mint, skin_ycrcb_maxt)
cv2.imwrite(sys.argv[2], skin_ycrcb) # Second image

contours, _ = cv2.findContours(skin_ycrcb, cv2.RETR_EXTERNAL, 
        cv2.CHAIN_APPROX_SIMPLE)
for i, c in enumerate(contours):
    area = cv2.contourArea(c)
    if area > 1000:
        cv2.drawContours(im, contours, i, (255, 0, 0), 3)
cv2.imwrite(sys.argv[3], im)         # Final image

最后,有相当数量的论文并不依赖于像素级别的分类来完成这项任务。相反,它们从标注的图像库开始,其中已知包含皮肤像素或非皮肤像素。然后,它们训练例如一个支持向量机分类器,并根据这个分类器区分其他输入。


@mmpg 哇,这真的非常有效!谢谢。使用 cv2.inRange() 时我遇到了一些麻烦,但通过使用 min_YCrCb = numpy.array([0,133,77],numpy.uint8)max_YCrCb = numpy.array([255,173,127],numpy.uint8) 解决了问题。 - samkhan13
@samkhan13:有没有iOS编程方面的参考资料可以实现这个功能? - pkc456

3
一个简单而强大的选择是使用直方图反向投影法。例如,使用来自手部不同训练图像的 H 和 S(来自 HSV 颜色空间)或 a* 和 b*(来自 La*b* 颜色空间)创建一个 2D 直方图,使用像素。然后使用 [cv2.calcBackProject][1] 对流中的像素进行分类。这很快速,您应该可以轻松获得 25 到 30 fps,我猜测。请注意,这是学习感兴趣对象的颜色分布的一种方式。相同的方法也可以在其他情况下使用。

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