学习一:人脸识别
1.opencv
简介:? OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。
? ①在Pycharm中新建一个opencv项目,选择的编译环境为[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plRPIptJ-1651756167081)(C:\Users\艺\AppData\Roaming\Typora\typora-user-images\image-20220504212337051.png)]
? ②安装opencv-python
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python
③获取分类器位置
D:\Anaconda\Lib\sitepackages\cv2\data\haarcascade_frontalface_default.xml
④完整代码
import cv2
def detect(filename):
##创建?个级联分类器,加载?个 .xml?件
# 这?路径替换成??的'Python路径下/Lib/sitepackages/cv2/data/haarcascade_frontalface_default.xml'
face_cascade =cv2.CascadeClassifier('D:\Anaconda\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml')
# 加载图像
img = cv2.imread(filename)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使?上?创建的分类器来检测?脸,faces为识别出脸部的矩形框向量组,?张脸就有?个矩
#形框,向量组?就有?组向量,保存?脸的坐标和??。
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# scaleFactor表示?脸检测过程中每次迭代时图?的压缩率(1.3)
# minNeighbors:每个?脸矩形保留近邻数?的最?值(5)
# 在原图上绘制矩形
# 遍历faces矩形框向量组?每?组矩形(即每?张脸)
for (x, y, w, h) in faces:
# 通过坐标绘制矩形,x,y是左上?坐标;w,h分别是宽度和?度
# 参数:图?,??形框左上?坐标, ??形框右下?坐标, 字体颜?,字体粗细)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 其中参数的含义:(255, 0, 0)表示颜?, 2表示线条粗细
cv2.imshow('Person Detected!', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
detect('smile.jpg')
⑤实验结果
2.基于face_recognition
? 由上图可以看到opencv在识别的过程中有些人脸因为边缘性无法识别。可以通过face_recognition 提高精确度。
? ①简介:face_recognition项目是世界上最简洁的人脸识别库,可以使用Python和命令行工具提取、识别、操作人脸。
? ②安装环境
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python
pip install CMake
pip install Boost
pip install dlib
pip install face_recognition
在这里安装的过程中,直接安装会报错需要先安装dlib,dlib依赖于boost和cmake
注意在安装dlib的时候会报错
解决方法:找到python对应的dlib安装版本:3.6——对应的版本是dlib-19.8.1
链接:https://pypi.org/project/dlib/19.8.1/#files
其他版本对应链接:https://pypi.org/project/dlib/#description
安装face_recognitiond可能需要等待一段时间
(将对应的.whl文件下载到对应到本地,在cmd中:cd+对应下载的路径;接着: pip install dlib-19.8.1-cp36-cp36m-win_amd64.whl 加安装成功了
③实验代码:使用cnn卷积神经网络
import face_recognition
import cv2
#加载图像?件(.jpg,.png等),返回的数据是Numpy数组,记录了图?的所有像素的特征向量
image = face_recognition.load_image_file("smile.jpg")
#定位图中所有的?脸的像素位置,返回值为列表形式,列表中每??是?张?脸的位置信息,包括
#【top, right, bottom, left】 这是?组元组。
face_locations_noCNN=face_recognition.face_locations(image)
# face_locations_useCNN =
face_recognition.face_locations(image,model='cnn')
# A list of tuples of found face locations in css (top, right, bottom,
#left) order
# 因为返回值的顺序是这样?的,因此在后?的for循环??赋值要注意按这个顺序来
print("face_location_noCNN:")
print(face_locations_noCNN)
face_num2=len(face_locations_noCNN)
print(face_num2) # The number of faces
# 到这?为?,可以观察两种情况的坐标和?脸数,?般来说,坐标会不?样,但是检测出来的?
#脸数应该是?样的
# 也就是说face_num1 = face_num2; face_locations_useCNN 和
#pipface_locations_noCNN 不?样
org = cv2.imread("smile.jpg")
img = cv2.imread("smile.jpg")
cv2.imshow("smile.jpg",img) # 原始图?
for i in range(0,face_num2):
top = face_locations_noCNN[i][0]
right = face_locations_noCNN[i][1]
bottom = face_locations_noCNN[i][2]
left = face_locations_noCNN[i][3]
start = (left, top)
end = (right, bottom)
color = (0,255,255)
thickness = 2
#参数:图?,??形框左上?坐标, ??形框右下?坐标, 字体颜?,字体粗细)
cv2.rectangle(org, start, end, color, thickness)
cv2.imshow("no cnn ",org)
cv2.waitKey(0)
cv2.destroyAllWindows()
? ④实验结果
? 可以看到输出两个坐标,识别出两个人脸
3.人脸特征点检测
Dlib有专门的函数和模型可以实现人脸68个特征点的定位。 支持更加精准的标定点。分为五点和八点,可以圈出面部和嘴鼻的位置。
? ① 下载预训练模型
shape_predictor_68_face_landmarks.dat
链接:https://pan.baidu.com/s/1e7oyn-bc3r4USGwo4alZ5w
提取码:wppp
shape_predictor_5_face_landmarks.dat
链接:https://pan.baidu.com/s/1CxUl5NEVOFokcQb4pKry-Q
提取码:y0f3
这两个个包放在python路径下的site-packages?
? ② 实验代码
import cv2
import dlib
path = "smile.jpg"
#读取图?
img = cv2.imread(path)
#灰度化处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#获得脸部位置检测器
detector = dlib.get_frontal_face_detector()
# 初步?脸检测,框出矩形。返回值是<class 'dlib.dlib.rectangle'>,即?个矩形,表示
#为能够唯?表示这个?脸矩形框两个点坐标:左上?(x1,y1)、右下?(x2,y2
dets = detector(gray, 1)
# 使?模型构建特征提取器,返回5/68个特征点的位置
#此处路径是??的python路径下site-packages位置
predictor =dlib.shape_predictor("D:\Anaconda\Lib\site-packages\shape_predictor_68_face_landmarks.dat")
for face in dets:
shape = predictor(img, face) # 寻找?脸的68个标定点
# 遍历所有点,打印出其坐标,并圈出来
#shape.parts() 类型为_dlib_pybind11.points,可返回检测到的关键点的位置坐标
for pt in shape.parts():
pt_pos = (pt.x, pt.y)
#参数:图?,圆?, 半径, 字体颜?,字体粗细)
cv2.circle(img, pt_pos, 2, (0, 255, 0), 1)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
? ③实验结果
4.使用人脸识别技术进行创新
? 创新:AI换脸
? ①使用技术:基于python的opencv和dlib
? ②实现步骤:参考链接:(58条消息) AI换脸_hxxjxw的博客-CSDN博客_ai换脸 csdn
a. 使用dlib的shapepredictor_68_face_landmarks.dat模型获取人脸图片im1和视频中的人脸图片im2的68个人脸特征点。
b. 根据上一步获得的特征点得到两张图片的人脸掩模im1_mask和im2_mask
c. 利用68个特征点中的3个特征点,对人脸图片im1进行仿射变换使其脸部对准摄像头图片中的脸部,得到图片affine_im1
d. 对人脸图片的掩模im1_mask也进行相同的仿射变换得到affine_im1_mask。
e. 对掩模im2_mask和掩模affine_im1_mask的掩盖部分取并集得到union_mask。
f. 利用opencv里的seamlessClone函数对仿射变换后的affine_im1和摄像头图片im2进行泊松融合,掩模为union_mask,得到融合后的图像seamless_im
? ③实验代码
# -*- coding: utf-8 -*-
import os
import cv2
import dlib
import numpy as np
here = os.path.dirname(os.path.abspath(__file__))
print(here)
models_folder_path = os.path.join(here, 'models') # 模型保存文件夹
faces_folder_path = os.path.join(here, 'faces') # 人脸图片保存文件夹
predictor_path = os.path.join(models_folder_path, 'shape_predictor_68_face_landmarks.dat') # 模型路径
image_face_path = os.path.join(faces_folder_path, 'test.jpg') # 人脸图片路径
#image_face_path = os.path.join(faces_folder_path, 'test.jpg') # 人脸图片路径
print(image_face_path)
detector = dlib.get_frontal_face_detector() # dlib的正向人脸检测器
predictor = dlib.shape_predictor(predictor_path) # dlib的人脸形状检测器
#predictor = dlib.shape_predictor("./model/shape_predictor_68_face_landmarks.dat") # dlib的人脸形状检测器
print(predictor_path)
def get_image_size(image):
"""
获取图片大小(高度,宽度)
:param image: image
:return: (高度,宽度)
"""
image_size = (image.shape[0], image.shape[1])
return image_size
def get_face_landmarks(image, face_detector, shape_predictor):
"""
获取人脸标志,68个特征点
:param image: image
:param face_detector: dlib.get_frontal_face_detector
:param shape_predictor: dlib.shape_predictor
:return: np.array([[],[]]), 68个特征点
"""
dets = face_detector(image, 1)
num_faces = len(dets)
if num_faces == 0:
print("Sorry, there were no faces found.")
return None
shape = shape_predictor(image, dets[0])
face_landmarks = np.array([[p.x, p.y] for p in shape.parts()])
return face_landmarks
def get_face_mask(image_size, face_landmarks):
"""
获取人脸掩模
:param image_size: 图片大小
:param face_landmarks: 68个特征点
:return: image_mask, 掩模图片
"""
mask = np.zeros(image_size, dtype=np.uint8)
points = np.concatenate([face_landmarks[0:16], face_landmarks[26:17:-1]])
cv2.fillPoly(img=mask, pts=[points], color=255)
# mask = np.zeros(image_size, dtype=np.uint8)
# points = cv2.convexHull(face_landmarks) # 凸包
# cv2.fillConvexPoly(mask, points, color=255)
return mask
def get_affine_image(image1, image2, face_landmarks1, face_landmarks2):
"""
获取图片1仿射变换后的图片
:param image1: 图片1, 要进行仿射变换的图片
:param image2: 图片2, 只要用来获取图片大小,生成与之大小相同的仿射变换图片
:param face_landmarks1: 图片1的人脸特征点
:param face_landmarks2: 图片2的人脸特征点
:return: 仿射变换后的图片
"""
three_points_index = [18, 8, 25]
M = cv2.getAffineTransform(face_landmarks1[three_points_index].astype(np.float32),
face_landmarks2[three_points_index].astype(np.float32))
dsize = (image2.shape[1], image2.shape[0])
affine_image = cv2.warpAffine(image1, M, dsize)
return affine_image.astype(np.uint8)
def get_mask_center_point(image_mask):
"""
获取掩模的中心点坐标
:param image_mask: 掩模图片
:return: 掩模中心
"""
image_mask_index = np.argwhere(image_mask > 0)
miny, minx = np.min(image_mask_index, axis=0)
maxy, maxx = np.max(image_mask_index, axis=0)
center_point = ((maxx + minx) // 2, (maxy + miny) // 2)
return center_point
def get_mask_union(mask1, mask2):
"""
获取两个掩模掩盖部分的并集
:param mask1: mask_image, 掩模1
:param mask2: mask_image, 掩模2
:return: 两个掩模掩盖部分的并集
"""
mask = np.min([mask1, mask2], axis=0) # 掩盖部分并集
mask = ((cv2.blur(mask, (5, 5)) == 255) * 255).astype(np.uint8) # 缩小掩模大小
mask = cv2.blur(mask, (3, 3)).astype(np.uint8) # 模糊掩模
return mask
def skin_color_adjustment(im1, im2, mask=None):
"""
肤色调整
:param im1: 图片1
:param im2: 图片2
:param mask: 人脸 mask. 如果存在,使用人脸部分均值来求肤色变换系数;否则,使用高斯模糊来求肤色变换系数
:return: 根据图片2的颜色调整的图片1
"""
if mask is None:
im1_ksize = 55
im2_ksize = 55
im1_factor = cv2.GaussianBlur(im1, (im1_ksize, im1_ksize), 0).astype(np.float)
im2_factor = cv2.GaussianBlur(im2, (im2_ksize, im2_ksize), 0).astype(np.float)
else:
im1_face_image = cv2.bitwise_and(im1, im1, mask=mask)
im2_face_image = cv2.bitwise_and(im2, im2, mask=mask)
im1_factor = np.mean(im1_face_image, axis=(0, 1))
im2_factor = np.mean(im2_face_image, axis=(0, 1))
im1 = np.clip((im1.astype(np.float) * im2_factor / np.clip(im1_factor, 1e-6, None)), 0, 255).astype(np.uint8)
return im1
def main():
print(image_face_path)
filename = "test.jpg"
im1=cv2.imread(filename)
#im1 = cv2.imread(image_face_path) # face_image
im1 = cv2.resize(im1, (600, im1.shape[0] * 600 // im1.shape[1]))
landmarks1 = get_face_landmarks(im1, detector, predictor) # 68_face_landmarks
if landmarks1 is None:
print('{}:检测不到人脸'.format(image_face_path))
exit(1)
im1_size = get_image_size(im1) # 脸图大小
im1_mask = get_face_mask(im1_size, landmarks1) # 脸图人脸掩模
cam = cv2.VideoCapture("1.mp4")
while True:
ret_val, im2 = cam.read() # camera_image
landmarks2 = get_face_landmarks(im2, detector, predictor) # 68_face_landmarks
if landmarks2 is not None:
im2_size = get_image_size(im2) # 摄像头图片大小
im2_mask = get_face_mask(im2_size, landmarks2) # 摄像头图片人脸掩模
affine_im1 = get_affine_image(im1, im2, landmarks1, landmarks2) # im1(脸图)仿射变换后的图片
affine_im1_mask = get_affine_image(im1_mask, im2, landmarks1, landmarks2) # im1(脸图)仿射变换后的图片的人脸掩模
union_mask = get_mask_union(im2_mask, affine_im1_mask) # 掩模合并
# affine_im1_face_image = cv2.bitwise_and(affine_im1, affine_im1, mask=union_mask) # im1(脸图)的脸
# im2_face_image = cv2.bitwise_and(im2, im2, mask=union_mask) # im2(摄像头图片)的脸
# cv2.imshow('affine_im1_face_image', affine_im1_face_image)
# cv2.imshow('im2_face_image', im2_face_image)
affine_im1 = skin_color_adjustment(affine_im1, im2, mask=union_mask) # 肤色调整
point = get_mask_center_point(affine_im1_mask) # im1(脸图)仿射变换后的图片的人脸掩模的中心点
seamless_im = cv2.seamlessClone(affine_im1, im2, mask=union_mask, p=point, flags=cv2.NORMAL_CLONE) # 进行泊松融合
# cv2.imshow('affine_im1', affine_im1)
# cv2.imshow('im2', im2)
cv2.imshow('seamless_im', seamless_im)
else:
cv2.imshow('seamless_im', im2)
if cv2.waitKey(1) == 27: # 按Esc退出
break
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
?
? ④实验结果 将甄嬛传中甄嬛的脸换成周迅的脸。
|