欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python 人脸五官关键点检测 + 自动识别人脸给头像戴口罩

程序员文章站 2022-07-12 20:52:20
...

目标

输入一张人脸头像图片,可以自动识别其五官关键点,并加上口罩

步骤

口罩图片处理

到网上找到一张N95口罩图片,去掉其背景

Python 人脸五官关键点检测 + 自动识别人脸给头像戴口罩

关于图片去除背景,可以使用PS 的魔棒抠图,也可以找到一些在线网站,如 https://www.zenfotomatic.com/

检测人脸关键点

引入包 dlib,其自带人脸特征提取器

百度下载文件 shape_predictor_68_face_landmarks.dat

	PREDICTOR_PATH = "shape_predictor_68_face_landmarks.dat"
	detector = dlib.get_frontal_face_detector()
	predictor = dlib.shape_predictor(PREDICTOR_PATH)
	rects = detector(img, 1)

检测关键点函数为

def key_points(img):
	points_key = []
	PREDICTOR_PATH = "shape_predictor_68_face_landmarks.dat"
	detector = dlib.get_frontal_face_detector()
	predictor = dlib.shape_predictor(PREDICTOR_PATH)
	rects = detector(img, 1)

	for i in range(len(rects)):
		landmarks = np.matrix([[p.x, p.y] for p in predictor(img, rects[i]).parts()])
		print(landmarks)
		for idx, point in enumerate(landmarks):    # 特定点,可直接提取
			print(idx)
			pos = (point[0, 0], point[0, 1])
			print(pos)
			if idx in [2, 8, 14, 28]:
				points_key.append(pos)
				# cv2.circle(img, pos, 2, (255, 0, 0))

其中landmarks为68个关键点坐标矩阵

我们取2,8,14,28作为口罩关键点,即下图3,9,15,29,放入points_key中

Python 人脸五官关键点检测 + 自动识别人脸给头像戴口罩

 戴口罩

def wear_mask(mask_img, face_img):
	h_mask, w_mask = mask_img.shape[:2]   # 高,宽
	gray = cv2.cvtColor(face_img, cv2.COLOR_BGR2GRAY)
	face_keys = key_points(gray)
	left = face_keys[0][0]
	jaw = face_keys[1][1]
	right = face_keys[2][0]
	nose = face_keys[3][1]
	w_mouth = right - left
	h_mouth = jaw - nose
	mask_img = cv2.resize(mask_img, (w_mouth, h_mouth))
	
	mask_channels = cv2.split(mask_img)
	face_channels = cv2.split(face_img)
	b, g, r, a = cv2.split(mask_img)
	ans_img = face_img.copy()
	print(nose, nose+h_mouth, left, left+w_mouth)
	for c in range(0, 3):
		face_channels[c] = np.array(face_channels[c], dtype=np.uint8)
		k = np.uint8((255.0-a)/255.0)
		face_channels[c][nose:nose+h_mouth, left:left+w_mouth] = face_channels[c][nose:nose+h_mouth, left:left+w_mouth]*k
		mask_channels[c] *= np.array(a/255, dtype=np.uint8)
		face_channels[c][nose:nose+h_mouth, left:left+w_mouth] += np.array(mask_channels[c], dtype=np.uint8)
	ans = cv2.merge(face_channels)

	return ans

将脸图转化为灰度图,调用检测函数监测关键点。

left,jaw,right,nose分别为上面四个点左右的x坐标,和上下的y坐标,由此可得出口罩要放置的高度宽度

将口罩图片 resize 到该尺寸

之后需进行两图片的四通道叠加

cv2.split 可提取图片各通道

遍历每个通道,k为透明比例

最后cv2.merge合并通道

效果

Python 人脸五官关键点检测 + 自动识别人脸给头像戴口罩

Python 人脸五官关键点检测 + 自动识别人脸给头像戴口罩

代码

# -*- coding: utf-8 -*-
# @Author: zhr
# @Date:   2020-01-22 15:28:26
# @Last Modified by:   zhr
# @Last Modified time: 2020-02-20 15:21:50
import cv2
import numpy as np 
import dlib

def key_points(img):
	points_key = []
	PREDICTOR_PATH = "shape_predictor_68_face_landmarks.dat"
	detector = dlib.get_frontal_face_detector()
	predictor = dlib.shape_predictor(PREDICTOR_PATH)
	rects = detector(img, 1)

	for i in range(len(rects)):
		landmarks = np.matrix([[p.x, p.y] for p in predictor(img, rects[i]).parts()])
		print(landmarks)
		for idx, point in enumerate(landmarks):    # 特定点,可直接提取
			print(idx)
			pos = (point[0, 0], point[0, 1])
			print(pos)
			if idx in [2, 8, 14, 28]:
				points_key.append(pos)
				# cv2.circle(img, pos, 2, (255, 0, 0))

	return(points_key)

def wear_mask(mask_img, face_img):
	h_mask, w_mask = mask_img.shape[:2]   # 高,宽
	gray = cv2.cvtColor(face_img, cv2.COLOR_BGR2GRAY)
	face_keys = key_points(gray)
	left = face_keys[0][0]
	jaw = face_keys[1][1]
	right = face_keys[2][0]
	nose = face_keys[3][1]
	w_mouth = right - left
	h_mouth = jaw - nose
	mask_img = cv2.resize(mask_img, (w_mouth, h_mouth))
	
	mask_channels = cv2.split(mask_img)
	face_channels = cv2.split(face_img)
	b, g, r, a = cv2.split(mask_img)
	ans_img = face_img.copy()
	print(nose, nose+h_mouth, left, left+w_mouth)
	for c in range(0, 3):
		face_channels[c] = np.array(face_channels[c], dtype=np.uint8)
		k = np.uint8((255.0-a)/255.0)
		face_channels[c][nose:nose+h_mouth, left:left+w_mouth] = face_channels[c][nose:nose+h_mouth, left:left+w_mouth]*k
		mask_channels[c] *= np.array(a/255, dtype=np.uint8)
		face_channels[c][nose:nose+h_mouth, left:left+w_mouth] += np.array(mask_channels[c], dtype=np.uint8)
	ans = cv2.merge(face_channels)

	return ans

face_img = cv2.imread("try10.jpg")
mask_img = cv2.imread("ma.png", -1)
ans_img = wear_mask(mask_img, face_img)

cv2.imwrite("ans10.jpg", ans_img)
cv2.imshow("ans", ans_img)
cv2.waitKey(0)

 

相关标签: Python杂七杂八