肤色检测识别(附代码)原创

基于贝叶斯分类器的肤色识别实现(不讲原理,小白照着做就能跑)

引言:之前做的时候,网上的实现对新手而言不怎么友好,自己找了蛮多不同的资源,最后才整合到了一起,浪费了很多时间,所以在自己实现后把这个分享出来,希望提供思路对刚做这个的朋友有所帮助。

第一步 运行环境 

环境: pycharm下 pthon3.8; opencv版本:4.2.0; 这是我的电脑环境

第二步 新建项目

 

第三步 安装cv2包

 

 cv2就是opencv包,安装其他的包方法同上

第四步 图像预处理

图像预处理第一步 建立一个文件夹palm用于存储所有获得的图片

以下是手机拍照获得的原始图片一共13张,放到plam文件夹中

 

 

 

 

 在项目中建立一个ImageReName.py文件,把图片名做修改,便于后续的处理:

 

 

 

import os

file_path = ".\Palm"  # 被命名的原文件路径
new_path = ".\Palm"  # 新命名后的图片输出路径

filelist_1 = os.listdir(file_path)  # 输出文件/文件夹名 的列表
print("filelist_1", filelist_1)
fils_1 = filelist_1[:3]
print("file1:", fils_1)


def rename(path):
    i = 0
    filelist = os.listdir(path)
    for files in filelist:  # 取文件夹中文件
        oldDirpath = os.path.join(path, files)  # 路径拼接 作用就是把这个图片路径找出来
        filename = os.path.splitext(files)[0]  # 返回文件路径
        filetype = os.path.splitext(files)[1]  # 返回文件名
        """ 下面这行代码是用于改变图片名称的"""
        newDirPath = os.path.join(new_path, str(i) + filetype)
        # newDirPath = os.path.join(new_path, 'F'+str(i)+filetype)
        # print(filename, filetype)
        os.rename(oldDirpath, newDirPath)  # 把文件改成新名字的函数
        print("filename:", filename)
        print("filetype:", filetype)
        print("oldDirpath", oldDirpath)
        print("newDirPath ", newDirPath)
        i += 1
    print("共有文件数目:", i)


rename(file_path)

if __name__ == '__main__':
    print('finish!')

图片改名处理结果如下:

 

图像预处理第二步 对获得的图片大小进行图片数据处理

由于获得的图片大小参差不齐,不便于后面的训练。所以把图片处理成大小一样300*600大小的图片,并且把这些处理后的图片放在文件夹T中,将这些T文件作为之后模型训练的训练集:

import cv2
import os

file_path = "./Palm/"  # 原文件路径
new_path = "./Palm/T/"  # 新文件路径

if os.path.exists(new_path):
    print("文件已存在")
else:
    os.mkdir(new_path)

filelist_1 = os.listdir(file_path) # 输出文件/文件夹名 的列表
print("", filelist_1)
fils_1 = filelist_1[:3] # 前三个文件的名
print("file1:",fils_1)

def ImageResize(file_path,new_path):
    picture = []
    for filename in os.listdir(file_path):  # listdir的参数是文件夹的路径
        filenames = file_path + filename
        new_filenames = new_path +"T"+ filename
        print("filenames:",filenames)
        # print(filenames)
        img = cv2.imread(filenames)  # 以默认方式读入
        img = cv2.resize(img,(300,600))
        im = img
        # im = transform(img)
        cv2.imwrite(new_filenames, im, [int(cv2.IMWRITE_JPEG_QUALITY), 95])  # 保存的文件名 图片 以及方式

        cv2.waitKey(100)

        print("new_path:", new_path)
        print("file_path:",file_path)

ImageResize(file_path,new_path)

if __name__ == '__main__':

    print('PyCharm')

图像预处理第三步 利用OSTU法把300*600大小的图片生成训练集的标签图片保存在F文件中

由于训练贝叶斯模型的时候,训练数据需要标签去验证训练优化模型,所以需要把图片变成黑白图像作为标签,因为黑白图像中黑色为0,白色为255(可以视为0和1),是一种简单的二分类问题,而贝叶斯模型恰好适合于二分类问题,并且把这些经过二值化处理后的图片放在文件夹F中,将这些F文件中的黑白图像作为监督训练模型中训练图片的图片标签:

import cv2
import os

"""
transform() 函数
 功能: 输入原图 返回一张 二值化的图片
 过程:
     1.将RGB图像转换到 YCrCb 颜色空间,提取 Cr 分量图像
     2.对 Cr 分量进行高斯滤波
     3.对Cr做自二值化阈值分割处理 OSTU 法
"""
def transform(img):

    ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)  # 把图像转换到YUV色域
    (y, cr, cb) = cv2.split(ycrcb)  # 图像分割, 分别获取y, cr, br通道图像
    # 高斯滤波, cr 是待滤波的源图像数据, (5,5)是值窗口大小, 0 是指根据窗口大小来计算高斯函数标准差
    cr1 = cv2.GaussianBlur(cr, (3, 3), 0)  # 对cr通道分量进行高斯滤波
    # 根据OTSU算法求图像阈值, 对图像进行二值化
    _, skin1 = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    return skin1


file_path = "./Palm/T/"  # 原文件路径
new_path = "./Palm/F/"  # 新文件路径

if os.path.exists(new_path):
    print("文件已存在")
else:
    os.mkdir(new_path)

filelist_1 = os.listdir(file_path) # 输出文件/文件夹名 的列表
print("", filelist_1)
fils_1 = filelist_1[:3] # 前三个文件的名
print("file1:",fils_1)

""" 
遍历文件夹内所有图片且把这些图片都变成二值化图片 
"""
def Binary(file_path,new_path):
    picture = []
    for filename in os.listdir(file_path):  # listdir的参数是文件夹的路径
        filenames = file_path + filename
        new_filenames = new_path +"F"+ filename
        print("filenames:",filenames)
        # print(filenames)
        img = cv2.imread(filenames)  # 以默认方式读入
        img = transform(img)
        # img = cv2.resize(img,(300,600))
        im = img
        # im = transform(img)
        cv2.imwrite(new_filenames, im, [int(cv2.IMWRITE_JPEG_QUALITY), 95])  # 保存的文件名 图片 以及方式

        cv2.waitKey(100)

        print("new_path:", new_path)
        print("file_path:",file_path)
Binary(file_path,new_path)

if __name__ == '__main__':

    print('PyCharm')

得结果如下:

 

训练集中原始图片和原始图片的其黑白图片(作为图片标签)的对比图如下:

 

 

 第五步 模型的训练

 

 

 

import cv2
import numpy as  np
import os
import joblib

train_path = "./Palm/T/"
Label_train_path = "./Palm/F/"
picture  = []
for filename in os.listdir(train_path):              #listdir的参数是文件夹的路径
    filenames = train_path+filename
    img = cv2.imread(filenames) # 第二个参数是读取图像的方式(默认值为1,以RGB格式读取)
    imgCBCR = cv2.cvtColor(img,cv2.COLOR_BGR2YCR_CB) # 转化为 YUV 图像格式
    # cv2.imshow("imgCBCR:",imgCBCR)
    #print(imgCBCR.shape)
    picture.append(imgCBCR)
"""建立空的数组 用于存储数据 """
Y = np.array([])
CB = np.array([])
CR = np.array([])
for i in range(len(picture)):
    a = picture[i][:,:,0].flatten() # flatten 降1维  YUV的三个通道 明度 红 蓝 变成一维
    b = picture[i][:,:,1].flatten()
    c = picture[i][:,:,2].flatten()
    Y = np.hstack((Y,a))  # 把 Y都以 数组的形式放在A中 下同  先把这些数据存起来
    CR = np.hstack((CR,b))
    CB = np.hstack((CB,c))
print(Y[:10],CB[:10],CR[:10]) # 输出前十个数据


""" #########################  Y CR CB 三个变量 用于以数组方式 存储训练的数据 """

picture  = []
for filename in os.listdir(Label_train_path):              #listdir的参数是文件夹的路径
    filenames = Label_train_path+filename
    print(filenames)
    img = cv2.imread(filenames,cv2.IMREAD_GRAYSCALE) # 以灰度图像的方式读入
    #print(img.shape)
    picture.append(img)

    """ 把黑白图像作为标签 """
lable = np.array([]) # 标签
for i in range(len(picture)):
    a = picture[i][:,:].flatten()
    lable = np.hstack((lable,a)) # 把黑白图像作为标签
print("lable.shape", lable.shape)

Y_1 = Y.reshape(len(Y),-1) #
CB_1 = Y.reshape(len(CB),-1)
CR_1 = Y.reshape(len(CR),-1)

print("Y_1, CB_1, CR_1", Y_1, CB_1, CR_1)
X = np.hstack((np.hstack((Y_1,CB_1)),CR_1)) # 全部转为一列
y = lable

 from sklearn.naive_bayes import GaussianNB
 from sklearn.model_selection import train_test_split

print("X即train_data", X)
print("y即train_target,", y)
print("lable:",lable)
X_train, X_test, y_train, y_test = train_test_split(X,y/255., test_size=0.1, random_state=42)

# 建立模型
clf = GaussianNB() # 用sklearn包中的 贝叶斯
#使用训练集对模型进行训练
print("X_train数据类型",X_train.dtype)
print("y_train数据类型",y_train.dtype)
clf.fit(X_train,y_train.astype("int")) #把测试集的数据类型变成int
#使用测试集数据检验模型准确率
print("test_data1的准确率",clf.score(X_test,y_test.astype("int")))  # 训练后结果数据 保存在这个模型中

joblib.dump(clf, 'model') # 保存训练好的模型
print("Model save Done!")


if __name__ == '__main__':
    print("finish!")

 

第六步 输入一张照片,查看识别效果

从手机中拍一张照片,建立一个文件里Palm,命名111.jpg

 

 

 

 

 

 

 

 

 

import cv2
import numpy as  np
import joblib

img = cv2.imread("./Palm/Palm/111.jpg")
img = cv2.resize(img,(300,600))
img = cv2.GaussianBlur(img, (5, 5), 0)
# img = cv2.resize(img,(512,1024))
#  显示
cv2.imshow("InputImage",img)
cv2.waitKey(500)

#转化为imgCBCR
imgCBCR = cv2.cvtColor(img,cv2.COLOR_RGB2YCR_CB)
Y_pre = imgCBCR[:,:,0].flatten() # 第一个通道 为明度
CR_pre = imgCBCR[:,:,1].flatten() # 第二个通道 为红色和明度的差距
CB_pre = imgCBCR[:,:,2].flatten() # 第三个通道 为蓝色跟明度的差距

print("Y_pre ", Y_pre)
print("CR_pre", CR_pre)
print("CB_pre", CB_pre)

Y_2 = Y_pre.reshape(len(Y_pre),-1)
CB_2 =CB_pre.reshape(len(CB_pre),-1)
CR_2 =CR_pre.reshape(len(CR_pre),-1)
X_2 = np.hstack((np.hstack((Y_2,CB_2)),CR_2)) # 变成一维向量
clf = joblib.load('model')
c = clf.predict(X_2) # 利用对输入图片的预测值生成图片
# print("c",c)
img1 = c.reshape(img[:,:,0].shape)
"""  最大的BUG 就是数据类型转化 """
cv2.imshow("Final_outputPalm:",img1.astype("float64"))
cv2.waitKey(0)


if __name__ == '__main__':
    print("finish!")

 

运行代码后,效果如下:(由于模型选择,参数调整,数据集选取等原因运行效果不怎么好,但主要提供一种思路)

 

 

 

谢谢! 

 

posted on 2021-01-28 22:48  周街街  阅读(730)  评论(0)    收藏  举报