OpenCV Using Python——RGB颜色空间中的统计肤色模型

RGB颜色空间中的统计肤色模型

1. 统计肤色模型简介

前几篇文章提出的参数肤色模型,由于参数值固定,所以来自测试图像集的分割误差有可能很大(不过在光照足够的情况下已经够用了)。对于光线比较昏暗的场合,一般人们不太会训练这样的数据来提取参数,同时光照不足时颜色容易跟背景混在一起,所以做出来效果也不好。在光照昏暗的场合,直接在自然光和复杂背景下分割肤色到现在为止依然是比较困难的事。这里讨论的仅仅是单个像素是否为肤色,如果要求在大面积肤色的背景下分割出手或脸来,这种不依赖上下文的方法就完蛋了。

那么统计肤色模型相比参数肤色模型到底有什么改进呢?参数肤色模型的参数是不变的,而统计肤色模型的参数是可变的(根据训练的数据集计算出来),并且引入了可能性的判断。

Jone MJ等人提出统计肤色模型,参数计算步骤如下:

(1)使用图片训练集建立肤色类和非肤色类的颜色直方图;

(2)计算先验概率:属于肤色类的概率P(Cs)和属于非肤色类的概率P(Cns);

(3)计算条件概率:在肤色类中属于该颜色值的概率P(v|Cs)和在非肤色类中属于该颜色值的概率P(v|Cns);

(4)贝叶斯法则计算后验概率:该颜色块属于肤色类的概率P(Cs|v)。

2. 统计肤色模型实现问题

图片训练集合几十到上千张图片不等,到底用多大分辨率的图片呢?我尝试过RGB三通道颜色分别为8bit的图片(即单通道颜色用8位表示),颜色直方图的自变量大小为256*256*256个。笔记本跑起来很慢,我忍了。终于跑出来数据了,存放在2个数组里面,好高兴~

接着是读取数据,考虑到训练数据量远大于测试数据量,所以计算训练数据的代码和计算测试数据的代码我分开写。执行测试数据时需要从之前跑出来的训练数据中获取,所以我在训练数据程序的后面添加了写入csv文件的片段。写入完成后尝试打开csv文件,令我惊呆的是,csv文件125MB,表格打开显示不完全,文本文档根本打不开!好吧,我不打开你了。直接读取数据总是可以的吧,在另一边添加读取csv文件,出现MemoryError。问题在于为Python运行分配的内存空间比较小,超长的数据即使显示,中间的数据也是用“...”来略过。还有后面的显示部分运行起来也比较耗时。

最后决定用6*6*6位颜色值来作颜色直方图。

3. 代码实现

(1)训练代码

训练的数据写入skin_nonskin.csv文件。由于训练数据较大,所以如果没有特殊要求,暂时不提供训练数据。

import cv2
import numpy as np
import os
import csv
################################################################################

print 'Set Image Directory'

imgFile = 'images/skin_color_database/skin_color_database_1/'
################################################################################

# define variables for histogram

colorRange = 64

# skin color counts
countSkin = np.zeros(colorRange ** 3, np.double)
# non-skin color counts
countNonSkin = np.zeros(colorRange ** 3, np.double)

# label sets true if it's a label image, otherwise sets false if it's an original image
label = True
################################################################################

print 'Skin Color Histogram'

for fileName in os.listdir(imgFile):

    if label == True:
        # load a label image
        print 'Label File Name:',fileName
        imgLabel = cv2.imread(imgFile + fileName)

        # convert color space from bgr to gray
        imgLabel = cv2.cvtColor(imgLabel, cv2.COLOR_BGR2GRAY)

    else:
        # load an original image
        print 'Original File Name:',fileName
        img = cv2.imread(imgFile + fileName)
    ############################################################################

    # count pixel color values

    if label == False:

        # get image shape
        rows,cols,channels = img.shape 

        for r in range(rows):
            for c in range(cols):

                # get values from rgb color space
                B = img.item(r,c,0) / 4
                G = img.item(r,c,1) / 4
                R = img.item(r,c,2) / 4

                color = B * 64 * 64 + G * 64 + R

                if imgLabel.item(r,c) == 255:
                    countSkin[color] += 1
                else:
                    countNonSkin[color] += 1                                  

    label = not label
################################################################################

# data combination
# ---------countSkin------------
# ---------countNonSkin---------
data = [countSkin, countNonSkin]
################################################################################

# write csv file

csvFile = open('skin_nonskin.csv','wb')
writer = csv.writer(csvFile)

for row in data:
    writer.writerow([row[col] for col in range(colorRange ** 3)])
################################################################################

print 'Goodbye!'

(2)测试代码

import os
import cv2
import csv
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
################################################################################

print 'read csv file'

VRange = 64 * 64 * 64
print VRange

countSkin = np.zeros(VRange, np.double)
countNonSkin = np.zeros(VRange, np.double)

csvFile = open('skin_nonskin.csv', "rb")
reader = csv.reader(csvFile)

rowNum = 0
for row in reader:

    colNum = 0
    for col in row:
        # restore countSkin and countNonSkin
        modNum = rowNum - rowNum / 2 * 2

        if modNum == 1:
            countNonSkin[((rowNum - 1) * VRange + colNum)] = float(col)
        if modNum == 0:
            countSkin[((rowNum - 1) * VRange + colNum)] = float(col)

        colNum += 1

    rowNum += 1
################################################################################

print 'Skin Color Database Result'

# count
print 'count of skin pixels:',countSkin
print 'count of non-skin pixels:',countNonSkin
################################################################################

print 'prior probability'

skinPix = sum(countSkin)
nskinPix = sum(countNonSkin)

PCs = skinPix / (skinPix + nskinPix) # P(Cs)
PCns = 1 - PCs # P(Cns)

print 'probability of skin class:',PCs
print 'probability of non-skin class',PCns
################################################################################

print 'conditional probability variables'

PVCs = np.zeros(VRange, np.double)  # P(V|Cs)
PVCns = np.zeros(VRange, np.double) # P(V|Cns)

for i in range(VRange):
    # pixel color probability given skin color
    PVCs[i] = countSkin[i] / skinPix

    # pixel color probability given non-skin color
    PVCns[i] = countNonSkin[i] / nskinPix
################################################################################

print 'posterior probability'

PCsV = np.zeros(VRange, np.double) # P(Cs|V)

for i in range(VRange):
    # skin probability given pixel color
    PCsV[i] = (PVCs[i] * PCs) / (PVCs[i] * PCs + PVCns[i] * PCns + 0.00000001)
################################################################################

print 'determine skin distribution'

# pixel color range
v = range(VRange)
# skin class threshold
theta = [0.6,0.7,0.8,0.9]
# color of a single class
rgbColor = np.zeros(3, np.uint8)
# rgb color value
skinPix = np.zeros(VRange, np.uint8)

# prepare for 3d plot
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')

for i in v:

    # split 3 channels(64b * 64b * 64b)
    B = i / (64 * 64)
    G = (i - B * 64 * 64) / 64
    R = i - B * 64 * 64 - G * 64

    # given probability as threshold
    if PCsV[i] > theta[3]:
        skinPix[i] = 4
        ax.scatter(R, G, B, c='r', marker='o')
    else:
        skinPix[i] = 0
################################################################################

print 'display distribution of skin color'

ax.set_xlabel('Red')
ax.set_ylabel('Green')
ax.set_zlabel('Blue')

plt.show()
################################################################################

print 'Goodbye!'<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">  </span>

这部分也不能算作测试代码吧,因为没用测试图片去测试效果。为什么不测试呢?因为该模型的泛化误差取决于训练数据,所以该模型的完美形态为基于完美数据库的带缺陷模型。同时,看到肤色在RGB颜色空间中的形状,要比用图片测试肤色来得更加直观。下图是我找到的训练数据集的实验结果:按照从左到右,从上到下的顺序依次为有90%,80%,70%和60%的可能性确定的肤色空间。

结语

这部分的实验结果为训练数据库得到的肤色在RGB颜色空间中的分布。所以如果给出1个像素点,就可以通过上图来判断这个像素点的颜色值有大可能性为肤色。相比之前参数肤色模型的绝对性判断会有更好的鲁棒性。

时间: 2024-10-11 07:58:50

OpenCV Using Python——RGB颜色空间中的统计肤色模型的相关文章

OpenCV Using Python——应用统计肤色模型和相对于块原点能量的肤色分割

应用统计肤色模型和相对于块原点能量的肤色分割 1. 肤色分割简介 (1)统计肤色模型简介 在前面的文章中,我们利用训练数据已经成功计算出训练数据的后验概率P(Cs|v),即已知像素值判断属于肤色类的概率.同时我们获得后验概率大于不同阈值的肤色掩膜.但之前并没有给出统计肤色模型的肤色检测效果,因为测试效果取决于训练数据对应像素所在的RGB颜色空间分布.本篇将给出统计肤色模型的应用效果,同时改进单一使用模型的缺陷. (2)块原点能量简介 图像中被分割出来的肤色块后面统称为块.根据统计肤色模型在一幅图

Python实现RabbitMQ中6种消息模型

RabbitMQ与Redis对比 ? RabbitMQ是一种比较流行的消息中间件,之前我一直使用redis作为消息中间件,但是生产环境比较推荐RabbitMQ来替代Redis,所以我去查询了一些RabbitMQ的资料.相比于Redis,RabbitMQ优点很多,比如: 具有消息消费确认机制 队列,消息,都可以选择是否持久化,粒度更小.更灵活. 可以实现负载均衡 RabbitMQ应用场景 异步处理:比如用户注册时的确认邮件.短信等交由rabbitMQ进行异步处理 应用解耦:比如收发消息双方可以使用

python图工具中基于随机块模型动态网络社团检测

原文链接:http://tecdat.cn/?p=7602 这是“政治博客圈和2004年美国大选”中的政治博客网络图,但是边缘束是使用随机块模型确定的(注:下图与图相同(即,布局和数据相同)). Tiago论文中的5-我只是在上面放了一个黑色背景 . 边缘配色方案与Adamic和Glance的原始论文中的相同,即每个节点对应一个博客URL,颜色反映政治取向,红色代表保守派,蓝色代表自由派.橙色边从自由派博客到保守派博客,紫色边从保守派到自由派(参见Adamic和Glance中的图1). 颜色方案

「新手必看」Python+Opencv实现摄像头调用RGB图像并转换成HSV模型

在ROS机器人的应用开发中,调用摄像头进行机器视觉处理是比较常见的方法,现在把利用opencv和python语言实现摄像头调用并转换成HSV模型的方法分享出来,希望能对学习ROS机器人的新手们一点帮助.至于为什么转换成HSV模型,因为在机器视觉方面用HSV模型进行图像处理是比较方便的,实现的方法和效果相对于其他模型都较为突出. 接下来是完整步骤: 1.打开一个终端,用vim编辑器新建并打开一个后缀为.py的文件 1 $ vim a.py 2.在打开的文件里按"a"进入编辑模式,然后输入

资深Python程序员教你统计,三国中人物名字出现的频率,很简单

资深Python程序员教你简单.有趣的程序:使用第三方库jieba切分,统计统计名著三国演义中人物名字出现次数. 资深Python程序员教你统计,三国中人物名字出现的频率,很简单其中一个jieba库是一个对中文文本依照汉字间关联概率进行词组划分的第三方库,使用简单,且非常好用 import jieba def getWords(): txt = open('novels/threekingdoms.txt', 'r', encoding = 'utf-8').read() words = jie

OpenCV之Python学习笔记

OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书<OpenCV Computer Vision with Python>,于是就看一遍,顺便把自己掌握的东西整合一下,写成学习笔记了.更需要的朋友参考. 阅读须知: 本文不是纯粹的译文,只是比较贴近原文的笔记:         请设法购买到出版社出版的书,支持正版. 从书名就能看出来本书是介绍在Pytho

Ubuntu16.04安装opencv for python/c++

Ubuntu16.04安装opencv for python/c++ 网上关于opencv的安装已经有了不少资料,但是没有一篇资料能让我一次性安装成功,因此花费了大量时间去解决各种意外,希望这篇能给一些人带去便利,节省时间. 1.安装OpenCV所需的库 1 sudo apt-get install build-essential 2 sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavforma

OpenCV for Python 学习笔记 三

给源图像增加边界 cv2.copyMakeBorder(src,top, bottom, left, right ,borderType,value) src:源图像 top,bottem,left,right: 分别表示四个方向上边界的长度 borderType: 边界的类型 有以下几种: BORDER_REFLICATE # 直接用边界的颜色填充, aaaaaa | abcdefg | gggg BORDER_REFLECT # 倒映,abcdefg | gfedcbamn | nmabcd

OpenCV for Python 学习 (二 事件与回调函数)

今天主要看了OpenCV中的事件以及回调函数,这么说可能不准确,主要是下面这两个函数(OpenCV中还有很多这些函数,可以在 http://docs.opencv.org/trunk/modules/highgui/doc/user_interface.html 找到,就不一一列举了),然后自己做了一个简单的绘图程序 函数如下: cv2.setMouseCallback(windowName, onMouse[, param]) cv2.createTrackbar(trackbarName,