计算机视觉:遮罩人手

11 投票
2 回答
14141 浏览
提问于 2025-04-17 15:06

我想从实时视频流中检测我的手,并制作一个手的遮罩。不过,结果并不好,正如你在图片中看到的那样。

我的目标是追踪手的运动,所以我做了以下几步:首先把视频流的颜色从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。新链接包含了图像、轮廓、遮罩和原图。https://picasaweb.google.com/103610822612915300423/February7201304

这是上面的一个示例图片:

一张显示上半身和手的示例图片

2 个回答

3

一个简单又强大的方法是直方图反投影。比如,你可以用H和S(来自HSV颜色空间)或者a*和b*(来自La*b*颜色空间)来创建一个二维直方图,这些数据是从你手的不同训练图像中提取的。然后使用[cv2.calcBackProject][1]来对你的视频流中的像素进行分类。这种方法非常快,你应该能轻松达到每秒25到30帧的速度。我想说,这是一种学习你感兴趣的物体的颜色分布的方法。这个方法也可以用在其他情况中。

15

有很多方法可以逐个像素地设置阈值,以区分“皮肤像素”和“非皮肤像素”,而且几乎所有颜色空间都有相关的研究(甚至是RGB颜色空间)。所以,我的回答主要参考了Chai和Ngan的论文《在视频电话应用中的皮肤颜色图像分割》。他们使用了YCbCr颜色空间,得到了不错的结果,论文中也提到了一些有效的阈值:

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

关于Y通道的阈值并没有具体说明,但有些论文提到Y > 80。对于你的一张单独图像来说,Y的整个范围都是可以的,也就是说,实际上区分皮肤时这个值并不重要。

这里是输入图像,根据提到的阈值生成的二值图像,以及在去掉小的部分后得到的结果图像。

在这里输入图像描述 在这里输入图像描述 在这里输入图像描述

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

最后,有相当多的研究并不依赖于逐个像素的分类来完成这个任务。相反,他们从一些已标记的图像开始,这些图像已知包含皮肤像素或非皮肤像素。然后,他们可以训练一个支持向量机(SVM),并根据这个分类器来区分其他输入。

撰写回答