【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的方法对採集 ...
随机推荐
- js鼠标滚轮事件兼容
JavaScript鼠标滚轮事件 IE6.0首先实现了鼠标的滚轮事件,其良好的交互效果得到认可,随后Opera.chrome.safari等主流浏览器都实现了该效果,不过存在着很大的兼容问题. 大多数 ...
- UVA1619 栈维护递增序列
先说这题的关键性质:每一个数应该只会计算一次,它有一个最小区间[L,R],即它在这个区间内是最小的,最小区间内任何包含它的子区间都不会大于F(L,R)=(a[L]+...+a[R])*min(a[l] ...
- C语言中的sizeof函数总结
sizeof函数的结果: 变量:变量所占的字节数. ; printf( 数组:数组所占的字节数. ,,,,}; ] = {,,,,}; printf("size_arr1=%d\n" ...
- 约瑟夫环-循环队列算法(曾微软,google笔试题)
这也是我们聚会时常常做的游戏之一. 算法思路: 此处我使用循环链表模拟人围城一圈,每一个结点代表一个人.链表是一个有序链表,链表结点数据域是一个整型,代表人的序号.出局等同于链表删除元素,每次出局后重 ...
- 笔记︱范数正则化L0、L1、L2-岭回归&Lasso回归(稀疏与特征工程)
机器学习中的范数规则化之(一)L0.L1与L2范数 博客的学习笔记,对一些要点进行摘录.规则化也有其他名称,比如统计学术中比较多的叫做增加惩罚项:还有现在比较多的正则化. -------------- ...
- 实战DeviceIoControl 之一:通过API访问设备驱动程序
Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数.读写绝对扇区数据.测试光驱实际速度等,该从哪里入手呢? A 在NT/2000/XP中,应用程序可以通过API函数Dev ...
- Java中File类总结
/** * @Title:JavaFile.java * @Package:com.yhd.chart.model * @Description:File类测试 * @author:Youhaidon ...
- Linux 系统裁剪笔记 4 (内核配置选项及删改)
CDROM filesystem support(CONFIG_ISO9660_FS)[Y/m/n/?]有标准光驱的系统应该选Y.Minix fs support(CONFIG_MINIX_FS)[ ...
- dedecms 使用自由列表实现首页列表分页
- JBoss启动项目报错
具体报错如下: WARNING: -logmodule is deprecated. Please use the system property 'java.util.logging.manager ...