《OpenCV》—— dlib(換臉操作)

文章目錄

    • dlib換臉介紹
    • 仿射變換
      • 在 dlib 換臉中的應用
    • 換臉操作

dlib換臉介紹

  • dlib 換臉是基于 dlib 庫實現的一種人臉替換技術,以下是關于它的詳細介紹:
    • 原理
      • 人臉檢測:dlib 庫中包含先進的人臉檢測器,如基于 HOG(方向梯度直方圖)特征和線性分類器的方法,能夠在圖像或視頻幀中快速定位人臉的位置,確定人臉的邊界框。
      • 關鍵點檢測:利用 dlib 預訓練的形狀預測模型,如shape_predictor_68_face_landmarks.dat,可以精準定位出人臉的 68 個關鍵點,這些點分布在眼睛、眉毛、鼻子、嘴巴、下巴等部位,精確描述了人臉的形狀和表情。
      • 圖像變換與融合:通過計算源人臉和目標人臉關鍵點之間的變換關系,如仿射變換、Delaunay 三角剖分等,將源人臉的形狀和姿態調整到與目標人臉匹配。然后,采用圖像融合技術,將調整后的源人臉與目標圖像進行融合,使換臉效果更加自然。
    • 實現步驟
      • 安裝相關庫:主要安裝 dlib 庫,還可能需要 opencv、numpy 等庫配合。在 Python 中可以使用pip install dlib等命令安裝。
      • 人臉檢測與關鍵點提取:使用 dlib 的人臉檢測器和形狀預測器,加載圖像或視頻幀,檢測其中的人臉并提取關鍵點。
      • 計算變換關系:根據源人臉和目標人臉的關鍵點,計算出兩者之間的變換矩陣,確定如何將源人臉變換到目標人臉的位置和姿態。
      • 人臉替換:將源人臉按照計算出的變換關系進行變形和調整,然后將其融合到目標圖像的對應位置上。
      • 后處理:對換臉后的圖像進行一些后處理操作,如調整顏色、亮度、對比度等,使換臉效果更加自然逼真。
    • 優缺點
      • 優點:具有較高的人臉檢測和關鍵點定位精度,能夠處理不同姿態、表情和光照條件下的人臉;提供了豐富的函數和工具,方便開發者進行二次開發和集成;在處理速度上相對較快,能夠滿足一些實時性要求不高的應用場景。
      • 缺點:對圖像和視頻的質量要求較高,如果輸入的圖像分辨率低、模糊或存在遮擋,可能會影響換臉效果;對于復雜的場景和特殊的光照條件,換臉效果可能不夠自然;在實時性要求較高的場景中,如實時視頻通話換臉,可能需要進一步優化才能滿足性能要求。

仿射變換

仿射變換(Affine Transformation)是一種在二維或三維空間中廣泛應用的線性變換,它能夠保持圖像的 “平直性” 和 “平行性”,在計算機視覺、圖形學等領域有諸多應用,比如在 dlib 換臉中就用于調整源人臉的形狀和姿態以匹配目標人臉。
在這里插入圖片描述

在這里插入圖片描述

在 dlib 換臉中的應用

在這里插入圖片描述

圖片:在這里插入圖片描述

仿射變換代碼:

import cv2
import numpy as np# 讀取圖像,這里讀取的圖像文件名為 'c_luo.png'
# cv2.imread 函數用于從指定路徑讀取圖像,返回一個表示圖像的 NumPy 數組
img = cv2.imread('c_luo.png')# 獲取圖像的高度和寬度
# img.shape 返回一個包含圖像維度信息的元組,元組的前兩個元素分別是圖像的高度和寬度
height, width = img.shape[:2]# 定義源圖像的三個關鍵點
# 這里使用 np.float32 創建一個 3x2 的浮點型 NumPy 數組
# 三個點分別是圖像的左上角 (0, 0)、左下角 (0, height - 1) 和右上角 (width - 1, 0)
mat_src = np.float32([[0, 0], [0, height - 1], [width - 1, 0]])# 定義目標圖像對應的三個關鍵點
# 同樣是一個 3x2 的浮點型 NumPy 數組
# 這里的三個點是經過變換后源圖像三個關鍵點對應的目標位置
mat_dst = np.float32([[0, 0], [100, height - 100], [width - 100, 100]])# 計算仿射變換矩陣
# cv2.getAffineTransform 函數根據源圖像和目標圖像的三個對應關鍵點,計算仿射變換矩陣
# 該矩陣用于描述從源圖像到目標圖像的仿射變換關系
M = cv2.getAffineTransform(mat_src, mat_dst)# 應用仿射變換
# cv2.warpAffine 函數將仿射變換應用到輸入圖像 img 上
# M 是前面計算得到的仿射變換矩陣
# (width, height) 是輸出圖像的大小
dst = cv2.warpAffine(img, M, (width, height))# 將原始圖像和經過仿射變換后的圖像水平拼接在一起
# np.hstack 函數用于將多個數組水平堆疊,方便同時顯示原始圖像和變換后的圖像
imgs = np.hstack([img, dst])# 創建一個可調整大小的窗口
# cv2.namedWindow 函數用于創建一個指定名稱的窗口,cv2.WINDOW_NORMAL 表示窗口可以調整大小
cv2.namedWindow('imgs', cv2.WINDOW_NORMAL)# 在創建的窗口中顯示拼接后的圖像
cv2.imshow('imgs', imgs)# 等待用戶按下任意按鍵
# cv2.waitKey(0) 表示無限期等待用戶按鍵,按鍵后程序繼續執行
cv2.waitKey(0)

這段代碼的主要功能是對一張圖像進行仿射變換,并將原始圖像和變換后的圖像拼接在一起顯示。通過指定源圖像和目標圖像的三個對應關鍵點,計算出仿射變換矩陣,然后將該變換應用到圖像上。

結果:
在這里插入圖片描述

換臉操作

對下方圖片進行換臉操作:
在這里插入圖片描述
在這里插入圖片描述
實現代碼:

import cv2
import dlib
import numpy as np# 定義人臉關鍵點的索引范圍
# 下巴關鍵點索引
JAW_POINTS = list(range(0, 17))
# 右眉毛關鍵點索引
RIGHT_BROW_POINTS = list(range(17, 22))
# 左眉毛關鍵點索引
LEFT_BROW_POINTS = list(range(22, 27))
# 鼻子關鍵點索引
NOSE_POINTS = list(range(27, 35))
# 右眼關鍵點索引
RIGHT_EYE_POINTS = list(range(36, 42))
# 左眼關鍵點索引
LEFT_EYE_POINTS = list(range(42, 48))
# 嘴巴關鍵點索引
MOUTH_POINTS = list(range(48, 61))
# 臉部關鍵點索引(不包括下巴)
FACE_POINTS = list(range(17, 68))# 選取用于變換的關鍵點集合
POINTS = [LEFT_BROW_POINTS + RIGHT_EYE_POINTS + LEFT_EYE_POINTS + RIGHT_BROW_POINTS + NOSE_POINTS + MOUTH_POINTS]
# 將關鍵點集合轉換為元組
POINTStuple = tuple(POINTS)def getFaceMask(im, keyPoints):"""生成人臉掩碼:param im: 輸入圖像:param keyPoints: 人臉關鍵點:return: 人臉掩碼圖像"""# 創建一個與輸入圖像高度和寬度相同的零矩陣im = np.zeros(im.shape[:2], dtype=np.float64)for p in POINTS:# 計算關鍵點的凸包points = cv2.convexHull(keyPoints[p])# 填充凸包區域為 1cv2.fillConvexPoly(im, points, color=1)# 將單通道掩碼擴展為三通道im = np.array([im, im, im]).transpose((1, 2, 0))# 對掩碼進行高斯模糊處理im = cv2.GaussianBlur(im, (25, 25), 0)return imdef getM(points1, points2):"""計算仿射變換矩陣:param points1: 源圖像的關鍵點:param points2: 目標圖像的關鍵點:return: 仿射變換矩陣"""points1 = points1.astype(np.float64)points2 = points2.astype(np.float64)# 計算關鍵點的均值c1 = np.mean(points1, axis=0)c2 = np.mean(points2, axis=0)# 減去均值進行中心化points1 -= c1points2 -= c2# 計算關鍵點的標準差s1 = np.std(points1)s2 = np.std(points2)# 歸一化關鍵點points1 /= s1points2 /= s2# 進行奇異值分解U, S, Vt = np.linalg.svd(points1.T * points2)# 計算旋轉矩陣R = (U * Vt).Treturn np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T))def getKeyPoints(im):"""檢測圖像中的人臉關鍵點:param im: 輸入圖像:return: 人臉關鍵點矩陣"""# 使用 dlib 的人臉檢測器檢測人臉rects = detector(im, 1)# 使用 dlib 的形狀預測器預測關鍵點shape = predictor(im, rects[0])# 將關鍵點轉換為矩陣形式s = np.matrix([[p.x, p.y] for p in shape.parts()])return sdef normalColor(a, b):"""顏色校正:param a: 源圖像:param b: 目標圖像:return: 顏色校正后的目標圖像"""# 定義高斯核大小ksize = (71, 71)# 對源圖像和目標圖像進行高斯模糊aGauss = cv2.GaussianBlur(a, ksize, 0)bGauss = cv2.GaussianBlur(b, ksize, 0)# 避免除以零bGauss = np.where(bGauss == 0, 1e-8, bGauss)# 計算權重weight = aGauss / bGaussreturn b * weight# 讀取源圖像和目標圖像
a = cv2.imread('c_luo.png')
b = cv2.imread('mu_ba_pei.png')# 初始化 dlib 的人臉檢測器
detector = dlib.get_frontal_face_detector()
# 初始化 dlib 的形狀預測器,需要提前下載 shape_predictor_68_face_landmarks.dat 文件
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')# 檢測源圖像和目標圖像的人臉關鍵點
aKeyPoints = getKeyPoints(a)
bKeyPoints = getKeyPoints(b)# 保存目標圖像的原始副本
bOriginal = b.copy()# 生成源圖像的人臉掩碼
aMask = getFaceMask(a, aKeyPoints)
# 顯示源圖像的人臉掩碼
cv2.imshow('aMask', aMask)
cv2.waitKey()# 生成目標圖像的人臉掩碼(使用源圖像的關鍵點)
bMask = getFaceMask(b, aKeyPoints)
# 顯示目標圖像的人臉掩碼
cv2.imshow('bMask', bMask)
cv2.waitKey()# 計算仿射變換矩陣
M = getM(aKeyPoints[POINTStuple], bKeyPoints[POINTStuple])# 獲取源圖像的尺寸(寬度和高度)
dsize = a.shape[:2][::-1]# 對目標圖像的掩碼進行仿射變換
bMaskWarp = cv2.warpAffine(bMask, M, dsize,borderMode=cv2.BORDER_TRANSPARENT,flags=cv2.WARP_INVERSE_MAP)
# 顯示變換后的目標圖像掩碼
cv2.imshow('bMaskWarp', bMaskWarp)
cv2.waitKey()# 合并源圖像掩碼和變換后的目標圖像掩碼
mask = np.max([aMask, bMaskWarp], axis=0)
# 顯示合并后的掩碼
cv2.imshow('mask', mask)
cv2.waitKey()# 對目標圖像進行仿射變換
bWrap = cv2.warpAffine(b, M, dsize,borderMode=cv2.BORDER_TRANSPARENT,flags=cv2.WARP_INVERSE_MAP)
# 顯示變換后的目標圖像
cv2.imshow('bWrap', bWrap)
cv2.waitKey()# 對變換后的目標圖像進行顏色校正
bcolor = normalColor(a, bWrap)
# 顯示顏色校正后的目標圖像
cv2.imshow('bcolor', bcolor)
cv2.waitKey()# 融合源圖像和顏色校正后的目標圖像
out = a * (1.0 - mask) + bcolor * mask
# 顯示源圖像
cv2.imshow('a', a)
# 顯示目標圖像的原始副本
cv2.imshow('b', bOriginal)
# 顯示換臉后的結果圖像
cv2.imshow('out', out / 255)
cv2.waitKey()
# 關閉所有 OpenCV 窗口
cv2.destroyAllWindows()

結果:

在這里插入圖片描述
可通過結果看出換臉成功。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73067.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73067.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73067.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

機器學習中的梯度下降是什么意思?

梯度下降(Gradient Descent)是機器學習中一種常用的優化算法,用于最小化損失函數(Loss Function)。通過迭代調整模型參數,梯度下降幫助模型逐步逼近最優解,從而提升模型的性能。 1.核心思想 梯…

三、Docker 集群管理與應用

(一)項目案例 1、準備主機 (1)關閉防火墻,或者開放TCP端口2377(用于集群管理通信)、TCP/UPD端口7946(用于節點之間的通信)、UDP端口4789(用于overlay網絡流…

網絡DNS怎么更改?

訪問速度慢或某些網站無法打開?改變網絡DNS設置可能會幫助解決這些問題。本文將詳細介紹如何更改網絡DNS,包括更改的原因、具體步驟。 一、為什么要更改DNS? 更改DNS的原因有很多,以下是一些主要的考慮因素:某些公共DNS服務器的響應速度比…

江科大51單片機筆記【12】DS18B20溫度傳感器(上)

寫在前言 此為博主自學江科大51單片機(B站)的筆記,方便后續重溫知識 在后面的章節中,為了防止篇幅過長和易于查找,我把一個小節分成兩部分來發,上章節主要是關于本節課的硬件介紹、電路圖、原理圖等理論…

基于springboot+vue的佳途旅行分享預約平臺

一、系統架構 前端:vue2 | element-ui | html 后端:springboot | mybatis-plus 環境:jdk1.8 | mysql | maven | node 二、代碼及數據庫 三、功能介紹 01. web端-注冊 02. web端-登錄 03. web端-系統主頁1 04. web端-系統主頁2 05. we…

【數據結構】2算法及分析

0 章節 1.4到1.5小節。 掌握算法概念、特性、描述、算法性能時間復雜度和空間復雜度; 理解遞歸含義? 掌握實現遞歸的條件和時機; 應用簡單遞歸問題的算法設計; 重點 算法…

【一起學Rust | Tauri2.0框架】基于 Rust 與 Tauri 2.0 框架實現軟件開機自啟

文章目錄 前言 一、準備工作1.1 環境搭建1.2 創建 Tauri 項目1.3 添加依賴 二、實現開機自啟的基本原理2.1 開機自啟的基本概念2.2 Tauri 應用的生命周期 三、Windows 平臺實現3.1 Windows 注冊表機制3.2 實現步驟3.3 注意事項 四、Linux 平臺實現4.1 Linux systemd 服務4.2 實…

一周熱點-OpenAI 推出了 GPT-4.5,這可能是其最后一個非推理模型

在人工智能領域,大型語言模型一直是研究的熱點。OpenAI 的 GPT 系列模型在自然語言處理方面取得了顯著成就。GPT-4.5 是 OpenAI 在這一領域的又一力作,它在多個方面進行了升級和優化。 1 新模型的出現 GPT-4.5 目前作為研究預覽版發布。與 OpenAI 最近的 o1 和 o3 模型不同,…

css中的浮動

在 CSS 中,浮動(float)是一種定位元素的方式,它允許元素脫離正常的文檔流,并向左或向右移動,直到其邊緣碰到包含塊或者另一個浮動元素的邊緣。下面從多個方面詳細介紹 CSS 浮動: 一&#xff0c…

element-plus中form表單組件的使用

1.如何讓每個表單項對齊? 問題描述:如下圖,每個表單項的輸入框/下拉框/日期選擇器是沒有對齊的,我們希望它們縱向是對齊的。 解決方案:給el-form標簽,加上label-width"100px"即可。意思就是給每個…

線性搜索算法

何時使用線性搜索算法? 當處理一個小數據集時。當搜索存儲在連續內存中的數據集時。 線性搜索算法在什么情況下優于其他搜索算法? 當列表或數組未排序時,或者當輸入的大小相對較小時,首選線性搜索算法。它易于實現,并…

踩坑記錄:yolov5環境版本要求比較嚴苛?

在安裝yolov5環境時,numpy安裝失敗報錯metadata-generation-failed 報錯如下: Collecting numpy1.18.5 (from -r /*****/yolov5-5.0/requirements.txt (line 5))Using cached https://pypi.tuna.tsinghua.edu.cn/packages/01/1b/d3ddcabd5817be02df0e6…

Java設計模式系列:單例模式的7種實現與適用場景

一、單例模式核心價值與實現原則 1. 使用場景 全局配置類(如數據庫連接池)日志記錄器Spring默認Bean作用域硬件設備訪問(如打印機)2. 設計三原則 私有構造器:禁止外部實例化靜態實例持有:全局唯一訪問點延遲加載(可選):避免資源浪費二、七種單例實現方式深度解析 1.…

OpenManus-通過源碼方式本地運行OpenManus,含踩坑及處理方案,chrome.exe位置修改

前言:最近 Manus 火得一塌糊涂啊,OpenManus 也一夜之間爆火,那么作為程序員應該來嘗嘗鮮 1、前期準備 FastGithub:如果有科學上網且能正常訪問 github 則不需要下載此軟件,此軟件是提供國內直接訪問 githubGit&#…

【最新】DeepSeek 實用集成工具有那些?

deepseek 系列github倉庫地址 【主頁】deepseek-aiDeepSeek-R1DeepSeek-V3DeepSeek-VL2【本文重點介紹】awesome-deepseek-integration 注意:以下內容來自awesome-deepseek-integration DeepSeek 實用集成(awesome-deepseek-integration) 將…

開源!速度100Kb/s的有線和無線雙模ESP32S3芯片的DAP-Link調試器

開源!速度100Kb/s的有線和無線雙模ESP32S3芯片的DAP-Link調試器 目錄 開源!速度100Kb/s的有線和無線雙模ESP32S3芯片的DAP-Link調試器本項目未經授權,禁止商用!本項目未經授權,禁止商用!本項目未經授權&…

Flink測試環境Standalone模式部署實踐

1.JDK環境 參考官方文檔: https://nightlies.apache.org/flink/flink-docs-release-1.20/release-notes/flink-1.18/ 2.下載Flink:https://flink.apache.org/downloads/ 本次驗證用的是:https://www.apache.org/dyn/closer.lua/flink/flink…

在16卡服務器上使用最新版的CUDA和驅動訓練`llama - 2 - 7b`和`llama - 2 - 70b`模型,并生成訓練指標數據

要在16卡服務器上使用最新版的CUDA和驅動訓練llama - 2 - 7b和llama - 2 - 70b模型,并生成訓練指標數據,你可以按照以下步驟進行: 1. 環境準備 確保你的服務器已經安裝了最新版的CUDA和驅動,并且安裝了必要的Python庫&#xff0…

macOS 終端優化

macOS 安裝、優化、還原、升級 Oh My Zsh 完全指南 🚀 Oh My Zsh 是 macOS 終端增強的利器,它能提供強大的自動補全、主題定制和插件支持,讓你的終端更高效、更炫酷。本文將全面介紹 如何安裝、優化、還原、重新安裝和升級 Oh My Zsh&#x…

計算機網絡--訪問一個網頁的全過程

文章目錄 訪問一個網頁的全過程應用層在瀏覽器輸入URL網址http://www.aspxfans.com:8080/news/index.aspboardID5&ID24618&page1#r_70732423通過DNS獲取IP地址生成HTTP請求報文應用層最后 傳輸層傳輸層處理應用層報文建立TCP連接傳輸層最后 網絡層網絡層對TCP報文進行處…