iT邦幫忙

2022 iThome 鐵人賽

DAY 26
2

這篇教學會使用「Mediapipe 人臉偵測」搭配「邊緣羽化效果」文章,透過人臉辨識擷取出眼睛和嘴巴,再將眼睛與嘴巴合成到橘子圖片上,做出搞笑橘子臉的效果。

原文參考:Mediapipe 即時合成搞笑橘子臉

因為程式使用 Jupyter 搭配 Tensorflow 進行開發,所以請先閱讀「使用 Anaconda」和「使用 MediaPipe」,安裝對應的套件,如果不要使用 Juputer,也可參考「使用 Python 虛擬環境」,建立虛擬環境進行實作。

Mediapipe 即時合成搞笑橘子臉

即時合成搞笑橘子臉

因為整體程式碼較多,因此將詳細說明寫在程式碼的註解內,程式碼的重點如下:

  • 沿用「Mediapipe 人臉偵測」文章的範例程式。
  • 參考「邊緣羽化效果」文章,在指定位置建立遮罩 ( 指定位置需要和擷取出來的眼睛嘴巴對應 )。
  • 透過座標和人臉的大小,抓取出眼睛和嘴巴範圍內的影像。
  • 將眼睛嘴巴組合成新圖像,套用邊緣羽化的遮罩,和橘子圖片背景合成 ( 圖片下載 )。
import cv2
import mediapipe as mp
import numpy as np

cap = cv2.VideoCapture(0)                          # 讀取攝影鏡頭
mp_face_detection = mp.solutions.face_detection    # 使用人臉偵測方法

h, w = 360, 640                                    # 輸出時的影像長寬
mask = np.zeros((h, w, 3), dtype='uint8')          # 建立遮罩
cv2.ellipse(mask, (260,100),(55,35),0,0,360,(255,255,255),-1)   # 繪製左眼的橢圓形遮罩
cv2.ellipse(mask, (380,100),(55,35),0,0,360,(255,255,255),-1)   # 繪製右眼的橢圓形遮罩
cv2.ellipse(mask, (320,212),(115,66),0,0,360,(255,255,255),-1)  # 繪製嘴巴的橢圓形遮罩
mask = cv2.GaussianBlur(mask,(35,35),0)            # 將遮罩進行高斯模糊
mask = mask/255                                    # 轉換成比例

orange = cv2.imread('orange.jpg')                  # 讀取橘子圖片背景

# 人臉偵測模組啟用成功後,執行相關內容
with mp_face_detection.FaceDetection(
    model_selection=0, min_detection_confidence=0.5) as face_detection:

    if not cap.isOpened():
        print("Cannot open camera")
        exit()
    while True:
        ret, img = cap.read()                        # 讀取攝影機畫面
        if not ret:
            print("Cannot receive frame")
            break
        img = cv2.resize(img, (w, h))                # 縮小尺寸加快速度
        img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 轉換成 RGB 才能夠在 mediapipe 中使用
        results = face_detection.process(img2)       # 讀取人臉偵測資訊

        if results.detections:
            for detection in results.detections:
                s = detection.location_data.relative_bounding_box      # 取得人臉尺寸
                eye_w = int(s.width*w*0.24/2)                          # 計算眼睛寬度 ( 除以 2 計算座標使用 )
                eye_h = int(s.width*w*0.16/2)                          # 計算眼睛高度 ( 除以 2 計算座標使用 )
                mouth_w = int(s.width*w*0.5/2)                         # 計算嘴巴寬度 ( 除以 2 計算座標使用 )
                mouth_h = int(s.width*w*0.3/2)                         # 計算嘴巴高度 ( 除以 2 計算座標使用 )

                eye_r = detection.location_data.relative_keypoints[0]  # 左眼中心點座標
                eye_l = detection.location_data.relative_keypoints[1]  # 右眼中心點座標
                mouth = detection.location_data.relative_keypoints[3]  # 嘴巴中心點座標

                rcx, rcy = int(eye_r.x*w), int(eye_r.y*h)              # 計算左眼真正的座標
                lcx, lcy = int(eye_l.x*w), int(eye_l.y*h)              # 計算右眼真正的座標
                mx, my = int(mouth.x*w), int(mouth.y*h)                # 計算嘴巴真正的座標

                eye_r_img = img[rcy-eye_h:rcy+eye_h, rcx-eye_w:rcx+eye_w]      # 取出右眼的區域
                eye_r_img = cv2.resize(eye_r_img, (120,80))                    # 改變尺寸為 180x120
                eye_l_img = img[lcy-eye_h:lcy+eye_h, lcx-eye_w:lcx+eye_w]      # 取出左眼的區域
                eye_l_img = cv2.resize(eye_l_img, (120,80))                    # 改變尺寸為 180x120
                mouth_img = img[my-mouth_h:my+mouth_h, mx-mouth_w:mx+mouth_w]  # 取出嘴巴的區域
                mouth_img = cv2.resize(mouth_img, (240,144))                   # 改變尺寸為 360x216

                face = np.zeros((h, w, 3), dtype='uint8')  # 建立空白全黑畫布
                bg = orange.copy()                         # 複製 orange 圖片當作背景
                face[60:140, 200:320] =  eye_l_img         # 貼上左眼
                face[60:140, 320:440] =  eye_r_img         # 貼上右眼
                face[140:284, 200:440] =  mouth_img        # 貼上嘴巴
                face = face + 30                           # 增加亮度
                face = face/255                            # 轉換成比例
                bg = bg/255                                # 轉換成比例
                out  = bg * (1 - mask) + face * mask       # 根據比例混合
                out = (out * 255).astype('uint8')          # 轉換成數字

        cv2.imshow('oxxostudio', out)
        if cv2.waitKey(5) == ord('q'):
            break    # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()

Python 教學 - Mediapipe 即時合成搞笑橘子臉


上一篇
( Day 25 ) Mediapipe 辨識手指,用手指擦除霧氣
下一篇
( Day 27 ) Jupyter 安裝 Tensorflow
系列文
Python x AI 影像辨識好好玩32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言