肤色检测识别(附代码)原创
基于贝叶斯分类器的肤色识别实现(不讲原理,小白照着做就能跑)
引言:之前做的时候,网上的实现对新手而言不怎么友好,自己找了蛮多不同的资源,最后才整合到了一起,浪费了很多时间,所以在自己实现后把这个分享出来,希望提供思路对刚做这个的朋友有所帮助。
第一步 运行环境
环境: 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!")
运行代码后,效果如下:(由于模型选择,参数调整,数据集选取等原因运行效果不怎么好,但主要提供一种思路)
谢谢!