Python實戰項目:為人臉照片添加口罩

来源:https://www.cnblogs.com/123456feng/archive/2022/04/25/16182300.html
-Advertisement-
Play Games

前言 好想玩點不一樣的,感覺平常的已經不能吸引大家了。想了又想,我今天給大家分享如何給人像添加口罩吧。畢竟最近疫情那麼 嚴重,也只能玩玩這個了,大家千萬別亂跑啊。 效果展示 數據集展示 數據集來源:使用了開源數據集FaceMask_CelebA github地址:https://github.com ...


前言

好想玩點不一樣的,感覺平常的已經不能吸引大家了。想了又想,我今天給大家分享如何給人像添加口罩吧。畢竟最近疫情那麼

嚴重,也只能玩玩這個了,大家千萬別亂跑啊。

效果展示

在這裡插入圖片描述

數據集展示

數據集來源:使用了開源數據集FaceMask_CelebA

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

部分人臉數據集:
在這裡插入圖片描述

口罩樣本數據集:

在這裡插入圖片描述

為人臉照片添加口罩代碼

這部分有個庫face_recognition需要安裝,如果之前沒有用過的小伙伴可能得費點功夫。

Face Recognition 庫主要封裝了dlib這一 C++ 圖形庫,通過 Python 語言將它封裝為一個非常簡單就可以實現人臉識別的 API

庫,屏蔽了人臉識別的演算法細節,大大降低了人臉識別功能的開發難度。

Python學習交流Q群:906715085###
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : 2014Vee
import 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/')

class FaceMasker:    
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 = None
    def mask(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 = False        
        for face_landmark in face_landmarks:            
        # check whether facial features meet requirement            
        skip = False            
        for facial_feature in self.KEY_FACIAL_FEATURES:                
        if facial_feature not in face_landmark:                    
 skip = True                    
 break           
if 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}')
    @staticmethod    def get_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]))        
      return int(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 += 1       
 continue    
 FaceMasker(image, BLUE_IMAGE_PATH, WHITE_IMAGE_PATH, SAVE_PATH, SAVE_PATH2, 'hog').
 mask()    
 cnt += 1    
 print(f"正在處理第{cnt}張圖片,還有{99 - cnt}張圖片")

 

掩膜生成代碼

這部分其實就是對使用的口罩樣本的二值化,因為後續要相關模型會用到
在這裡插入圖片描述

Python學習交流Q群:906715085####
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/'

def processImage(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 in range(img.size[1]):        
for x in range(img.size[0]):            
if pixdata[x, y][0] < 90:                
pixdata[x, y] = (0, 0, 0, 255)
    for y in range(img.size[1]):        
    for x in range(img.size[0]):            
    if pixdata[x, y][1] < 136:                
    pixdata[x, y] = (0, 0, 0, 255)
    for y in range(img.size[1]):        
    for x in range(img.size[0]):            
    if pixdata[x, y][2] > 0:                
    pixdata[x, y] = (255, 255, 255, 255)    
    img.save(destsoure + name, imgtype)

def run():    
# 切換到源目錄,遍歷源目錄下所有圖片    
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()

 

最後

今天又到周末了,祝大家周末愉快,玩夠了記得回來學習鴨!下一章見啦~~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第二話來了 這一章的知識緊接上一章,零基礎的小伙伴可以從上 一章學起來。當然,你也可以收藏起來慢慢學習,學習是不可操之過急的啦… 列表 Python學習交流Q群:906715085### print(" 創建列表 "); list1 = ['JAVA', 'Hello', 'Python', 'VS ...
  • 綜合前述的類、函數、matplotlib等,完成一個隨機移動的過程(註意要確定移動的次數,比如10萬次),每次行走都完全是隨機的,沒有明確的方向,結果是由一系列隨機決策確定的,最後顯示出每次移動的位置的圖表。 思考: 1)每次走動多少個像素,由隨機函數決定,每次移動方向也隨機確定。由隨機方向和隨機像 ...
  • 作者:雙子孤狼 來源:https://blog.csdn.net/zwx900102/article/details/115446997 任何一個服務如果沒有監控,那就是兩眼一抹黑,無法知道當前服務的運行情況,也就無法對可能出現的異常狀況進行很好的處理,所以對任意一個服務來說,監控都是必不可少的。 ...
  • 1.開發環境 新建一個工程-配置jdk版本-配置maven 2.創建maven工程 修改打包方式為jar 導入依賴: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" x ...
  • 在前後端分離的項目中後端返回的格式一定要友好,不然會對前端的開發人員帶來很多的工作量。那麼SpringBoot如何做到統一的後端返回格式呢?今天我們一起來看看。 為什麼要對SpringBoot返回統一的標準格式 在預設情況下,SpringBoot的返回格式常見的有三種: 返回String @GetM ...
  • Python基礎知識 今天給大家分享一些Python的基礎知識,想要蓋好大房子,不把地基打扎實打牢怎麼行呢?所以,今天咱們就來學習基礎知識, 這樣後期學習Python的時候才能更容易掌握,更輕鬆的學會Python的使用。別跟我說你都學過了,看完再告訴我… 一、編程基礎 1.基本的輸入輸出: prin ...
  • 最近一個粉絲說,他面試了4個公司,有三個公司問他:“Spring Boot 中自動裝配機制的原理” 他回答了,感覺沒回答錯誤,但是怎麼就沒給offer呢? 對於這個問題,看看普通人和高手該如何回答。 普通人: 嗯… Spring Boot裡面的自動裝配,就是@EnableAutoConfigurat ...
  • 首發地址:day01-從一個基礎的socket服務說起 教程說明:C++高性能網路服務保姆級教程 本節目的 實現一個基於socket的echo服務端和客戶端 服務端監聽流程 第一步:使用socket函數創建套接字 在linux中,一切都是文件,所有文件都有一個int類型的編號,稱為文件描述符。服務端 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...