opencv毛孔识别(python实现)

毛孔识别

本文仅仅描述如何用opencv完成一个入门级别的毛孔识别,基于python3.7和 opencv 4.3

原图以及识别生成的效果图,图片来自论文[1]


一、首先引入需要的包,然后读取需要识别的图片

import cv2
import numpy as np
imageMat = cv2.imread("b.png")

二、选取B通道和均值滤波

选取通道是为了将图片转换为灰度图,以便后续的阀值处理,具体选取BGR哪个根据图片不同而不同;之后均值滤波以降噪,要在失真和去噪效果之间取得平衡,选取合适大小的卷积核

#选取blue通道
blueChannelMat = imageMat[:,:,0]
#均值滤波(滤波窗口越大图像失真越严重即更模糊)
blurMat = cv2.blur(blueChannelMat,(5,5))#5,5表示卷积核大小是5x5

三、阀值分割

阀值分割是将灰度图转换为二值图,这也是关乎识别质量很重要的一步,关键在于阀值大小的选取;图中大于阀值的像素会被设置为最大值(一般为255),小于或等于阀值的像素灰度值会被设置为0

otsu法是一种自动计算阀值的算法,通过如下代码可以获取阀值t和二值图

#动态阀值分割(otsu法)
t,thresMat = cv2.threshold(blurMat,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

但有时otsu的效果并不好,就比如现在这样,阀值明显是偏大了

这时就需要手动设置一个合适的阀值(根据阀值处理的效果不断调整到合适为止),并且将参数从THRESH_BINARY修改为THRESH_BINARY_INV即反向阀值处理,因为我们识别的对象是黑色的毛孔,像素值趋向0,阀值处理后像素会被设置为0,而反向阀值则把毛孔的像素设置为255,为什么这么做后面会说明

t,thresMat = cv2.threshold(blurMat,70,255,cv2.THRESH_BINARY_INV)

看到这里你应该能理解识别是怎么做到的了,其实就是因为黑色的毛孔像素值低,可以通过阀值分割出来,完成了对毛孔和皮肤的区分,图里的白色部分就是分割出的毛孔

四、腐蚀膨胀

腐蚀和膨胀简单是去除那些单独小的噪点和让毛孔边缘更平滑,这里不展开说明;根据图片和毛孔的大小调整卷积核的大小,毛孔小卷积核也要取小点,一般取3x3,5x5,7x7…
下面腐蚀膨胀的处理参考了论文: 基于计算机视觉的皮肤毛孔识别及精准定位 - 苏晓朋[3]

#核为矩形5x5腐蚀
k1 = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))#生成形状为矩形5x5的卷积核
x0 = cv2.erode(thresMat, k1)

#核为圆形9x9开运算
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(9,9))
x1 = cv2.morphologyEx(thresMat,cv2.MORPH_OPEN,kernel)

#9x9椭圆核开闭运算
x1 = cv2.morphologyEx(x1,cv2.MORPH_OPEN,kernel)
x2 = cv2.morphologyEx(x1,cv2.MORPH_CLOSE,kernel)

腐蚀膨胀处理后的效果


五、标识毛孔

这里采用opencv的查找轮廓函数来查找连通区域(即图中的白色区域),然后通过计算每个轮廓的面积来大致计算毛孔面积。前面提到阀值分割时要使用反向阀值分割,是因为opencv查找轮廓是以白色区域为对象,就是只会查找白色区域的轮廓

#计算连通区域面积
#查找图像轮廓,参数分别表示只检测外轮廓,存储所有轮廓点
contours,hierarchy=cv2.findContours(x2,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

#计算轮廓面积
contoursArea=[]#存储面积的列表
contours_sel=[]#存储符合要求的轮廓
for i in range(len(contours)):
    temp = cv2.contourArea(contours[i])
    if temp>30:#筛选出面积大于30的轮廓
        contoursArea.append(temp)
        contours_sel.append(contours[i])
        
#绘制轮廓,第一个参数是你要绘制轮廓的图,第二个参数是使用的轮廓,
#第一个-1表示绘制所有轮廓,(0,255,0)是绘制使用的颜色,第二个-1表示填充轮廓内部
x2 = cv2.drawContours(imageMat,contours_sel,-1,(0,255,0),-1)
cv2.imshow("b",x2)#显示图像
cv2.waitKey()
cv2.destroyAllWindows()

下图是识别出的轮廓叠加在原图上的结果


六、如何生成mask图

一般我们用于训练神经网络使用的label图是mask图,当然这里的label图还要人工修正,这里只说说如何从查找到的轮廓生成mask图

#先生成一张纯白的图
mask = np.zeros(imageMat.shape,np.uint8)#生成和原图大小一致的黑色图片
t,mask = cv2.threshold(mask,0,255,cv2.THRESH_BINARY_INV)#通过阀值将其反色为白图
#在白图上绘制查找到的轮廓即可
mask = cv2.drawContours(mask,contours_sel,-1,(0,0,0),-1)
cv2.imshow('m',mask)

第一次写博客,经验不足请多多包涵,之后应该会更新如何使用Unet神经网络来分割出毛孔的文章

参考文献
[1] 林绵. 面部皮肤评测系统的设计与实现[D].华南理工大学,2016.
[2] 李立综. OpenCV轻松入门:面向Python[M].电子工业出版社,2019-05-01
[3] 苏晓朋. 基于计算机视觉的皮肤毛孔识别及精准定位[D].华北电力大学(北京),2018.
本文为博主原创文章,未经博主允许禁止转载

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页