本文代码及图片下载地址
1.jpg
使用 OpenCV 的级联分类器 CascadeClassifier 加载人脸识别预训练模型 haarcascade_frontalface_default.xml,该模型使用 AdaBoost 算法,运行速度十分快,在2013年12月19日上传。
安装库
pip install opencv-python
PS:该分类器仅适用于正面人脸
import cv2
# 读取文件
image = '1.jpg'
model = 'haarcascade_frontalface_default.xml'
image = cv2.imread(image) # 读取图片
model = cv2.CascadeClassifier(model) # 加载模型
# 人脸检测
faces = model.detectMultiScale(image)
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), thickness=2) # 画出人脸矩形框
# 显示和保存图片
cv2.imshow('result', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('result.jpg', image)
print('已保存')
图片尺寸会被统一,仍需优化
import cv2
import numpy
import random
from PIL import Image
from pathlib import Path
# 参数
HAT_PATH = './hat/' # 圣诞帽图像路径
MODEL_PATH = 'haarcascade_frontalface_default.xml' # 人脸识别预训练模型路径
# 读取
model = cv2.CascadeClassifier(MODEL_PATH)
# 读取圣诞帽
hats = [] # 圣诞帽
hats_portion = [] # 圣诞帽宽高比
for i in Path(HAT_PATH).glob('*.png'):
hat = Image.open(i)
width, height = hat.size
hats.append(hat)
hats_portion.append(width / height)
def std_size(imagePath):
'''转标准尺寸'''
pic = Image.open(imagePath)
width, height = pic.size
portion = width / height
if portion < 1: # 肖像
if portion <= 0.75:
pic_w = 960
pic_h = round(960 / portion)
box = (0, round((pic_h - 1280) / 2), 960, round(pic_h / 2 + 640))
if portion > 0.75:
pic_h = 1280
pic_w = round(1280 * portion)
box = (round((pic_w - 960) / 2), 0, round(pic_w / 2 + 480), 1280)
elif portion > 1: # 风景
if portion >= 1.3333:
pic_h = 960
pic_w = round(960 * portion)
box = (round((pic_w - 1280) / 2), 0, round(pic_w / 2 + 640), 960)
if portion < 1.3333:
pic_w = 1280
pic_h = round(1280 / portion)
box = (0, round((pic_h - 960) / 2), 1280, round(pic_h / 2 + 480))
elif portion == 1: # 正方形
(pic_w, pic_h) = (960, 960)
box = (0, 0, 960, 960)
pic = pic.resize((pic_w, pic_h))
pic = pic.crop(box)
return pic
def face_detect(pil_image):
'''人脸检测
:param pil_image: PIL读取的图片
'''
image = cv2.cvtColor(numpy.array(pil_image), cv2.COLOR_RGB2BGR) # PIL转cv
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = model.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(50, 60),
flags=cv2.CASCADE_SCALE_IMAGE
)
return faces
def get_hat(x, y, w, h):
# 设定每个帽子的概率
num = random.randint(1, 100)
if num in range(1, 17):
hat_num, offset1, offset2, offset3 = (0, 1.2, .05, .67) # hat1
elif num in range(17, 33):
hat_num, offset1, offset2, offset3 = (1, 1.3, -.4, .62) # hat2
elif num in range(33, 49):
hat_num, offset1, offset2, offset3 = (2, .9, .05, .8) # hat3
elif num in range(91, 101):
hat_num, offset1, offset2, offset3 = (3, 1.2, .05, .67) # green hat
elif num in range(49, 65):
hat_num, offset1, offset2, offset3 = (4, 1.2, -.1, 1.2) # jiao1
elif num in range(65, 81):
hat_num, offset1, offset2, offset3 = (5, 1, 0, 1.2) # jiao2
elif num in range(81, 91):
hat_num, offset1, offset2, offset3 = (6, .9, .05, 1) # tree
hat_portion = hats_portion[hat_num]
(hat_w, hat_h) = (int(w * offset1), int(w * offset1 / hat_portion))
# print('hat size:', hat_w, hat_h)
hatter = hats[hat_num].resize((hat_w, hat_h))
(hat_x, hat_y) = (int(x + w * offset2), int(y - hat_h * offset3))
hat_pos = (hat_x, hat_y)
# print('hat at:', hat_x, hat_y)
return (hatter, hat_pos)
def wear_hat(imagePath, output, show=False):
'''戴圣诞帽
:param imagePath: 图片路径
:param output: 保存路径
:param show: 是否显示中间过程
:return:
'''
# 人脸检测
image = std_size(imagePath)
faces = face_detect(image)
if show:
temp_image = image.copy()
# 戴圣诞帽
for (x, y, w, h) in faces:
# print('face at:', x, y, w, h)
(hatter, hat_pos) = get_hat(x, y, w, h)
image.paste(hatter, hat_pos, hatter)
image.save(output)
if show:
# 原图
temp_image = cv2.cvtColor(numpy.array(temp_image), cv2.COLOR_RGB2BGR)
cv2.imshow('1', temp_image)
cv2.waitKey(0)
# 人脸检测框
for (x, y, w, h) in faces:
cv2.rectangle(temp_image, (x, y), (x + w, y + h), (0, 255, 0), thickness=2)
cv2.imshow('1', temp_image)
cv2.waitKey(0)
# 戴圣诞帽
temp_image = Image.fromarray(cv2.cvtColor(temp_image, cv2.COLOR_BGR2RGB))
for (x, y, w, h) in faces:
(hatter, hat_pos) = get_hat(x, y, w, h)
temp_image.paste(hatter, hat_pos, hatter)
temp_image = cv2.cvtColor(numpy.array(temp_image), cv2.COLOR_RGB2BGR) # PIL转cv
cv2.imshow('1', temp_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
wear_hat('2.jpg', 'result.jpg', show=True)