深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

AIBigbull2050發表於2019-11-11

作者 | Trent 1985

來源 | CSDN部落格

人像靜態/動態貼紙特效幾乎已經是所有影像影片處理類/直播類app的必需品了,這個功能看起來複雜,實際上很簡單,本文將給大家做個詳細的講解。

我們先來看一下FaceU的兩張效果圖:

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

這兩張效果圖中, 我們可以看到一些可愛的聖誕帽貼紙和小鹿形象貼紙,在人臉區域,自動貼上不同的貼紙,便會生成很多有趣的特效,這也是大家愛不釋手的原因。

我們從靜態貼紙講起,動態貼紙實際上是靜態貼紙的迴圈播放而已。人像靜態貼紙的鼻祖是in app,而後FaceU的動態貼紙風靡一時,現在靜態/動態貼紙已經隨處可見了。它的演算法分為兩個部分:

1. 人臉檢測與關鍵點識別

所謂人像貼紙,第一步必然是人臉檢測與關鍵點識別。在有人臉的情況下獲取到必須的關鍵點,這樣我們才能準確的打上貼紙。現有的app中,比如FaceU和輕顏相機,當然他們是一家的,他們的貼紙基本上都是數十個人臉特徵點的模板配置,也就是說,完成一個貼紙效果,需要數十個點位資訊的支援。不過,個人認為,最簡單的貼紙,可以從三個點開始。

關於人臉特徵點識別演算法,相關的論文或者開源的程式碼工程,已經多如牛毛,這裡我不 一一例舉,本人這裡以mtcnn為例,因為本文演算法只需要三個點即可。mtcnn在檢測到人臉的情況下,會給我們提供5個特徵點,如下圖所示:

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

mtcnn的演算法詳解大家也可以在網路資源中自行學習,這裡我們僅僅給出網路結構示意圖,如圖所示。

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

對於上述三個網路,分別為三個階段:

Stage 1:使用P-Net是一個全卷積網路,用來生成候選窗和邊框迴歸向量(bounding box regression vectors)。使用Bounding box regression的方法來校正這些候選窗,使用非極大值抑制(NMS)合併重疊的候選框;

Stage 2:使用N-Net改善候選窗,將透過P-Net的候選窗輸入R-Net中,拒絕掉大部分false的視窗,繼續使用Bounding box regression和NMS合併;

Stage 3:使用O-Net輸出最終的人臉框和特徵點位置。和第二步類似,但是不同的是生成5個特徵點位置;

本文使用NCNN呼叫MTCNN的模型,上層採用C#呼叫,程式碼如下:

/*************************************************Copyright: Copyright Trent.Author: TrentDate: 2015-03-09Description:MTCNN.**************************************************/#include"Trent.h"#include "mtcnn.h"#include <stdint.h>static char* model_path = "C:/Users/Administrator/Desktop/mtcnn/001_TestDemo/TestDemo/TestDemo_C/models";MTCNN* mtcnn;int FD_Initialize{mtcnn = new MTCNN(model_path);return 0;};int FD_Process(unsigned char* srcData, int width, int height, int stride, int faceInfos[15]){unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * height * width * 3);unsigned char* pSrc = srcData;unsigned char* pData = data;for (int j = 0; j < height; j++){for (int i = 0; i < width; i++){pData[0] = pSrc[0];pData[1] = pSrc[1];pData[2] = pSrc[2];pData += 3;pSrc += 4;}}ncnn::Mat ncnn_img = ncnn::Mat::from_pixels(data, ncnn::Mat::PIXEL_RGB, width, height);std::vector<Bbox> finalBbox;mtcnn->detect(ncnn_img, finalBbox);if(finalBbox.size > 0){faceInfos[0] = 1;faceInfos[1] = finalBbox[0].x1;faceInfos[2] = finalBbox[0].y1;faceInfos[3] = finalBbox[0].x2 - finalBbox[0].x1;faceInfos[4] = finalBbox[0].y2 - finalBbox[0].y1;faceInfos[5] = finalBbox[0].ppoint[0];faceInfos[6] = finalBbox[0].ppoint[5];faceInfos[7] = finalBbox[0].ppoint[1];faceInfos[8] = finalBbox[0].ppoint[6];faceInfos[9] = finalBbox[0].ppoint[2];faceInfos[10] = finalBbox[0].ppoint[7];faceInfos[11] = finalBbox[0].ppoint[3];faceInfos[12] = finalBbox[0].ppoint[8];faceInfos[13] = finalBbox[0].ppoint[4];faceInfos[14] = finalBbox[0].ppoint[9];}free(data);return 0;};void FD_Unitialize{if(model_path != )free(model_path);delete(mtcnn);}

拿到五個人臉特徵點,這一步我們就完成了。

2. 貼紙融合

有了特徵點,我們如何將貼紙融合到恰當的位置?

①計算基準點

我們從5個特徵點中,計算得到三個關鍵點A,B,C;

  • A為左眼中心點

  • B為右眼中心點

  • C為嘴巴水平中心點

對於一張人臉,它的這三個點變化比較小,同時又可以覆蓋整個臉部區域,因此,具有整張臉的代表性。

②構建模特基準點

選取一張模特圖,要求五官端正,比例協調,如下圖所示:

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

在圖中標定出三個人臉關鍵點位置A,B,C,如藍色點所示,並記錄位置資訊:

③構建貼紙模板

我們使用如下兩個貼紙,在PS中將貼紙放置到模特臉上合適的位置,然後儲存兩個貼紙模板為mask_a,mask_b,這樣兩個貼紙模板就製作完成了,模板如下圖所示:

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

③貼圖

對於任意一張使用者照片,先使用MTCNN得到人臉5個關鍵點,計算出人臉關鍵點A,B,C,我們記做A0,B0,C0;

然後,使用仿射變換,公式如下圖所示所示,將A0,B0,C0對映到模特圖A,B,C三點,得到仿射變換矩陣H;

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

仿射變換H矩陣求解程式碼如下:

void GetTexTransMatrix(float x1, float y1, float x2, float y2, float x3, float y3,float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float*texMatrix){float detA;detA = tx1*ty2 + tx2*ty3 + tx3*ty1 - tx3*ty2 - tx1*ty3 - tx2*ty1;float A11, A12, A13, A21, A22, A23, A31, A32, A33;A11 = ty2 - ty3;A21 = -(ty1 - ty3);A31 = ty1 - ty2;A12 = -(tx2 - tx3);A22 = tx1 - tx3;A32 = -(tx1 - tx2);A13 = tx2*ty3 - tx3*ty2;A23 = -(tx1*ty3 - tx3*ty1);A33 = tx1*ty2 - tx2*ty1;texMatrix[0] = (x1*A11 + x2*A21 + x3*A31) / detA;texMatrix[1] = (x1*A12 + x2*A22 + x3*A32) / detA;texMatrix[2] = (x1*A13 + x2*A23 + x3*A33) / detA;texMatrix[3] = (y1*A11 + y2*A21 + y3*A31) / detA;texMatrix[4] = (y1*A12 + y2*A22 + y3*A32) / detA;texMatrix[5] = (y1*A13 + y2*A23 + y3*A33) / detA;

最後,根據H遍歷使用者照片,將使用者照片畫素對映到貼紙模板mask_a或者mask_b中,根據貼紙模板畫素的透明度進行alpha混合,即可得到最終效果,如下圖所示:

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選

最後給出完整的自動人像貼紙程式碼,僅僅50行左右,即可實現靜態圖貼紙效果,如果大家需要動態貼紙,可以迴圈播放不同貼紙即可,程式碼如下:

#include"Trent_Sticker.h"#include"Trent.h"void GetTexTransMatrix(float x1, float y1, float x2, float y2, float x3, float y3,float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float*texMatrix){float detA;detA = tx1*ty2 + tx2*ty3 + tx3*ty1 - tx3*ty2 - tx1*ty3 - tx2*ty1;float A11, A12, A13, A21, A22, A23, A31, A32, A33;A11 = ty2 - ty3;A21 = -(ty1 - ty3);A31 = ty1 - ty2;A12 = -(tx2 - tx3);A22 = tx1 - tx3;A32 = -(tx1 - tx2);A13 = tx2*ty3 - tx3*ty2;A23 = -(tx1*ty3 - tx3*ty1);A33 = tx1*ty2 - tx2*ty1;texMatrix[0] = (x1*A11 + x2*A21 + x3*A31) / detA;texMatrix[1] = (x1*A12 + x2*A22 + x3*A32) / detA;texMatrix[2] = (x1*A13 + x2*A23 + x3*A33) / detA;texMatrix[3] = (y1*A11 + y2*A21 + y3*A31) / detA;texMatrix[4] = (y1*A12 + y2*A22 + y3*A32) / detA;texMatrix[5] = (y1*A13 + y2*A23 + y3*A33) / detA;}int Trent_Sticker(unsigned char* srcData, int width, int height, int stride, unsigned char* mask, int maskWidth, int maskHeight, int maskStride, int srcFacePoints[6], int maskFacePoints[6], int ratio){int ret = 0;float H[6];GetTexTransMatrix(maskFacePoints[0], maskFacePoints[1], maskFacePoints[2], maskFacePoints[3], maskFacePoints[4], maskFacePoints[5], srcFacePoints[0], srcFacePoints[1], srcFacePoints[2], srcFacePoints[3], srcFacePoints[4], srcFacePoints[5], H);for (int j = 0; j < height; j++){for (int i = 0; i < width; i++){float x = (float)i;float y = (float)j;float tx = 0;float ty = 0;tx = (int)((H[0] * (x)+H[1] * (y)+H[2]) + 0.5);ty = (int)((H[3] * (x)+H[4] * (y)+H[5]) + 0.5);tx = CLIP3(tx, 0, maskWidth - 1);ty = CLIP3(ty, 0, maskHeight - 1);int mb = mask[(int)tx * 4 + (int)ty * maskStride];int mg = mask[(int)tx * 4 + (int)ty * maskStride + 1];int mr = mask[(int)tx * 4 + (int)ty * maskStride + 2];int alpha = mask[(int)tx * 4 + (int)ty * maskStride + 3];int b = srcData[i * 4 + j * stride];int g = srcData[i * 4 + j * stride + 1];int r = srcData[i * 4 + j * stride + 2];srcData[(int)i * 4 + (int)j * stride] = CLIP3((b * (255 - alpha) + mb * alpha) / 255, 0, 255);srcData[(int)i * 4 + (int)j * stride + 1] = CLIP3((g * (255 - alpha) + mg * alpha) / 255, 0, 255);srcData[(int)i * 4 + (int)j * stride + 2] = CLIP3((r * (255 - alpha) + mr * alpha) / 255, 0, 255);}}return ret;};

最後,給出完整工程的原始碼,包含MTCNN呼叫程式碼和靜態貼紙程式碼: 1985/10891121

注意,程式碼執行環境為VS2015,執行時需要把model_path修改為自己的本地路徑即可。

DEMO原始碼介面如下:

深度學習AI美顏系列——人像靜態/動態貼紙特效演算法實現 | CSDN博文精選






來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946223/viewspace-2663426/,如需轉載,請註明出處,否則將追究法律責任。

相關文章