肤色阈值分割

1.视频帧读取图像(YCbCr+Ostu滤波)

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 10 11:31:43 2018

@author: 1
"""
import cv2

cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
#调整参数实现读取视频或调用摄像头
while(cap.isOpened()):
    ret_flag , Vshow = cap.read()#Vshow是一个三维矩阵
#        gray = cv2.cvtColor(Vshow,cv2.COLOR_BGR2GRAY)
#        cv2.imshow("Gray",gray)
    cv2.imshow("Capture_Test",Vshow)  #窗口显示,显示名为 Capture_Test
    k = cv2.waitKey(1) & 0xFF #每帧数据延时 1ms,延时不能为 0,否则读取的结果会是静态帧
    if  k == ord('s'):  #若检测到按键 ‘s’,打印字符串
         #显示图片分辨率
#            print(cap.get(3));
#            print(cap.get(4));
#                img= cv2.cvtColor(Vshow,cv2.COLOR_BGR2GRAY)
        
#        #肤色分割
##                img = cv2.imread('YCbCr OR.jpg', cv2.IMREAD_COLOR)
#        ycrcb = cv2.cvtColor(Vshow, cv2.COLOR_BGR2YCrCb) # 把图像转换到YUV色域
#        (y, cr, cb) = cv2.split(ycrcb) # 图像分割, 分别获取y, cr, br通道图像
#        # 高斯滤波, cr 是待滤波的源图像数据, (5,5)是值窗口大小, 0 是指根据窗口大小来计算高斯函数标准差
#        cr1 = cv2.GaussianBlur(cr, (5, 5), 0) # 对cr通道分量进行高斯滤波
#        # 根据OTSU算法求图像阈值, 对图像进行二值化
#        #_, skin1 = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) 
#        _, img = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
#        #cv2.imshow("image CR", cr1)
##                cv2.imshow("Skin Cr+OSTU", skin )
        
        cv2.imwrite("test.jpg",Vshow)
        # 肤色检测之一: YCrCb之Cr分量 + OTSU二值化
        img = cv2.imread('test.jpg', cv2.IMREAD_COLOR)
        ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) # 把图像转换到YUV色域
        (y, cr, cb) = cv2.split(ycrcb) # 图像分割s, 分别获取y, cr, br通道图像
        # 高斯滤波, cr 是待滤波的源图像数据, (5,5)是值窗口大小, 0 是指根据窗口大小来计算高斯函数标准差
        cr1 = cv2.GaussianBlur(cr, (5, 5), 0) # 对cr通道分量进行高斯滤波
        # 根据OTSU算法求图像阈值, 对图像进行二值化
        #_, skin1 = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) 
        _, skin1 = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        cv2.imshow("image", img)
#        cv2.imshow("image CR", cr1)
        cv2.imshow("Skin Cr+OSTU", skin1 )
    elif k == 27:#检测到esc则退出  #ord('q'): #若检测到按键 ‘q’,退出
        break
cap.release()
cv2.destroyAllWindows()

2.HSV颜色空间阈值分割

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 10 15:30:18 2018

@author: 1
"""

import cv2
import numpy as np
from matplotlib import pyplot as plt
################################################################################
 
print('Pixel Values Access')
 
imgFile = 'test.jpg'
 
# load an original image
img = cv2.imread(imgFile)
img1 = cv2.imread(imgFile)
################################################################################
 
print('HSV Skin Model')
 
rows,cols,channels = img.shape
 
# convert color space from bgr to rgb                        
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 
# prepare an empty image space
imgSkin = np.zeros(img.shape, np.uint8)
# copy original image
imgSkin = img.copy()                       
 
# convert color space from rgb to hsv
imgHsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
 
for r in range(rows):
    for c in range(cols):
 
        # get values of hue, saturation and value
        # standard -- h range: [0,360]; s range: [0,1]; v range: [0,255]
        # opencv -- h range: [0,180]; s range: [0,255]; v range: [0,255]       
        H = imgHsv.item(r,c,0)
        S = imgHsv.item(r,c,1)
        V = imgHsv.item(r,c,2)
        
        # non-skin area if skin equals 0, skin area otherwise        
        skin = 0
                
        if ((H >= 0) and (H <= 25 / 2)) or ((H >= 335 / 2) and (H <= 360 / 2)):
            if ((S >= 0.2 * 255) and (S <= 0.6 * 255)) and (V >= 0.4 * 255):
                skin = 1
                # print 'Skin detected!'
        
        if 0 == skin:
            imgSkin.itemset((r,c,0),0)
            imgSkin.itemset((r,c,1),0)                
            imgSkin.itemset((r,c,2),0)
 
# display original image and skin image
#img= imgSkin[...,::-1]
#cv2.imwrite("HSV.jpg",img)
#plt.subplot(1,2,1), plt.imshow(img), plt.title('Original Image'), plt.xticks([]), plt.yticks([])
#plt.subplot(1,2,2), 
img2= img1[...,::-1]
plt.imshow(img2)
plt.title('Original')
plt.xticks([])
plt.yticks([])
#plt.imshow(imgSkin)
#plt.title('HSV')
plt.show()  


                                              
################################################################################
#img = cv2.imread('YCbCr OR.jpg', cv2.IMREAD_COLOR) 
#hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 把图像转换到HSV色域
#(_h, _s, _v) = cv2.split(hsv) # 图像分割, 分别获取h, s, v 通道分量图像
#skin3 = np.zeros(_h.shape, dtype=np.uint8)  # 根据源图像的大小创建一个全0的矩阵,用于保存图像数据
#(x, y) = _h.shape # 获取源图像数据的长和宽
## 遍历图像, 判断HSV通道的数值, 如果在指定范围中, 则置把新图像的点设为255,否则设为0
#for i in  range(0, x):
#    for j in  range(0, y):
#        if (_h[i][j] >  7) and (_h[i][j] <  20) and (_s[i][j] >  28) and (_s[i][j] <  255) and (_v[i][j] >  50) and (_v[i][j] <  255):
#            skin3[i][j] =  255
#        else:
#            skin3[i][j] =  0
#cv2.imshow('YCbCr OR.jpg', img)
#cv2.imshow('YCbCr OR.jpg' +  " Skin3 HSV", skin3)

3.RGB阈值分割

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 10 15:32:32 2018

@author: 1
"""

import cv2
import numpy as np
from matplotlib import pyplot as plt
################################################################################
 
#print 'Pixel Values Access'
 
imgFile = 'test.jpg'
 
# load an original image
img = cv2.imread(imgFile)
 
# access a pixel at (row,column) coordinates
px = img[150,200]
#print 'Pixel Value at (150,200):',px
 
# access a pixel from blue channel
blue = img[150,200,0]
# access a pixel from green channel
green = img[150,200,1]
# access a pixel from red channel
red = img[150,200,2]
#print 'Pixel Value from B,G,R channels at (150,200): ',blue,green,red
################################################################################
 
#print 'Pixel Values Modification'
# 
img[150,200] = [0,0,0]
#print 'Modified Pixel Value at (150,200):',px
################################################################################
# better way: using numpy
 
# access a pixel from blue channel
blue = img.item(100,200,0)
# access a pixel from green channel
green = img.item(100,200,1)
# access a pixel from red channel
red = img.item(100,200,2)
#print 'Pixel Value using Numpy from B,G,R channels at (100,200): ',blue,green,red
 
# warning: we can only change pixels in gray or single-channel image
 
# modify green value: (row,col,channel)
img.itemset((100,200,1),255)
# read green value
green = img.item(100,200,1)
#print 'Modified Green Channel Value Using Numpy at (100,200):',green
################################################################################
 
#print 'Skin Model'
 
rows,cols,channels = img.shape
 
# prepare an empty image space
imgSkin = np.zeros(img.shape, np.uint8)
# copy original image
imgSkin = img.copy()
 
for r in range(rows):
    for c in range(cols):
 
        # get pixel value       
        B = img.item(r,c,0)
        G = img.item(r,c,1)
        R = img.item(r,c,2)
        
        # non-skin area if skin equals 0, skin area otherwise        
        skin = 0
                
        if (abs(R - G) > 15) and (R > G) and (R > B):
            if (R > 95) and (G > 40) and (B > 20) and (max(R,G,B) - min(R,G,B) > 15):               
                skin = 1    
                # print 'Condition 1 satisfied!'
            elif (R > 220) and (G > 210) and (B > 170):
                skin = 1
                # print 'Condition 2 satisfied!'
        
        if 0 == skin:
            imgSkin.itemset((r,c,0),0)
            imgSkin.itemset((r,c,1),0)                
            imgSkin.itemset((r,c,2),0)
            # print 'Skin detected!'
 
# convert color space of images because of the display difference between cv2 and matplotlib                         
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#cv2.imwrite("RGB.jpg",imgSkin)
imgSkin = cv2.cvtColor(imgSkin, cv2.COLOR_BGR2RGB)
 

# display original image and skin image
#plt.subplot(1,2,1), plt.imshow(img), plt.title('Original Image'), plt.xticks([]), plt.yticks([])
#plt.subplot(1,2,2), 
plt.imshow(imgSkin), plt.title('RGB'), plt.xticks([]), plt.yticks([])
plt.show()                                                
################################################################################
 
#print 'Waiting for Key Operation'
 
k = cv2.waitKey(0)
 
# wait for ESC key to exit
if 27 == k:
    cv2.destroyAllWindows()

4.YCbCr颜色空间方法一

# -*- coding: utf-8 -*-
"""
Created on Wed Dec  5 14:37:04 2018

@author: 1
"""


import cv2
import numpy as np
from matplotlib import pyplot as plt
################################################################################
 
print ('Pixel Values Access')
 
imgFile = 'test.jpg'
 
# load an original image
img = cv2.imread(imgFile)
################################################################################
 
print ('YCbCr Skin Model')
 
rows,cols,channels = img.shape
################################################################################
# light compensation
 
gamma = 0.95
 
for r in range(rows):
    for c in range(cols):
        
        # get values of blue, green, red     
        B = img.item(r,c,0)
        G = img.item(r,c,1)
        R = img.item(r,c,2)
        
        # gamma correction
        B = int(B ** gamma)  
        G = int(G ** gamma) 
        R = int(R ** gamma)
        
        # set values of blue, green, red
        img.itemset((r,c,0), B)
        img.itemset((r,c,1), G)
        img.itemset((r,c,2), R)
                  
################################################################################
 
# convert color space from rgb to ycbcr
imgYcc = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
 
# convert color space from bgr to rgb                        
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 
# prepare an empty image space
imgSkin = np.zeros(img.shape, np.uint8)
# copy original image
imgSkin = img.copy()                       
################################################################################
 
# define variables for skin rules
 
Wcb = 46.97
Wcr = 38.76
 
WHCb = 14
WHCr = 10
WLCb = 23
WLCr = 20
 
Ymin = 16
Ymax = 235
 
Kl = 125
Kh = 188
 
WCb = 0
WCr = 0
 
CbCenter = 0
CrCenter = 0
################################################################################
 
for r in range(rows):
    for c in range(cols):
        
        # non-skin area if skin equals 0, skin area otherwise        
        skin = 0
        
        ########################################################################
        
        # color space transformation
        
        # get values from ycbcr color space     
        Y = imgYcc.item(r,c,0)
        Cr = imgYcc.item(r,c,1)
        Cb = imgYcc.item(r,c,2)                                
                                                                                                        
        if Y < Kl:
            WCr = WLCr + (Y - Ymin) * (Wcr - WLCr) / (Kl - Ymin)
            WCb = WLCb + (Y - Ymin) * (Wcb - WLCb) / (Kl - Ymin)
            
            CrCenter = 154 - (Kl - Y) * (154 - 144) / (Kl - Ymin)
            CbCenter = 108 + (Kl - Y) * (118 - 108) / (Kl - Ymin)            
            
        elif Y > Kh:
            WCr = WHCr + (Y - Ymax) * (Wcr - WHCr) / (Ymax - Kh)
            WCb = WHCb + (Y - Ymax) * (Wcb - WHCb) / (Ymax - Kh)
 
            CrCenter = 154 + (Y - Kh) * (154 - 132) / (Ymax - Kh)
            CbCenter = 108 + (Y - Kh) * (118 - 108) / (Ymax - Kh) 
        
        if Y < Kl or Y > Kh:
            Cr = (Cr - CrCenter) * Wcr / WCr + 154            
            Cb = (Cb - CbCenter) * Wcb / WCb + 108
        ########################################################################
        
        # skin color detection
        
        if Cb > 77 and Cb < 127 and Cr > 133 and Cr < 173:
            skin = 1
            # print 'Skin detected!'
        
        if 0 == skin:
            imgSkin.itemset((r,c,0),0)
            imgSkin.itemset((r,c,1),0)                
            imgSkin.itemset((r,c,2),0)
 
# display original image and skin image
#plt.imshow(img)
YCbCr_= imgSkin[...,::-1]#将Plt RGB转换到cv BGR
#cv2.imwrite("YCbCr_4.jpg",YCbCr_)
plt.imshow(imgSkin)
plt.title('YCbCr')
plt.axis('off')
#plt.subplot(1,2,1), plt.imshow(img), plt.title('Original Image'), plt.xticks([]), plt.yticks([])
#plt.subplot(1,2,2), plt.imshow(imgSkin), plt.title('Transformed YCbCr Skin Image'), plt.xticks([]), plt.yticks([])
plt.show()                                                

5.YCbCr颜色空间方法二

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 10 15:37:03 2018

@author: 1
"""
import cv2
import numpy as np

img = cv2.imread('YCbCr OR.jpg', cv2.IMREAD_COLOR)
ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) # 把图像转换到YUV色域
(y, cr, cb) = cv2.split(ycrcb) # 图像分割, 分别获取y, cr, br通道分量图像
skin2 = np.zeros(cr.shape, dtype=np.uint8) # 根据源图像的大小创建一个全0的矩阵,用于保存图像数据
(x, y) = cr.shape # 获取源图像数据的长和宽
# 遍历图像, 判断Cr和Br通道的数值, 如果在指定范围中, 则置把新图像的点设为255,否则设为0
for i in  range(0, x): 
    for j in  range(0, y):
        if (cr[i][j] >  140) and (cr[i][j] <  175) and (cb[i][j] >  100) and (cb[i][j] <  120):
            skin2[i][j] =  255
        else:
            skin2[i][j] =  0
cv2.imshow('YCbCr OR.jpg', img)
cv2.imshow('YCbCr OR.jpg' +  " Skin2 Cr+Cb", skin2)
原文地址:https://www.cnblogs.com/Manuel/p/10430172.html