0


Python实战——为人脸照片添加口罩

文章目录

效果展示

请添加图片描述在这里插入图片描述请添加图片描述请添加图片描述

数据集展示

数据集来源:使用了开源数据集FaceMask_CelebA

github地址:https://github.com/sevenHsu/FaceMask_CelebA.git

部分人脸数据集:
在这里插入图片描述
口罩样本数据集:
在这里插入图片描述

为人脸照片添加口罩代码

这部分有个库face_recognition需要安装,如果之前没有用过的小伙伴可能得费点功夫。
Face Recognition 库主要封装了dlib这一 C++ 图形库,通过 Python 语言将它封装为一个非常简单就可以实现人脸识别的 API 库,屏蔽了人脸识别的算法细节,大大降低了人脸识别功能的开发难度。
请添加图片描述在这里插入图片描述

#!/usr/bin/env python# -*- coding: utf-8 -*-# @Author  : 2014Veeimport os
import numpy as np
from PIL import Image, ImageFile

__version__ ='0.3.0'

IMAGE_DIR = os.path.dirname('E:/play/FaceMask_CelebA-master/facemask_image/')
WHITE_IMAGE_PATH = os.path.join(IMAGE_DIR,'front_14.png')
BLUE_IMAGE_PATH = os.path.join(IMAGE_DIR,'front_14.png')
SAVE_PATH = os.path.dirname('E:/play/FaceMask_CelebA-master/save/synthesis/')
SAVE_PATH2 = os.path.dirname('E:/play/FaceMask_CelebA-master/save/masks/')classFaceMasker:
    KEY_FACIAL_FEATURES =('nose_bridge','chin')def__init__(self, face_path, mask_path, white_mask_path, save_path, save_path2, model='hog'):
        self.face_path = face_path
        self.mask_path = mask_path
        self.save_path = save_path
        self.save_path2 = save_path2
        self.white_mask_path = white_mask_path
        self.model = model
        self._face_img: ImageFile =None
        self._black_face_img =None
        self._mask_img: ImageFile =None
        self._white_mask_img =Nonedefmask(self):import face_recognition

        face_image_np = face_recognition.load_image_file(self.face_path)
        face_locations = face_recognition.face_locations(face_image_np, model=self.model)
        face_landmarks = face_recognition.face_landmarks(face_image_np, face_locations)
        self._face_img = Image.fromarray(face_image_np)
        self._mask_img = Image.open(self.mask_path)
        self._white_mask_img = Image.open(self.white_mask_path)
        self._black_face_img = Image.new('RGB', self._face_img.size,0)

        found_face =Falsefor face_landmark in face_landmarks:# check whether facial features meet requirement
            skip =Falsefor facial_feature in self.KEY_FACIAL_FEATURES:if facial_feature notin face_landmark:
                    skip =Truebreakif skip:continue# mask face
            found_face =True
            self._mask_face(face_landmark)if found_face:# save
            self._save()else:print('Found no face.')def_mask_face(self, face_landmark:dict):
        nose_bridge = face_landmark['nose_bridge']
        nose_point = nose_bridge[len(nose_bridge)*1//4]
        nose_v = np.array(nose_point)

        chin = face_landmark['chin']
        chin_len =len(chin)
        chin_bottom_point = chin[chin_len //2]
        chin_bottom_v = np.array(chin_bottom_point)
        chin_left_point = chin[chin_len //8]
        chin_right_point = chin[chin_len *7//8]# split mask and resize
        width = self._mask_img.width
        height = self._mask_img.height
        width_ratio =1.2
        new_height =int(np.linalg.norm(nose_v - chin_bottom_v))# left
        mask_left_img = self._mask_img.crop((0,0, width //2, height))
        mask_left_width = self.get_distance_from_point_to_line(chin_left_point, nose_point, chin_bottom_point)
        mask_left_width =int(mask_left_width * width_ratio)
        mask_left_img = mask_left_img.resize((mask_left_width, new_height))# right
        mask_right_img = self._mask_img.crop((width //2,0, width, height))
        mask_right_width = self.get_distance_from_point_to_line(chin_right_point, nose_point, chin_bottom_point)
        mask_right_width =int(mask_right_width * width_ratio)
        mask_right_img = mask_right_img.resize((mask_right_width, new_height))# merge mask
        size =(mask_left_img.width + mask_right_img.width, new_height)
        mask_img = Image.new('RGBA', size)
        mask_img.paste(mask_left_img,(0,0), mask_left_img)
        mask_img.paste(mask_right_img,(mask_left_img.width,0), mask_right_img)# rotate mask
        angle = np.arctan2(chin_bottom_point[1]- nose_point[1], chin_bottom_point[0]- nose_point[0])
        rotated_mask_img = mask_img.rotate(angle, expand=True)# calculate mask location
        center_x =(nose_point[0]+ chin_bottom_point[0])//2
        center_y =(nose_point[1]+ chin_bottom_point[1])//2

        offset = mask_img.width //2- mask_left_img.width
        radian = angle * np.pi /180
        box_x = center_x +int(offset * np.cos(radian))- rotated_mask_img.width //2
        box_y = center_y +int(offset * np.sin(radian))- rotated_mask_img.height //2# add mask
        self._face_img.paste(mask_img,(box_x, box_y), mask_img)# split mask and resize
        width = self._white_mask_img.width
        height = self._white_mask_img.height
        width_ratio =1.2
        new_height =int(np.linalg.norm(nose_v - chin_bottom_v))# left
        mask_left_img = self._white_mask_img.crop((0,0, width //2, height))
        mask_left_width = self.get_distance_from_point_to_line(chin_left_point, nose_point, chin_bottom_point)
        mask_left_width =int(mask_left_width * width_ratio)
        mask_left_img = mask_left_img.resize((mask_left_width, new_height))# right
        mask_right_img = self._white_mask_img.crop((width //2,0, width, height))
        mask_right_width = self.get_distance_from_point_to_line(chin_right_point, nose_point, chin_bottom_point)
        mask_right_width =int(mask_right_width * width_ratio)
        mask_right_img = mask_right_img.resize((mask_right_width, new_height))# merge mask
        size =(mask_left_img.width + mask_right_img.width, new_height)
        mask_img = Image.new('RGBA', size)
        mask_img.paste(mask_left_img,(0,0), mask_left_img)
        mask_img.paste(mask_right_img,(mask_left_img.width,0), mask_right_img)# rotate mask
        angle = np.arctan2(chin_bottom_point[1]- nose_point[1], chin_bottom_point[0]- nose_point[0])
        rotated_mask_img = mask_img.rotate(angle, expand=True)# calculate mask location
        center_x =(nose_point[0]+ chin_bottom_point[0])//2
        center_y =(nose_point[1]+ chin_bottom_point[1])//2

        offset = mask_img.width //2- mask_left_img.width
        radian = angle * np.pi /180
        box_x = center_x +int(offset * np.cos(radian))- rotated_mask_img.width //2
        box_y = center_y +int(offset * np.sin(radian))- rotated_mask_img.height //2# add mask
        self._black_face_img.paste(mask_img,(box_x, box_y), mask_img)def_save(self):
        path_splits = os.path.splitext(self.face_path)# new_face_path = self.save_path + '/' + os.path.basename(self.face_path) + '-with-mask' + path_splits[1]# new_face_path2 = self.save_path2 + '/' + os.path.basename(self.face_path) + '-binary' + path_splits[1]
        new_face_path = self.save_path +'/'+ os.path.basename(self.face_path)+'-with-mask'+ path_splits[1]
        new_face_path2 = self.save_path2 +'/'+ os.path.basename(self.face_path)+'-binary'+ path_splits[1]
        self._face_img.save(new_face_path)
        self._black_face_img.save(new_face_path2)#         print(f'Save to {new_face_path}')@staticmethoddefget_distance_from_point_to_line(point, line_point1, line_point2):
        distance = np.abs((line_point2[1]- line_point1[1])* point[0]+(line_point1[0]- line_point2[0])* point[1]+(line_point2[0]- line_point1[0])* line_point1[1]+(line_point1[1]- line_point2[1])* line_point1[0])/ \
                   np.sqrt((line_point2[1]- line_point1[1])*(line_point2[1]- line_point1[1])+(line_point1[0]- line_point2[0])*(line_point1[0]- line_point2[0]))returnint(distance)# FaceMasker("/home/aistudio/data/人脸.png", WHITE_IMAGE_PATH, True, 'hog').mask()from pathlib import Path

images = Path("E:/play/FaceMask_CelebA-master/bbox_align_celeba").glob("*")
cnt =0for image in images:if cnt <1:
        cnt +=1continue
    FaceMasker(image, BLUE_IMAGE_PATH, WHITE_IMAGE_PATH, SAVE_PATH, SAVE_PATH2,'hog').mask()
    cnt +=1print(f"正在处理第{cnt}张图片,还有{99- cnt}张图片")

掩膜生成代码

这部分其实就是对使用的口罩样本的二值化,因为后续要相关模型会用到
请添加图片描述请添加图片描述

import os
from PIL import Image

# 源目录# MyPath = 'E:/play/FaceMask_CelebA-master/facemask_image/'
MyPath ='E:/play/FaceMask_CelebA-master/save/masks/'# 输出目录
OutPath ='E:/play/FaceMask_CelebA-master/save/Binarization/'defprocessImage(filesoure, destsoure, name, imgtype):'''
    filesoure是存放待转换图片的目录
    destsoure是存在输出转换后图片的目录
    name是文件名
    imgtype是文件类型
    '''
    imgtype ='bmp'if imgtype =='.bmp'else'png'# 打开图片
    im = Image.open(filesoure + name)# =============================================================================#     #缩放比例#     rate =max(im.size[0]/640.0 if im.size[0] > 60 else 0, im.size[1]/1136.0 if im.size[1] > 1136 else 0)#     if rate:#         im.thumbnail((im.size[0]/rate, im.size[1]/rate))# =============================================================================

    img = im.convert("RGBA")
    pixdata = img.load()# 二值化for y inrange(img.size[1]):for x inrange(img.size[0]):if pixdata[x, y][0]<90:
                pixdata[x, y]=(0,0,0,255)for y inrange(img.size[1]):for x inrange(img.size[0]):if pixdata[x, y][1]<136:
                pixdata[x, y]=(0,0,0,255)for y inrange(img.size[1]):for x inrange(img.size[0]):if pixdata[x, y][2]>0:
                pixdata[x, y]=(255,255,255,255)
    img.save(destsoure + name, imgtype)defrun():# 切换到源目录,遍历源目录下所有图片
    os.chdir(MyPath)for i in os.listdir(os.getcwd()):# 检查后缀
        postfix = os.path.splitext(i)[1]
        name = os.path.splitext(i)[0]
        name2 = name.split('.')if name2[1]=='jpg-binary'or name2[1]=='png-binary':
            processImage(MyPath, OutPath, i, postfix)if __name__ =='__main__':
    run()

本文转载自: https://blog.csdn.net/qq_52118067/article/details/124334872
版权归原作者 .别拖至春天. 所有, 如有侵权,请联系我们删除。

“Python实战&mdash;&mdash;为人脸照片添加口罩”的评论:

还没有评论