MyException - 我的异常网
当前位置:我的异常网» Perl/Python » OpenCV Using Python——RGB颜色空间中的统计血色模

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

www.MyException.Cn  网友分享于:2015-02-11  浏览:0次
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个像素点,就可以通过上图来判断这个像素点的颜色值有大可能性为肤色。相比之前参数肤色模型的绝对性判断会有更好的鲁棒性。

        



文章评论

鲜为人知的编程真相
鲜为人知的编程真相
总结2014中国互联网十大段子
总结2014中国互联网十大段子
 程序员的样子
程序员的样子
旅行,写作,编程
旅行,写作,编程
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
漫画:程序员的工作
漫画:程序员的工作
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
程序员和编码员之间的区别
程序员和编码员之间的区别
为什么程序员都是夜猫子
为什么程序员都是夜猫子
如何成为一名黑客
如何成为一名黑客
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
代码女神横空出世
代码女神横空出世
我是如何打败拖延症的
我是如何打败拖延症的
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
程序员都该阅读的书
程序员都该阅读的书
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
编程语言是女人
编程语言是女人
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
每天工作4小时的程序员
每天工作4小时的程序员
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
程序员的鄙视链
程序员的鄙视链
程序员应该关注的一些事儿
程序员应该关注的一些事儿
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
Java程序员必看电影
Java程序员必看电影
10个调试和排错的小建议
10个调试和排错的小建议
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
一个程序员的时间管理
一个程序员的时间管理
程序员必看的十大电影
程序员必看的十大电影
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有