毛孔识别

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

原图以及识别生成的效果图

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

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......

下面腐蚀膨胀的处理参考了论文: 《基于计算机视觉的皮肤毛孔识别及精准定位》 - 苏晓朋

#核为矩形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.

本文为博主原创文章,未经博主允许禁止转载

声明:本文同步发布于CSDN:https://blog.csdn.net/Misaki____Mei/article/details/107272751

opencv毛孔识别(python实现)的更多相关文章

  1. 人脸检测及识别python实现系列(6)——终篇:从实时视频流识别出“我”

    人脸检测及识别python实现系列(6)——终篇:从实时视频流识别出“我” 终于到了最后一步,激动时刻就要来临了,先平复一下心情,把剩下的代码加上,首先是为Model类增加一个预测函数: #识别人脸 ...

  2. 人脸检测及识别python实现系列(3)——为模型训练准备人脸数据

    人脸检测及识别python实现系列(3)——为模型训练准备人脸数据 机器学习最本质的地方就是基于海量数据统计的学习,说白了,机器学习其实就是在模拟人类儿童的学习行为.举一个简单的例子,成年人并没有主动 ...

  3. 人脸检测及识别python实现系列(1)——配置、获取实时视频流

    人脸检测及识别python实现系列(1)——配置.获取实时视频流 1. 前言 今天用多半天的时间把QQ空间里的几篇年前的旧文搬到了这里,算是完成了博客搬家.QQ空间里还剩下一些记录自己数学学习路线的学 ...

  4. OpenCV.物体识别

    1.度娘:“OpenCV 物体识别” 1.1.opencv实时识别指定物体 - 诺花雨的博客 - CSDN博客.html(https://blog.csdn.net/qq_27063119/artic ...

  5. opencv +数字识别

    现在很多场景需要使用的数字识别,比如银行卡识别,以及车牌识别等,在AI领域有很多图像识别算法,大多是居于opencv 或者谷歌开源的tesseract 识别. 由于公司业务需要,需要开发一个客户端程序 ...

  6. opencv人脸识别代码

    opencv人脸识别C++代码 /* * Copyright (c) 2011,2012. Philipp Wagner <bytefish[at]gmx[dot]de>. * Relea ...

  7. 人脸检测及识别python实现系列(2)——识别出人脸

    人脸检测及识别python实现系列(2)——识别出人脸 http://www.cnblogs.com/neo-T/p/6430583.html

  8. OpenCV人脸识别的原理 .

    OpenCV人脸识别的原理 . 在之前讲到的人脸测试后,提取出人脸来,并且保存下来,以供训练或识别是用,提取人脸的代码如下: void GetImageRect(IplImage* orgImage, ...

  9. 人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型

    人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型 经过前面稍显罗嗦的准备工作,现在,我们终于可以尝试训练我们自己的卷积神经网络模型了.CNN擅长图像处理,keras库的te ...

随机推荐

  1. Tensorflow从0到1(2)之基础知识

    张量 张量是tensorflow中的基本数据结构 # 全零张量 zero_tsr = tf.zeros([row_dim, col_dim]) # 全1张量 ones_tsr = tf.ones([r ...

  2. 解决错误【selenium.common.exceptions.SessionNotCreatedException】

    以前能用,突然不能用了,是浏览器版本可能升级了,与原来的weddriver驱动版本不符合 解决办法:1.更新浏览器驱动, 2.降低浏览器版本

  3. 测试必备工具之最强抓包神器 Charles,你会了么?

    前言 ​ 作为软件测试工程师,大家在工作中肯定经常会用到各种抓包工具来辅助测试,比如浏览器自带的抓包工具-F12,方便又快捷:比如时下特别流行的Fiddler工具,使用各种web和APP测试的各种场景 ...

  4. 记一次 CocoaPod 的使用过程

    目前有一个cocos2d creator项目, 接入了微信SDK,  现在需要接入阿里云移动推送. 用到了CocoaPod集成.   于是创建了一个Podfile, (此文件在项目目录中, 和 xxx ...

  5. scanf中的%[^\n]%*c格式

    scanf中的%[^\n]%*c格式 (2011-02-19 16:12:38) 转载▼ 标签:  控制字符 空白字符 字符串 变量 整数 it 分类: C语言编程 文章转载自http://blog. ...

  6. 微信小程序点击保存图片到本地相册——踩坑

    在微信小程序中要保存图片到本地相册,需要获取相册权限. 总之整个功能实现下来需要如下几个小程序的API:wx.getSetting,wx.authorize,wx.openSetting,wx.dow ...

  7. idea中Junit的使用

    第一步:添加插件 添加插件:File->Settings->Plugins 第二步:修改设置 1.设置生成模式:File->Settings->Other Settings 指 ...

  8. Redis系列(六):数据结构List双向链表LPUSH、LPOP、RPUSH、RPOP、LLEN命令

    1.介绍 redis中的list既实现了栈(先进后出)又实现了队列(先进先出) 1.示意图 2.各命令详解 LPUSH/RPUSH LPUSH: 从队列的左边入队一个或多个元素 将所有指定的值插入到存 ...

  9. 并发02--JAVA内存模型

    在并发编程中,需要解决两个问题:线程间如何通信&线程间如何同步 线程同步:控制不同线程操作顺序的机制 解决这两个问题的方案有两种:共享内存&消息传递 共享内存:通过使用共享内存,隐式通 ...

  10. Write a program that prints its input one word per line.

    #include <stdio.h> #define State '\n' void main() { int Juge=;/*only one space*/ int c=; while ...