1. 程式人生 > >【Android】自動瘦臉與眼睛放大美顏演算法

【Android】自動瘦臉與眼睛放大美顏演算法

自動瘦臉與眼睛放大可以算作影象區域性扭曲演算法的一個應用,其參考文獻可以追溯至1993年的一篇博士論文:Interactive Image Warping。這篇論文詳細描述了演算法原理,並提供了偽碼實現,有興趣的同學自行下載研讀。

影象區域性扭曲演算法有三個:區域性縮放(Local Scaling)演算法、區域性平移(Local Transition)演算法和區域性旋轉(Local Rotation)演算法。其中應用區域性縮放演算法可實現眼睛放大,區域性平移演算法則可用於實現瘦臉效果。當然,影象區域性縮放演算法只是眼睛放大演算法流程中的最關鍵的一步,要實現自動眼睛放大演算法還需要額外的步驟。簡單來說,給一張美女頭像,你首先需要應用自動人臉檢測技術定位出影象中的眼睛位置;然後基於此位置座標應用影象區域性縮放演算法。自動瘦臉演算法流程類似,不同之處在於應用人臉檢測技術得到人臉輪廓點,由這些輪廓座標點應用區域性平移演算法得到瘦臉效果。

人臉檢測現在已經是一個很成熟的技術,網上也有很多開放資源,目前我只是演算法驗證,暫時使用的是face++提供的人臉關鍵點檢測SDK。它可以得到很豐富的人臉特徵點,包括眉毛、眼睛、鼻子、嘴巴以及臉部輪廓的各個引數,企業應用可能需要付費授權才能使用,個人驗證只要註冊獲取key就能簡單整合。

影象區域性縮放演算法

待續。。。

至於影象區域性縮放演算法實現,文獻中有偽碼描述,這裡我給出一個簡單的OpenGL Shader可以用於實現眼睛放大(其實也可以縮小),偷懶的同學自取,有問題可以跟我討論,但我不對此程式碼導致的bug負責。

 precision highp float;
 
 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;
 
 uniform highp float scaleRatio;// 縮放係數,0無縮放,大於0則放大
 uniform highp float radius;// 縮放演算法的作用域半徑
 uniform highp vec2 leftEyeCenterPosition; // 左眼控制點,越遠變形越小
 uniform highp vec2 rightEyeCenterPosition; // 右眼控制點
 uniform float aspectRatio; // 所處理影象的寬高比
 
 highp vec2 warpPositionToUse(vec2 centerPostion, vec2 currentPosition, float radius, float scaleRatio, float aspectRatio)
 {
     vec2 positionToUse = currentPosition;
     
     vec2 currentPositionToUse = vec2(currentPosition.x, currentPosition.y * aspectRatio + 0.5 - 0.5 * aspectRatio);
     vec2 centerPostionToUse = vec2(centerPostion.x, centerPostion.y * aspectRatio + 0.5 - 0.5 * aspectRatio);
     
     float r = distance(currentPositionToUse, centerPostionToUse);
     
     if(r < radius)
     {
         float alpha = 1.0 - scaleRatio * pow(r / radius - 1.0, 2.0);
         positionToUse = centerPostion + alpha * (currentPosition - centerPostion);
     }
      
     return positionToUse; 
 }
 
 void main()
 {
     vec2 positionToUse = warpPositionToUse(leftEyeCenterPosition, textureCoordinate, radius, scaleRatio, aspectRatio);
      
     positionToUse = warpPositionToUse(rightEyeCenterPosition, positionToUse, radius, scaleRatio, aspectRatio);
   
     gl_FragColor = texture2D(inputImageTexture, positionToUse);   
 }

給個測試效果圖:

bigeye-src bigeye-dst

影象區域性平移演算法

影象區域性平移演算法還是參見論文,多說無益,在此奉上對應Shader程式碼給需要的同學,可以實現瘦臉和肥臉。這裡需要指定瘦臉的控制點,最多支援MAX_CONTOUR_POINT_COUNT個控制點。

 precision highp float;
 
 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;
 
 uniform highp float radius;
 
 uniform highp float aspectRatio;
 
 uniform float leftContourPoints[MAX_CONTOUR_POINT_COUNT*2];
 uniform float rightContourPoints[MAX_CONTOUR_POINT_COUNT*2];
 uniform float deltaArray[MAX_CONTOUR_POINT_COUNT];
 uniform int arraySize;
 
 highp vec2 warpPositionToUse(vec2 currentPoint, vec2 contourPointA,  vec2 contourPointB, float radius, float delta, float aspectRatio)
 {
     vec2 positionToUse = currentPoint;
     
     vec2 currentPointToUse = vec2(currentPoint.x, currentPoint.y * aspectRatio + 0.5 - 0.5 * aspectRatio);
     vec2 contourPointAToUse = vec2(contourPointA.x, contourPointA.y * aspectRatio + 0.5 - 0.5 * aspectRatio);
     
     float r = distance(currentPointToUse, contourPointAToUse);
     if(r < radius)
     {
         vec2 dir = normalize(contourPointB - contourPointA);
         float dist = radius * radius - r * r;
         float alpha = dist / (dist + (r-delta) * (r-delta));
         alpha = alpha * alpha;
         
         positionToUse = positionToUse - alpha * delta * dir;
         
     }
     
     return positionToUse;
     
 }
 
 
 void main()
 {
     vec2 positionToUse = textureCoordinate;
     
     for(int i = 0; i < arraySize; i++)
     {
      
         positionToUse = warpPositionToUse(positionToUse, vec2(leftContourPoints[i * 2], leftContourPoints[i * 2 + 1]), vec2(rightContourPoints[i * 2], rightContourPoints[i * 2 + 1]), radius, deltaArray[i], aspectRatio);
         positionToUse = warpPositionToUse(positionToUse, vec2(rightContourPoints[i * 2], rightContourPoints[i * 2 + 1]), vec2(leftContourPoints[i * 2], leftContourPoints[i * 2 + 1]), radius, deltaArray[i], aspectRatio);
     }
     
     gl_FragColor = texture2D(inputImageTexture, positionToUse);
     
 }

同樣給個測試效果:

smallface-src smallface-dst

Taily老段的微信公眾號,歡迎交流學習