基本的hsb皮肤检测,霓虹灯照明


14

我希望这是问的正确地方。否则,请为我的错误感到抱歉,并请愿为我提供一个更好的网站。

我正在尝试使用一定范围的hsb图像实现一个超级简单的皮肤检测器。我正在这里这里描述的方法。

我尝试使用网络摄像头中的视频源。如果我使用阳光照明,效果会很好(不是很好,但是很好),但是在霓虹灯下..那是一团糟。检测到很多白色区域,到处都有很多噪音。

为什么?

我正在使用第二个来源中描述的算法:

  1. 将图像转换为HSV颜色空间
  2. 将白色放在0 <H <38的范围内
  3. 扩张过滤器
  4. 腐蚀过滤器
  5. 模糊滤镜

在此处输入图片说明

Answers:


10

实际上,使用简单的RGB生成模型而不是HSV可能会更好。

  1. 获取一张训练图像或一些皮肤有些训练的图像。
  2. 手动选择皮肤像素(例如,通过创建二进制蒙版)
  3. 计算RGB中肤色的均值和协方差(每个均应为3元素向量)
  4. 对于未知像素,使用协方差计算其距均值的马氏距离。
  5. 如果距离小于阈值,则将其分类为皮肤。
  6. 调整最佳性能的阈值。

ññPPC=C 是3 x 3

Edit2: 您获得的值似乎太大。要获得最大协方差,请创建以下矩阵:

255 255 255
 0   0   0

并计算其协方差。您应该获得一个矩阵,其中每个值大约为32513。因此,请确保像素值的范围是0到255,并确保将其正确复制到float或double中。马氏距离以方差为单位,因此,该数字应较小。您的皮肤分类阈值应小于4。


我在理解如何从图像中使用opencv获得3x3协方差矩阵时遇到问题。您能给我一些参考吗?
nkint 2012年

@nkint,请参阅编辑后的答案。
Dima 2012年

好,很好。在5行中,您让我了解了协方差。谢谢。有用。但我在存储结果时遇到问题。如果我的像素范围是0-255,那么我应该期望马哈拉诺比斯距离是什么样的数字?如果我将它们储存在8
盎司的纸上

是的,我认为我做错了,因为我的协方差矩阵是:[10913058.00000000,7046611.50000000,3290781.50000000; 7046611.50000000,4811646.00000000,2225078.00000000; 3290781.50000000,2225078.00000000,1387631.87500000]
nkint 2012年

1
您可以将协方差定义为3D中的椭球。您可能可以在Matlab中对其进行可视化,但这可能需要大量工作。或者,您可以尝试查看椭球的2D投影,但这也需要一些工作。
Dima 2012年

4

考虑到在应用霓虹灯时HSV颜色获得的不同值:此处是其偏差的示例。尝试调整您的算法,使其适应这些值。

这里有另一种检测皮肤的算法,并且可以使用算法来检测光照条件。

另一种算法,与皮肤检测,但没有太多的涉及到霓虹灯效果,是这一个


2

到目前为止,您所获得的答案都指向了不错的替代方法,但是,如果您对使用诸如初始算法之类的东西感兴趣,则可能不难解决。您只需要针对OpenCV的HSV特性进行调整。鉴于结果古怪,我认为您可能在选择阈值和/或转换像素时使用了HSV的一种较常见的数字表示形式?

OpenCV代表HSV的方式与您可能发现的大多数其他来源不同:

  • 您最大的不同是色相:OpenCV表示色相的范围是0到179,而几乎其他所有东西都利用悬挂位来保存更多信息,色泽是0-255。
  • 另一个区别是:饱和度的测量值与标准值相比是倒置的。因此255饱和度意味着opencv会变亮,而不是白色(注意,我们回到了255-只有色相是0-180,可能是因为“滚轮”表示吗?)

可能为时已晚,无法为您提供帮助,但这是一个有趣的问题,其他人可能会遇到同样的问题。


-1
import sys
import numpy
import cv2

cap = cv2.VideoCapture(0)
while(1):
    _, im = cap.read()

    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.imshow("Second Image", 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.imshow("Final Image", im)         # Final image
    cv2.waitKey(1)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.