opencv毛孔识别(python实现)
毛孔识别
本文仅仅描述如何用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实现)的更多相关文章
- 人脸检测及识别python实现系列(6)——终篇:从实时视频流识别出“我”
人脸检测及识别python实现系列(6)——终篇:从实时视频流识别出“我” 终于到了最后一步,激动时刻就要来临了,先平复一下心情,把剩下的代码加上,首先是为Model类增加一个预测函数: #识别人脸 ...
- 人脸检测及识别python实现系列(3)——为模型训练准备人脸数据
人脸检测及识别python实现系列(3)——为模型训练准备人脸数据 机器学习最本质的地方就是基于海量数据统计的学习,说白了,机器学习其实就是在模拟人类儿童的学习行为.举一个简单的例子,成年人并没有主动 ...
- 人脸检测及识别python实现系列(1)——配置、获取实时视频流
人脸检测及识别python实现系列(1)——配置.获取实时视频流 1. 前言 今天用多半天的时间把QQ空间里的几篇年前的旧文搬到了这里,算是完成了博客搬家.QQ空间里还剩下一些记录自己数学学习路线的学 ...
- OpenCV.物体识别
1.度娘:“OpenCV 物体识别” 1.1.opencv实时识别指定物体 - 诺花雨的博客 - CSDN博客.html(https://blog.csdn.net/qq_27063119/artic ...
- opencv +数字识别
现在很多场景需要使用的数字识别,比如银行卡识别,以及车牌识别等,在AI领域有很多图像识别算法,大多是居于opencv 或者谷歌开源的tesseract 识别. 由于公司业务需要,需要开发一个客户端程序 ...
- opencv人脸识别代码
opencv人脸识别C++代码 /* * Copyright (c) 2011,2012. Philipp Wagner <bytefish[at]gmx[dot]de>. * Relea ...
- 人脸检测及识别python实现系列(2)——识别出人脸
人脸检测及识别python实现系列(2)——识别出人脸 http://www.cnblogs.com/neo-T/p/6430583.html
- OpenCV人脸识别的原理 .
OpenCV人脸识别的原理 . 在之前讲到的人脸测试后,提取出人脸来,并且保存下来,以供训练或识别是用,提取人脸的代码如下: void GetImageRect(IplImage* orgImage, ...
- 人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型
人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型 经过前面稍显罗嗦的准备工作,现在,我们终于可以尝试训练我们自己的卷积神经网络模型了.CNN擅长图像处理,keras库的te ...
随机推荐
- Tensorflow从0到1(2)之基础知识
张量 张量是tensorflow中的基本数据结构 # 全零张量 zero_tsr = tf.zeros([row_dim, col_dim]) # 全1张量 ones_tsr = tf.ones([r ...
- 解决错误【selenium.common.exceptions.SessionNotCreatedException】
以前能用,突然不能用了,是浏览器版本可能升级了,与原来的weddriver驱动版本不符合 解决办法:1.更新浏览器驱动, 2.降低浏览器版本
- 测试必备工具之最强抓包神器 Charles,你会了么?
前言 作为软件测试工程师,大家在工作中肯定经常会用到各种抓包工具来辅助测试,比如浏览器自带的抓包工具-F12,方便又快捷:比如时下特别流行的Fiddler工具,使用各种web和APP测试的各种场景 ...
- 记一次 CocoaPod 的使用过程
目前有一个cocos2d creator项目, 接入了微信SDK, 现在需要接入阿里云移动推送. 用到了CocoaPod集成. 于是创建了一个Podfile, (此文件在项目目录中, 和 xxx ...
- scanf中的%[^\n]%*c格式
scanf中的%[^\n]%*c格式 (2011-02-19 16:12:38) 转载▼ 标签: 控制字符 空白字符 字符串 变量 整数 it 分类: C语言编程 文章转载自http://blog. ...
- 微信小程序点击保存图片到本地相册——踩坑
在微信小程序中要保存图片到本地相册,需要获取相册权限. 总之整个功能实现下来需要如下几个小程序的API:wx.getSetting,wx.authorize,wx.openSetting,wx.dow ...
- idea中Junit的使用
第一步:添加插件 添加插件:File->Settings->Plugins 第二步:修改设置 1.设置生成模式:File->Settings->Other Settings 指 ...
- Redis系列(六):数据结构List双向链表LPUSH、LPOP、RPUSH、RPOP、LLEN命令
1.介绍 redis中的list既实现了栈(先进后出)又实现了队列(先进先出) 1.示意图 2.各命令详解 LPUSH/RPUSH LPUSH: 从队列的左边入队一个或多个元素 将所有指定的值插入到存 ...
- 并发02--JAVA内存模型
在并发编程中,需要解决两个问题:线程间如何通信&线程间如何同步 线程同步:控制不同线程操作顺序的机制 解决这两个问题的方案有两种:共享内存&消息传递 共享内存:通过使用共享内存,隐式通 ...
- 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 ...