【OpenCV-Python:实现人脸、人眼、嘴巴识别】实战(一)
AI时代的到来,手机上的APP开始应用人脸识别去完成事情,如iphoneX的人脸解锁,百度自动贩卖机的人脸识别系统进行支付,支付宝的人脸识别登录等,提高了使用软件的易用性,但也因为其便利性,在某些市面上的应用已经发生了非本人(活人)通过图片可通过人脸识别,想想这样自己在应用上存储的信息和钱财不能得到保障,是一件很可怕的事情。因为这样,更应该去了解人脸识别的理论及实现,从而更好的去防范这种行为的发生。话不多说,把实现方法和在实现过程中遇到的问题和大家讨论讨论~
一、环境准备
MacOs+PyCharm+Python+OpenCV
1.Mac下PyCharm下载、安装、激活
参考:http://blog.csdn.net/qq_35246620/article/details/78254527?utm_source=gold_browser_extension
2.Python安装
Mac系统下本身已自带python2.7,所以这一步可以省去。要查看版本的话,终端使用如下命令查看:
which python
python
3.OpenCV安装
在实现人脸识别的代码中,我们需要用到的依赖库有:
Pillow 5.0.0
Pillow-PIL 0.1dev
numpy 1.14.1
opencv-python 3.3.0.10
在本机环境安装并配置以上库步骤偏复杂,所以直接在PyCharm中该工程中设置虚拟环境,然后再在虚拟环境中下载安装。虚拟环境与本机进行隔离,在不同的项目中使用到的第三方库版本可切换。下面是虚拟环境的创建和安装依赖库步骤:
因为OpenCV是安装到虚拟环境中,而我们后面需要的xml文件是在OpenCV/data/haarcascades/下,所以需要到OpenCV官网下载对应安装包
https://opencv.org/opencv-3-3.html ,解压缩后,我们就看到了xml文件。
二、代码实现
# !/usr/bin/env python
# coding=utf-8
import os
import numpy
from PIL import Image, ImageDraw
import cv2
#created by chenfenyu 2018.3.20 cap = cv2.VideoCapture(0)
#获取外接摄像头
eye = cv2.imread("/Users/funny/Downloads/img/eye.png")
#读取眼睛区域替换的图片
mouth = cv2.imread("/Users/funny/Downloads/img/mouth.png")
#读取嘴巴区域替换的图片
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) + 0.5), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) + 0.5))
#获取摄像头返回的宽和高
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
#确定保存视频的格式
video = cv2.VideoWriter("/Users/funny/Downloads/a.avi", fourcc, 5, size)
''' cv.VideoWriter参数(视频存放路径,视频存放格式,fps帧率,视频宽高)
注意点1:OpenCV只支持avi的格式,而且生成的视频文件不能大于2GB,而且不能添加音频
注意点2:若填写的文件名已存在,则该视频不会录制成功,但可正常使用
'''
print cap.isOpened()
#检测是否摄像头正常打开:成功打开时,isOpened返回ture
classifier_face = cv2.CascadeClassifier("/Users/funny/Documents/haarcascade_frontalface_alt.xml")
#定义分类器(人脸识别)
classifier_eye = cv2.CascadeClassifier("/Users/funny/Documents/haarcascade_eye.xml")
#定义分类器(人眼识别)
classifier_mouth=cv2.CascadeClassifier("/Users/funny/Documents/haarcascade_mcs_mouth.xml")
#定义分类器(嘴巴识别)
while (True):
#取得cap.isOpened()返回状态为True,即检测到人脸
#img = cv2.imread("/Users/funny/Downloads/img/pp.png")
ret, img = cap.read()
'''第一个参数ret的值为True或False,代表有没有读到图片
第二个参数是frame,是当前截取一帧的图片
'''
faceRects_face = classifier_face.detectMultiScale(img, 1.2, 2, cv2.CASCADE_SCALE_IMAGE, (20, 20))
#检测器:detectMultiScale参数(图像,每次缩小图像的比例,匹配成功所需要的周围矩形框的数目,检测的类型,匹配物体的大小范围)
key = cv2.waitKey(1)
#键盘等待
if len(faceRects_face) > 0:
#检测到人脸
for faceRect_face in faceRects_face:
x, y, w, h = faceRect_face
#获取图像x起点,y起点,宽,高
h1=int(float(h/1.5))
#截取人脸区域高度的一半位置,以精确识别眼睛的位置
intx=int(x)
inty=int(y)
intw=int(w)
inth=int(h)
#转换类型为int,方便之后图像截取
my = int(float(y + 0.7 * h))
#截取人脸区域下半部分左上角的y起点,以精确识别嘴巴的位置
mh = int(0.4 * h)
#截取人脸区域下半部分高度,以精确识别嘴巴的位置
img_facehalf = img[inty:(inty+h1), intx:intx+intw]
img_facehalf_bottom = img[my:(my + mh), intx:intx + intw]
'''img获取坐标为,【y,y+h之间(竖):x,x+w之间(横)范围内的数组】
img_facehalf是截取人脸识别到区域上半部分
img_facehalf_bottom是截取人脸识别到区域下半部分
'''
cv2.rectangle(img, (int(x), my), (int(x) + int(w), my + mh), (0, 255, 0), 2, 0)
'''矩形画出区域 rectangle参数(图像,左顶点坐标(x,y),右下顶点坐标(x+w,y+h),线条颜色,线条粗细)
画出人脸识别下部分区域,方便定位
'''
faceRects_mouth = classifier_mouth.detectMultiScale(img_facehalf_bottom, 1.1, 1, cv2.CASCADE_SCALE_IMAGE, (5, 20))
#嘴巴检测器
if len(faceRects_mouth) > 0:
for faceRect_mouth in faceRects_mouth:
xm1, ym1, wm1, hm2 = faceRect_mouth
cv2.rectangle(img_facehalf_bottom, (int(xm1), int(ym1)), (int(xm1) + int(wm1), int(ym1) + int(hm2)), (0,0, 255), 2, 0)
img_mx = cv2.resize(mouth, (wm1, hm2), interpolation=cv2.INTER_CUBIC)
#调整覆盖图片大小 resize参数(图像,检测到的(宽,高),缩放类型)
if key == ord('z'):
#检测当键盘输入z时,开始替换图片
img[my+ym1:(my+ym1+hm2), intx+xm1:(intx + xm1+wm1)] = img_mx
#将调整大小后的图片赋值给img
cv2.rectangle(img, (int(x), int(y)), (int(x) + int(w), int(y) + int(h1)), (0, 255, 0), 2, 0)
# 画出人脸识别上部分区域,方便定位
faceRects_eye = classifier_eye.detectMultiScale(img_facehalf, 1.2, 2, cv2.CASCADE_SCALE_IMAGE, (20, 20))
#检测器识别眼睛
if len(faceRects_eye) > 0:
#检测到眼睛后循环
eye_tag = []
#定义一个列表存放两只眼睛坐标
for faceRect_eye in faceRects_eye:
x1, y1, w1, h2 = faceRect_eye
cv2.rectangle(img_facehalf, (int(x1), int(y1)), (int(x1) + int(w1), int(y1) + int(h2)), (0, 255, 0), 2, 0)
#画出眼睛区域
a = ((inty+y1),(inty+y1 + h2), (intx+x1),(intx+x1 + w1))
#定义a变量获取眼睛坐标,现在img顶点位置已经改变,需要加上intx和inty的值才可以
eye_tag.append(a)
#通过append存入数组a中
n_eyetag = numpy.array(eye_tag)
#存放为ndarray数组类型,输入内容为[[x1 y1 x1+w y1+h][x1 y1 x1+w y1+h]...],后面会获取多维数组的下标来替换数值 if len(faceRects_eye)==2:
#眼睛识别到两个时,同时替换图片
img_ex=cv2.resize(eye,(n_eyetag[0,1]-n_eyetag[0,0], n_eyetag[0,3]-n_eyetag[0,2]),interpolation=cv2.INTER_CUBIC)
img_ex1 = cv2.resize(eye, (n_eyetag[1, 1] - n_eyetag[1, 0], n_eyetag[1, 3] - n_eyetag[1, 2]), interpolation=cv2.INTER_CUBIC)
if key == ord('p'):
#检测到键盘输入p时,进行替换
img[n_eyetag[0,0]:n_eyetag[0,1],n_eyetag[0,2]:n_eyetag[0,3]]=img_ex
img[n_eyetag[1, 0]:n_eyetag[1, 1], n_eyetag[1, 2]:n_eyetag[1, 3]] = img_ex1
if len(faceRects_eye)==1:
# 眼睛识别到一个时,替换图片
img_ex = cv2.resize(eye, (n_eyetag[0, 1] - n_eyetag[0, 0], n_eyetag[0, 3] - n_eyetag[0, 2]), interpolation=cv2.INTER_CUBIC)
if key == ord('p'):
img[n_eyetag[0, 0]:n_eyetag[0, 1], n_eyetag[0, 2]:n_eyetag[0, 3]] = img_ex video.write(img)
cv2.imshow('video', img)
#显示图片,标题名字为video
cv2.resizeWindow('video',1280,720)
#调整窗口大小video为1280*720
if key == ord('q'):
#检测到键盘输入q,退出循环
break video.release()
#不再录制视频
cap.release()
#释放摄像头
cv2.destroyAllWindows()
#关闭所有窗口显示
代码中都有注释,基本看懂第一个循环输出人脸区域检测的内容就足够了,后面只是在原来的基础上进行多个区域的循环和判断。接下来我来讲一下这个代码的实现思路,画成图解释一下:
1.打开摄像头的时候,开始检测人脸的区域。
2.将获取到的区域上、下半部分图像存储下来。
3.检测上半部分图像区域中双眼的位置。
4.检测下半部分图像区域中嘴巴的位置。
5.模拟人脸识别所进行的操作,如眨眼,摇头,慢慢张开嘴巴,这里我们直接使用键盘‘p’来替换眼睛的位置,‘z’替换嘴巴的位置。
6.关闭摄像头。
说到这里,大家可能有点疑问为什么要划出上下部分区域来识别眼睛和鼻子,原因是识别器的准确度不是很高,若检测眼睛,鼻子区域也会识别成眼睛,所以才需要划分范围,请看下图:
下面我来跟大家讲一下IMG取某区域内图像的坐标以及cv2.rectangle的定位坐标。
1)cv2.rectangle,我们从上面的注释中知道,获取的是左上角和右下角的顶点坐标,用画图的方式表达如下:
2)IMG区域取值范围则和1)不同,IMG[左上顶点y:左下顶点y,左上顶点x:右上顶点x],用图来表示S◇acef区域如下:
所以,之后截取后记得以最原始的IMG坐标为顶点,再来表示要截取的区域,不然就会报错。
三、Q&A
1、Q:2018-03-20 11:17:10.309 python[79368:108479406] mMovieWriter.status: 3. Error: Cannot Save
A:存放信息目录下已有同名文件,只需要删除文件即可,不影响程序正常使用
2、Q:网络上下载的opencv 识别器xml文件,运行工程时提示
OpenCV Error: Unknown error code -49 (Input file is empty) in cvOpenFileStorage, file /Users/travis/build/skvark/opencv-python/opencv/
modules/core/src/persistence.cpp, line 4484
Traceback (most recent call last):
File "/Users/funny/PycharmProjects/untitled1/open-cv.py", line 19, in <module>
classifier_mouth=cv2.CascadeClassifier("/Users/funny/Documents/haarcascade_mcs_mouth1.xml")
cv2.error: /Users/travis/build/skvark/opencv-python/opencv/modules/core/src/persistence.cpp:4484: error: (-49) Input file is empty in
function cvOpenFileStorage
A:一般xml文件不会超过1m,我下载的这个文件超过了6m,如何检测是否是可用文件?在存放xml文件的目录下,单击后在预览区能显示内容则是正确的,请看下图:
不能显示内容则是错误不可使用的文件:
3、Q:报错信息:无法覆盖图像
File "/Users/funny/PycharmProjects/untitled1/open-cv.py", line 52, in <module>
img[ym1:(my+ym1+hm2), intx+xm1:(intx + xm1+wm1)] = img_mx
ValueError: could not broadcast input array from shape (86,143,3) into shape (662,143,3)
A:计算图像的位置不正确,已经超出了范围,建议参考二代码中讲解图像IMG显示的区域坐标。
四、程序已知的问题
1、暂时定位嘴巴和眼睛位置是以人脸分开两个区域来缩小搜索检测范围,所以抬起头或多人时,仍会检测到别的地方,这是由于OpenCV内的Haar特征分类器训练模型还是不够,所以检测不够精准。程序实现的是实时检测摄像头内图像,换成识别静态图片则准确多了。
2、只要检测到人脸,就会一直循环检测,所以当人物晃动的时候,能检测到多个眼睛和嘴巴,而且检测框不断变换大小。
3、程序暂时只实现了单眼、双眼同时替换,嘴巴替换。当摄像头检测到多个眼睛,只能同时替换至多两个眼睛。
4、替换的图片在肉眼看来很假,瞳孔颜色,眼睛大小都还不够精准,只是用替换图替换。
五、参考资料
1、OpenCV教程
2、Python入门教程
3、人工智能书籍
【OpenCV-Python:实现人脸、人眼、嘴巴识别】实战(一)的更多相关文章
- OpenCV + python 实现人脸检测(基于照片和视频进行检测)
OpenCV + python 实现人脸检测(基于照片和视频进行检测) Haar-like 通俗的来讲,就是作为人脸特征即可. Haar特征值反映了图像的灰度变化情况.例如:脸部的一些特征能由矩形特征 ...
- 手把手教你如何用 OpenCV + Python 实现人脸识别
下午的时候,配好了OpenCV的Python环境,OpenCV的Python环境搭建.于是迫不及待的想体验一下opencv的人脸识别,如下文. 必备知识 Haar-like 通俗的来讲,就是作为人脸特 ...
- opencv python训练人脸识别
总计分为三个步骤 一.捕获人脸照片 二.对捕获的照片进行训练 三.加载训练的数据,识别 使用python3.6.8,opencv,numpy,pil 第一步:通过笔记本前置摄像头捕获脸部图片 将捕获的 ...
- 手把手教你如何用 OpenCV + Python 实现人脸检测
配好了OpenCV的Python环境,OpenCV的Python环境搭建.于是迫不及待的想体验一下opencv的人脸识别,如下文. 必备知识 Haar-like Haar-like百科释义.通俗的来讲 ...
- 基于opencv+python的二维码识别
花了2天时间终于把二维码识别做出来了,不过效果一般,后面会应用在ROS辅助定位上,废话少说先上图: 具体过程参考了这位大神的博客:http://blog.csdn.net/qq_25491201/ar ...
- opencv+python+dlib人脸关键点检测、实时检测
安装的是anaconde3.python3.7.3,3.7环境安装dlib太麻烦, 在anaconde3中新建环境python3.6.8, 在3.6环境下安装dlib-19.6.1-cp36-cp36 ...
- opencv+python实时人脸检测、磨皮
import numpy as np import cv2 cap = cv2.VideoCapture(0) face_cascade = cv2.CascadeClassifier("d ...
- 使用OpenCV和Python进行人脸识别
介绍 人脸识别是什么?或识别是什么?当你看到一个苹果时,你的大脑会立刻告诉你这是一个苹果.在这个过程中,你的大脑告诉你这是一个苹果水果,用简单的语言来说就是识别.那么什么是人脸识别呢?我肯定你猜对了. ...
- 【从零学习openCV】IOS7人脸识别实战
前言 接着上篇<IOS7下的人脸检測>,我们顺藤摸瓜的学习怎样在IOS7下用openCV的进行人脸识别,实际上非常easy,因为人脸检測部分已经完毕,剩下的无非调用openCV的方法对採集 ...
随机推荐
- web 参考网址
https://w3c.github.io/ https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket#%E7%A4%BA%E4%BE%8B ...
- Web/app端自动化测试对比
Web/app端自动化测试 做了一段时间的Android自动化测试,对比个人之前做的web端自动化测试,有一些感想.(由于个人接触的时间也不是太久,很多东西理解也并不深刻,先写下菜鸟时期的感想.) 区 ...
- 编码问题 php字符编码转换类
各种平台和软件打开显示的编码问题,需要使用不同的编码,根据我们不同的需求. php 字符编码转换类,支持ANSI.Unicode.Unicode big endian.UTF-8.UTF-8+Bom ...
- Android开发学习必备的java知识
Android开发学习必备的java知识本讲内容:对象.标识符.关键字.变量.常量.字面值.基本数据类型.整数.浮点数.布尔型.字符型.赋值.注释 Java作为一门语言,必然有他的语法规则.学习编程语 ...
- linux周期性计划任务 进程管理
周期性计划任务crontab命令系统服务:/etc/init.d/crond(crond必须启动才会生效)用户计划:/var/spool/cron/用户名默认的计划任务全局配置:/etc/cronta ...
- 【前端】nodejs的ORM框架sequelize的工厂化
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/sequelize_factory.html 一.什么是sequelize nodejs的后台在操作数据库的时候,需 ...
- R语言·文本挖掘︱Rwordseg/rJava两包的安装(安到吐血)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- R语言·文本挖掘︱Rwordseg/rJava ...
- Cortex-M3
大家听说过Cortex-M3吗?在嵌入式处理器的世界,cortex-M3是一位人见人爱的后生.它的成本和功耗低,可配置性很高.如今,很多ARM的工程师加入了cortex-M3的学习与开发中,WIZne ...
- javaWeb事务
JDBC事务: cmd 命令上的事务开启: start transaction; / begin; 回滚 rollback; 提交 commit; JDBC事务控制: 开启事务:co ...
- Django学习-14-分页功能实例
首先创建一个制作page的工具类 utils --page_make.py ...