基于OpenCV的面部交换
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                基于OpenCV的面部交换
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                需要裝python庫
OpenCV
dlib
docopt(根據打開方式選擇是否裝)
# -*- coding: UTF-8
#本電腦試運行 命令 python F:python_projectswapswapface.py E:picturefacexx.jpg E:picturefaceangelababy.jpg
#聲明編碼格式 方便中文注釋~
#實現命令行解析器 打開格式python 代碼文件路徑 圖片1路徑 圖片2路徑
"""
swapface.py
function:put one face's facial features onto another
based on OpenCV,dlib
this moudle used docopt
Usage: faceswap [options] <image1> [<image2>]
Options:
      -v --version      查看版本號
      -h --help         顯示這個幫助文檔
      -s --see          查看圖片
      -c --combine      換臉
"""
#命令行參數解析說明  [options]指定特定選項 完成特定任務
import cv2   #導入調用opencv庫
import dlib  #導入dlib庫
import numpy as np   #以np別名導入docopt
from docopt import docopt #導入docopt包中的docopt到文件
__version__ = 'swapface 1.0'   #版本號
#以下是一些要用的常量及路徑初始化部分
PREDICTOR_PATH = "F:/python_project/shape_predictor_68_face_landmarks.dat"   #訓練模式的路徑 注意斜杠別反了
#圖像放縮因子
SCALE_FACTOR = 1
FEATHER_AMOUNT = 11
FACE_POINTS = list(range(17, 68))   #臉
MOUTH_POINTS = list(range(48, 61))   #嘴
RIGHT_BROW_POINTS = list(range(17, 22))   #右眉
LEFT_BROW_POINTS = list(range(22, 27))   #左眉
RIGHT_EYE_POINTS = list(range(36, 42))   #右眼
LEFT_EYE_POINTS = list(range(42, 48))   #左眼
NOSE_POINTS = list(range(27, 35))   #鼻
JAW_POINTS = list(range(0, 17))   #下巴
#元組 選取左右眉,左右眼,鼻子,嘴巴  位置的特征點索引
ALIGN_POINTS = (LEFT_BROW_POINTS + RIGHT_EYE_POINTS + LEFT_EYE_POINTS +
                               RIGHT_BROW_POINTS + NOSE_POINTS + MOUTH_POINTS)
#元組轉列表 選取第二張臉對應面部特征用于覆蓋到第一張臉
OVERLAY_POINTS = [
    LEFT_EYE_POINTS + RIGHT_EYE_POINTS + LEFT_BROW_POINTS + RIGHT_BROW_POINTS,
    NOSE_POINTS + MOUTH_POINTS,
]
#定義用于顏色矯正的模糊量,作為瞳孔距離的系數
COLOUR_CORRECT_BLUR_FRAC = 0.6
#實例化臉部檢測器
detector = dlib.get_frontal_face_detector()
#根據路徑加載訓練模型 并 實例化特征提取器
predictor = dlib.shape_predictor(PREDICTOR_PATH)
#定義多臉和無臉類處理異常 以及 未打開異常
class TooManyFaces(Exception):
    pass
class NoFaces(Exception):
    pass
class OpenFailed(Exception):
    pass
#顯示圖片
def show_image(board,path,time):
    # 讀取這個圖片
    image = cv2.imread(path,cv2.IMREAD_COLOR)
    # 初始化一個名為Combine的窗口
    cv2.namedWindow(board, flags=0)
    # 顯示圖片
    cv2.imshow(board, image)
    # 等待按鍵釋放窗口
    if(time == 0):
        cv2.waitKey(time)
#獲取特征點函數
def get_landmarks(im):
    #特征檢測器
    rects = detector(im, 1)
    #如果檢測到多張臉 拋多臉異常
    if len(rects) > 1:
        raise TooManyFaces
    #如果沒有檢測到臉 拋無臉異常
    if len(rects) == 0:
        raise NoFaces
    #返回一個n*2維的矩陣,該矩陣由檢測到的臉部特征點坐標組成 特征提取器predictor
    return np.matrix([[p.x, p.y] for p in predictor(im, rects[0]).parts()])
#繪制凸多邊形
def draw_convex_hull(im, points, color):
    points = points.astype(np.int32)
    #檢查一個曲線是否有凸性缺陷并糾正
    points = cv2.convexHull(points)
    #凸多邊形填充成想要的顏色
    cv2.fillConvexPoly(im, points, color=color)
#獲取面部的掩碼
def get_face_mask(im, landmarks):
    im = np.zeros(im.shape[:2], dtype=np.float64)
    for group in OVERLAY_POINTS:
        draw_convex_hull(im,
                         landmarks[group],
                         color=1)
    im = np.array([im, im, im]).transpose((1,2,0))
    #應用高斯模糊
    im = (cv2.GaussianBlur(im, (FEATHER_AMOUNT, FEATHER_AMOUNT), 0) > 0) * 1.0
    im = cv2.GaussianBlur(im, (FEATHER_AMOUNT, FEATHER_AMOUNT), 0)
    return im
#使用普氏分析(Procrustes analysis)調整臉部 包括傾斜位置不同等等都可以調整
def transformation_from_points(points1,points2):
    #輸入矩陣轉換為64位float類型
    points1 = points1.astype(np.float64)
    points2 = points2.astype(np.float64)
    #對矩陣格列取均值,求矩心
    c1 = np.mean(points1,axis=0)
    c2 = np.mean(points2,axis=0)
    #每一個點集減去它的矩心。這兩個矩心c1和c2可以用來找到完整的解決方案。
    points1 -= c1
    points2 -= c2
    #標準差
    s1 = np.std(points1)
    s2 = np.std(points2)
    #除去標準差 這消除了問題的組件縮放偏差。
    points1 /= s1
    points2 /= s2
    U, S, Vt = np.linalg.svd(points1.T * points2)
    R = (U * Vt).T
    #公式
    return np.vstack([np.hstack(((s2 / s1) * R,
                                 c2.T - (s2 / s1) * R * c1.T)),
                      np.matrix([0., 0., 1.])])
#讀取圖片文件并獲取特征點
def read_im_and_landmarks(fname):
    #以RGB(紅綠藍)模式讀取圖片 就是讀入彩色圖片
    im = cv2.imread(fname,cv2.IMREAD_COLOR)
    if im is None:
        raise OpenFailed
    #對圖片進行適當的放縮
    im = cv2.resize(im, (im.shape[1] * SCALE_FACTOR,
                         im.shape[0] * SCALE_FACTOR))
    #獲取特征點
    s = get_landmarks(im)
    #返回圖片和特征點組成的元組
    return im, s
#變換圖像
def warp_im(im,M,dshape):
    output_im = np.zeros(dshape,dtype=im.dtype)
    #仿射函數,能對圖像進行幾何變換 三個參數 輸入圖像 變換矩陣np.float32類型 變換之后圖像
    cv2.warpAffine(im,
                   M[:2],
                   (dshape[1],dshape[0]),
                   dst=output_im,
                   borderMode=cv2.BORDER_TRANSPARENT,
                   flags=cv2.WARP_INVERSE_MAP)
    return output_im
#修正顏色 使得兩張圖片拼接時顯得更加自然
def correct_colours(im1,im2,landmarks1): #傳入圖1和圖2以及圖1的特征點
    blur_amount = COLOUR_CORRECT_BLUR_FRAC * np.linalg.norm(
        np.mean(landmarks1[LEFT_EYE_POINTS],axis=0) -
        np.mean(landmarks1[RIGHT_EYE_POINTS],axis=0))
    blur_amount = int(blur_amount)
    if blur_amount % 2 == 0:
        blur_amount += 1
    #高斯模糊
    im1_blur = cv2.GaussianBlur(im1,(blur_amount,blur_amount),0)
    im2_blur = cv2.GaussianBlur(im2,(blur_amount,blur_amount),0)
    #避免下面出現0除
    im2_blur += (128 * (im2_blur <= 1.0)).astype(im2_blur.dtype)
    return (im2.astype(np.float64) * im1_blur.astype(np.float64) / im2_blur.astype(np.float64))
#主過程函數
def main():
    arguments = docopt(__doc__, version=__version__)   #調用函數返回arguments字典型變量,記錄了選項是否被選用了,參數的值是什么等信息,當程序從命令行運行時,我們就是根據arguments變量的記錄來得知用戶輸入的選項和參數信息。
    if(arguments['--see'] != False):
        if(arguments['<image1>'] is not None):
            show_image('image1',arguments['<image1>'],1)
        if(arguments['<image2>'] is not None):
            show_image('image2',arguments['<image2>'],1)
    if(arguments['--combine'] == False):
        exit(0)
    # 1.獲取圖像與特征點
    im1,landmarks1 = read_im_and_landmarks(arguments['<image1>'])
    im2,landmarks2 = read_im_and_landmarks(arguments['<image2>'])
    # 2.選取兩組圖像特征矩陣中所需要的面部部位 計算轉換信息 返回變換矩陣
    M = transformation_from_points(landmarks1[ALIGN_POINTS],landmarks2[ALIGN_POINTS])
    # 3.獲取im2的面部掩碼
    mask = get_face_mask(im2,landmarks2)
    # 4.將im2的掩碼進行變化,使得與im1相符
    warped_mask = warp_im(mask,M,im1.shape)
    # 5.將二者的掩碼進行連通
    combined_mask = np.max([get_face_mask(im1,landmarks1),warped_mask],axis=0)
    # 6.將第二幅圖調整到與第一幅圖相符
    warped_im2 = warp_im(im2,M,im1.shape)
    # 7.將im2的皮膚顏色進行修正,使其和im1的顏色盡量協調
    warped_corrected_im2 = correct_colours(im1,warped_im2,landmarks1)
    # 組合圖像,獲得結果
    output_im = im1 * (1.0 - combined_mask) + warped_corrected_im2 * combined_mask
    SavePath = 'F:/python_project/output.jpg'
    #保存圖像 默認項目文件夾
    cv2.imwrite(SavePath,output_im)
    show_image('Combine',SavePath,0)
if __name__=='__main__':
    main()
命令行里運行 根據幫助文檔 python 程序路徑 -c 圖片1路徑 圖片2路徑
總結
以上是生活随笔為你收集整理的基于OpenCV的面部交换的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: jcenter maven 库
- 下一篇: kpw3 kindle越狱过程总结
