开发一个App来为你的女神“化妆”!
/? ?今日科技快訊? ?/
8月19日,三星電子公司發布財報顯示,今年上半年,該公司銷售額達到75.2萬億韓元(約合620億美元),其中86%來自海外。韓國是亞洲第四大經濟體(前三名是中國、日本、印度),同期出口總額為313.4萬億韓元(約合2596億美元),其中海外收入占20.6%。
/? ?作者簡介? ?/
本篇文章來自北斗星_And的投稿,分享了如何利用Android來給圖片美顏,相信會對大家有所幫助!同時也感謝作者貢獻的精彩文章。
北斗星_And的博客地址:
https://juejin.im/user/5d2ef4f7f265da1bb47d9a07
/? ?背景? ?/
最近刷抖音,看到一些大漢變“女神”,這化妝可以稱之為逆襲啊,大漢變蘿莉。作為技術,大部分是男生,并且經常有男生被女票懟我的口紅有多少色號,那是一樣的紅色嗎?為了廣大男同胞能好好的“活在”女票跟前,今天來講述一下化妝,用代碼擼一個好看的女票。
/? ?開始? ?/
先上效果在說吧,學習抖音的化妝教程方式,就畫一半,方便形成對比,效果如下:
如果正在看篇文章的人是個妹子,你應該很清楚畫了些什么吧?為了照顧廣大爺們,先講一下畫了些什么吧。直接看代碼吧:
public?enum?Region?{
????FOUNDATION("粉底"),
????BLUSH("腮紅"),
????LIP("唇彩"),
????BROW("眉毛"),
????EYE_LASH("睫毛"),
????EYE_CONTACT("美瞳"),
????EYE_DOUBLE("雙眼皮"),
????EYE_LINE("眼線"),
????EYE_SHADOW("眼影");
????private?String?name;
????Region(String?name)?{
????????this.name?=?name;
????}
}
女程序員們,你們看出這么多來了嗎?其實我也是挺佩服我自己的,一個男生知道那么多,嚇壞了我很多小伙伴,宅男的世界你們不懂。代碼已經托管到github,如果你喜歡,請給一個star,謝謝!
https://github.com/DingProg/Makeup
/? ?磨皮? ?/
磨刀不誤砍柴工,我們知道,一般的痘痘用粉底是蓋不住的,那么先來一次磨皮吧,把"底板"搞干凈了,我們使用一個高通濾波器(去掉低頻信號,來達到保留細節的效果)+Curve Adjustment某些頻率應用調整,然后在融合來達到磨皮的目的。流程大概是這樣的。
效果如下:
本文就沒有在擼一個這樣的庫,直接使用了github開源的磨皮庫。使用HighPassSkinSmoothing,地址如下:
https://github.com/msoftware/HighPassSkinSmoothing-Android
但是我這里為了形成對比,所以只取了左邊的臉。
?Bitmap?leftAndRightBitmap?=?Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),?Bitmap.Config.ARGB_8888);
?Canvas?canvas?=?new?Canvas(leftAndRightBitmap);
?//+3,為了彌補?int值相除精讀損失,讓左邊多一些
Rect?left?=?new?Rect(0,0,bitmap.getWidth()/2?+?3,bitmap.getHeight());
Rect?right?=?new?Rect(bitmap.getWidth()?-?bitmap.getWidth()/2?,0,bitmap.getWidth(),bitmap.getHeight());
??canvas.drawBitmap(result,left,left,null);
canvas.drawBitmap(bitmap,right,right,null);
/? ?人臉關鍵點檢測? ?/
往人臉上化妝,拿整張照片的磨皮肯定不行啊,我們需要精準的人臉,那就需要人臉識別技術,開源的庫也有一些,但是精度有待加強,所以本文選用了商用的人臉關鍵點檢測技術,大概看了一下,有這么幾家人臉識別技術做的還可以。
商湯
Face++
百度
虹軟
他們的技術,人臉精度,使用價格,在此不做評論。本文選用了Face++的稠密關鍵點檢測。為了方便去見,沒有下載其SDK,使用了網頁版本的關鍵點檢測,可以上傳本地照片,然后把數據拿下來。
右側有關鍵點的json,可以直接復制下來,供后續使用。
{
??"time_used":?140,
??"request_id":?"1565152700,b5efc234-055c-4109-8899-e7bd0b9d1d63",
??"face":?{
????"landmark":?{
??????"left_eye":?{
????????"left_eye_43":?{
??????????"y":?170,
??????????"x":?140
????????},
????????"left_eye_42":?{
??????????"y":?170,
??????????"x":?141
????????},
????????"left_eye_41":?{
??????????"y":?170,
??????????"x":?142
????????},
????????"left_eye_40":?{
??????????"y":?170,
??????????"x":?143
????????},
????????"left_eye_47":?{
??????????"y":?170,
??????????"x":?136
????????},
????????"left_eye_46":?{
??????????"y":?170,
??????????"x":?137
????????}
???????}
?????}
???}
}
如果商用建議購買其SDK。有了這些點,我們就可以接下來“畫”妝了。
/? ?粉底? ?/
有了磨皮,但是不夠白啊,上述的庫里其實包含了美白,它是對整個圖片進行處理,疊加白色濾波,但效果很差,肯定不是我們想要的。但是有了人臉檢測的點,那我們就好辦了,涂一層粉底吧。(女生還要先涂水啊,乳啊什么,照片上不了水了....)
看Face++的文檔我們可以知道json里面的關鍵點為face_contour_left_和face_hairline_為臉的區域。直接拿出左邊臉的區域。
?public?static?Path?landmark(String?faceJson){
????????JSONObject?jsonObject?=?null;
????????try?{
????????????jsonObject?=?new?JSONObject(faceJson);
????????????JSONObject?eye?=?jsonObject.getJSONObject("face").getJSONObject("landmark").getJSONObject("face");
????????????Path?path?=?new?Path();
????????????Point?start?=?getPointByJson(eye.getJSONObject("face_contour_left_0"));
????????????path.moveTo(start.x,start.y);
????????????for(int?i=?1;i<?64;i++){
????????????????Point?point?=?getPointByJson(eye.getJSONObject("face_contour_left_"+i));
????????????????path.lineTo(point.x,point.y);
????????????}
????????????for(int?i=?144;i>=?72;i--){
????????????????Point?point?=?getPointByJson(eye.getJSONObject("face_hairline_"+i));
????????????????path.lineTo(point.x,point.y);
????????????}
????????????path.close();
????????????return??path;
????????}?catch?(JSONException?e)?{
????????????e.printStackTrace();
????????}
????????return?null;
????}
有了左邊區域,只需要一個畫筆就可以畫上去(原圖就可以是畫板 new Canvas(originBitmap)),那我們正常直接涂一層白色,肯定不行,會嚇壞小伙伴的,那白色加透明可以嗎?那我們試試吧!
Canvas?canvas?=?new?Canvas(originBitmap);
?Paint?paint?=?new?Paint();
?paint.setColor(Color.WHITE);
?paint.setAlpha(50);
?paint.setStyle(Paint.Style.FILL);
?canvas.drawPath(facePath,paint);
效果如下所示:
感覺挺假的,我們知道,畫筆是可以設置成高斯模糊的,那就來試試吧。
?private?static?Bitmap?createMask(final?Path?path,?int?color,?@Nullable?PointF?position,?int?alpha,?int?blur_radius)?{
????????if?(path?==?null?||?path.isEmpty())
????????????return?null;
????????RectF?bounds?=?new?RectF();
????????path.computeBounds(bounds,?true);
????????int?width?=?(int)?bounds.width();
????????int?height?=?(int)?bounds.height();
????????Bitmap?bitmap?=?Bitmap.createBitmap(width,?height,?Bitmap.Config.ARGB_8888);??//?mutable
????????Canvas?canvas?=?new?Canvas(bitmap);
????????Paint?paint?=?new?Paint(Paint.ANTI_ALIAS_FLAG);
????????paint.setMaskFilter(new?BlurMaskFilter(blur_radius,?BlurMaskFilter.Blur.NORMAL));
????????paint.setColor(color);
????????paint.setAlpha(alpha);
????????paint.setStyle(Paint.Style.FILL);
????????path.offset(-bounds.left,?-bounds.top);
????????canvas.drawPath(path,?paint);
????????if?(position?!=?null)?{
????????????position.x?=?bounds.left;
????????????position.y?=?bounds.top;
????????}
????????return?bitmap;
????}
事實證明這樣是可以的,但是效果還是不咋行,那我們在用原圖來做一次漸變,剛好可以達到效果。
??private?static?Bitmap?getGradientBitmapByXferomd(Bitmap?originBitmap,?float?radius){
????????if(radius?<?10)?radius?=?10;
????????Bitmap?canvasBitmap?=?Bitmap.createBitmap(originBitmap.getWidth(),originBitmap.getHeight(),?Bitmap.Config.ARGB_8888);
????????Canvas?canvas?=?new?Canvas(canvasBitmap);
????????Paint?paint?=?new?Paint();
????????BitmapShader?bitmapShader?=?new?BitmapShader(originBitmap,?Shader.TileMode.CLAMP,?Shader.TileMode.CLAMP);
????????RadialGradient?radialGradient?=?new?RadialGradient(originBitmap.getWidth()?/?2,?originBitmap.getHeight()?/?2,
????????????????radius,?Color.BLACK,?Color.TRANSPARENT,?Shader.TileMode.CLAMP);
????????paint.setShader(new?ComposeShader(bitmapShader,radialGradient,new?PorterDuffXfermode(PorterDuff.Mode.DST_IN)));
????????canvas.drawRect(new?Rect(0,0,canvasBitmap.getWidth(),canvasBitmap.getHeight()),?paint);
????????return?canvasBitmap;
????}
/? ?口紅? ?/
關于口紅也只是僅僅畫上一層顏色,有了畫筆,就可以和粉底一樣的實現方式。
先看一下怎么連接的區域吧,為了方便,我直接采用了把外面的區域連接起來,然后在去做一次diff就可以了,代碼如下:
public?static?Path?getMouthPath(String?faceJson){
????????try?{
????????????JSONObject?jsonObject?=?new?JSONObject(faceJson);
????????????JSONObject?mouthJson?=?jsonObject.getJSONObject("face").getJSONObject("landmark").getJSONObject("mouth");
?????????????Path?outPath?=?new?Path();
?????????????Path?inPath?=?new?Path();
????????????Point?start?=?getPointByJson(mouthJson.getJSONObject("upper_lip_0"));
????????????outPath.moveTo(start.x,start.y);
?????????????for(int?i?=?1;i?<?18;i++){
?????????????????Point?pointByJson?=?getPointByJson(mouthJson.getJSONObject("upper_lip_"?+?i));
?????????????????outPath.lineTo(pointByJson.x,pointByJson.y);
?????????????}
????????????for(int?i?=?16;i?>?0;i--){
????????????????Point?pointByJson?=?getPointByJson(mouthJson.getJSONObject("lower_lip_"?+?i));
????????????????outPath.lineTo(pointByJson.x,pointByJson.y);
????????????}
????????????outPath.close();
????????????Point?inStart?=?getPointByJson(mouthJson.getJSONObject("upper_lip_32"));
????????????inPath.moveTo(inStart.x,inStart.y);
????????????for(int?i?=?46;i?<?64;i++){
????????????????Point?pointByJson?=?getPointByJson(mouthJson.getJSONObject("upper_lip_"?+?i));
????????????????inPath.lineTo(pointByJson.x,pointByJson.y);
????????????}
????????????for(int?i?=?63;i?>=?46;i--){
????????????????Point?pointByJson?=?getPointByJson(mouthJson.getJSONObject("lower_lip_"?+?i));
????????????????inPath.lineTo(pointByJson.x,pointByJson.y);
????????????}
????????????//取不同的地方
????????????outPath.op(inPath,?Path.Op.DIFFERENCE);
????????????return??outPath;
????????}?catch?(JSONException?e)?{
????????????e.printStackTrace();
????????}
????????return?null;
????}
Path.op()方法需要在API 19及以上才可以使用,如果使用了低版本的api,可以直接使用canvas.clipPath()。
/? ?腮紅? ?/
只有粉底,那看上去,還是有點假,那是不是需要用畫筆畫上一個腮紅呢?但是形狀什么,不好搞定,所以選擇了直接使用腮紅素材,直接貼上去。
實現也相對容易一些。
?public?static?void?drawBlush(Canvas?canvas,?Bitmap?faceBlush,?Path?path,?int?alpha)?{
????????Paint?paint?=?new?Paint();
????????paint.setAlpha(alpha);
????????RectF?rectF?=?new?RectF();
????????path.computeBounds(rectF,true);
????????canvas.drawBitmap(faceBlush,null,rectF,paint);
????}
/? ?眉毛? ?/
眉毛這個其實困擾了我很長時間,因為要把底部的眉毛給扣了,在裝新的眉毛在上面,不然可能完全蓋不住,眉形變化,識別準確率,會導致效果的直接變化。嘗試了很多方法其中OpenCV里有一個著名的inpaint方法的圖片修復方法,看別人寫的去書印demo,也都還行,但是放到這里去眉毛,效果很差,是因為我使用不對,還是什么問題,有大神可以指點,提取周邊的皮膚顏色去掉原來的眉毛。
最終還是放棄了去掉原來的眉毛,直接覆蓋眉毛。
?public?static?Path?getLeftEyeBrow(String?faceJson){
????????try?{
????????????JSONObject?jsonObject?=?new?JSONObject(faceJson);
????????????JSONObject?eye?=?jsonObject.getJSONObject("face").getJSONObject("landmark").getJSONObject("left_eyebrow");
????????????Path?path?=?new?Path();
????????????Point?start?=?getPointByJson(eye.getJSONObject("left_eyebrow_0"));
????????????path.moveTo(start.x,start.y);
????????????for(int?i=?1;i<?64;i++){
????????????????Point?point?=?getPointByJson(eye.getJSONObject("left_eyebrow_"+i));
????????????????path.lineTo(point.x,point.y);
????????????}
????????????path.close();
????????????return??path;
????????}catch?(Exception?e){
????????????e.printStackTrace();
????????}
????????return?null;
????}
?????public?static?void?draw(Canvas?canvas,?Bitmap?eyeBrowRes,?Path?path,?int?alpha){
????????Paint?paint?=?new?Paint();
????????paint.setAlpha(alpha);
????????RectF?rectF?=?new?RectF();
????????path.computeBounds(rectF,true);
????????canvas.drawBitmap(eyeBrowRes,new?Rect(0,0,eyeBrowRes.getWidth(),eyeBrowRes.getHeight()?-?30),rectF,paint);
????}
最終效果如下所示:
但是文中的開始給的效果那張照片,因為識別偏差,導致效果不太好。
/? ?眼睛? ?/
眼睛(睫毛,眼影,雙眼皮,眼線,美瞳),眼睛部分是最復雜的部分了,因為可以畫的實在是太多了。這就將兩個地方的實現,其他具體實現可以參考實際代碼,先看一下這些不是主要的素材吧。
/? ?美瞳? ?/
要向眼睛里畫美瞳,那么我們首先要有這個區域,區域人臉關鍵點已經給了,那么,我們知道,人的眼睛一般是橢圓性的,不可能直接是圓形的,所以畫的時候,需要和眼睛的區域做一個交集來得到結果。
??public?static?void?drawContact(Canvas?canvas,?Bitmap?contactBitmap,?Path?eyePath,?Point?centerPoint,?int?eyeRadius,?int?alpha)?{
????????Path?contactPath?=?new?Path();
????????contactPath.addCircle(centerPoint.x,centerPoint.y,eyeRadius,?Path.Direction.CCW);
????????//重點地方,做交集得到結果
????????contactPath.op(eyePath,?Path.Op.INTERSECT);
????????RectF?bounds?=?new?RectF();
????????contactPath.computeBounds(bounds,true);
????????bounds.offset(1,0);
????????Paint?paint?=?new?Paint();
????????paint.setAlpha(alpha);
????????canvas.drawBitmap(contactBitmap,new?Rect(0,30,contactBitmap.getWidth(),contactBitmap.getHeight()?-?60),bounds,paint);
????}
/? ?睫毛? ?/
我們知道,睫毛有上睫毛和下睫毛,那么怎么把這個眉毛畫上去呢?其實我們知道,一般把圖片繪制到目標區域需要經過,平移,旋轉,縮放來進行。睫毛我們選取了素材上的三個點,和眼睛上的三個點來做上述的三個操作。
有了這三個點,我們就可以計算寬高比,角度,使用三角函數可以很容易計算得到。
/? ?旋轉角度? ?/
使用人眼睛上對應的三個點來計算旋轉角度,(如果人的頭像是正的,可以不用計算,但是人可能偏頭,什么,需要計算旋轉角度,來warp)。
?/**
?????*?@param?p1?三角形頂點
?????*?@param?p2?三角形頂點
?????*?@param?p3?三角形頂點
?????*?@return?三角形頂點p3?到?p1,p3垂直高度
?????*/
????public?double?getTriangleHeight(Point?p1,?Point?p2,?Point?p3)?{
????????int?a?=?p1.x;
????????int?b?=?p1.y;
????????int?c?=?p2.x;
????????int?d?=?p2.y;
????????int?e?=?p3.x;
????????int?f?=?p3.y;
????????//計算三角形面積
????????double?S?=?(a?*?d?+?b?*?e?+?c?*?f?-?a?*?f?-?b?*?c?-?d?*?e)?/?2;
????????int?lengthSquare?=?(p1.x?-?p2.x)?*?(p1.x?-?p2.x)?+?(p1.y?-?p2.y)?*?(p1.y?-?p2.y);
????????return?Math.abs(2?*?S?/?Math.sqrt(lengthSquare));
????}
?????//獲取坐標軸內兩個點間的距離
????public?double?getLength(Point?p1,?Point?p2)?{
????????double?diff_x?=?Math.abs(p1.x?-?p2.x);
????????double?diff_y?=?Math.abs(p1.y?-?p2.y);
????????//兩個點在?橫縱坐標的差值與兩點間的直線?構成直角三角形。length_pow等于該距離的平方
????????double?length_pow?=?Math.pow(diff_x,?2)?+?Math.pow(diff_y,?2);
????????double?sqrt?=?Math.sqrt(length_pow);
????????return?sqrt?==?0?0.001f:(float)?sqrt;
????}
????static?double?pi180?=?180?/?Math.PI;
????public?double?getAngle(Point?p1,?Point?p2,?Point?p3)?{
????????double?_cos1?=?getCos(p1,?p2,?p3);//第一個點為頂點的角的角度的余弦值
????????return?90?-?Math.acos(_cos1)?*?pi180;
????}
/? ?寬高比旋轉角度? ?/
有了角度,那么我們在計算寬高比。
?/**
?????*?@param?targetP1?縮放目標線段點p1
?????*?@param?targetP2?縮放目標線段點p2
?????*?@param?P1???????待縮放線段點p1
?????*?@param?P2???????待縮放線段點p2
?????*?@return?水平高度比值
?????*/
????public?double?computeScaleX(Point?targetP1,?Point?targetP2,?Point?P1,?Point?P2)?{
????????int?targetLengthSquare?=?(targetP1.x?-?targetP2.x)?*?(targetP1.x?-?targetP2.x)?+?(targetP1.y?-?targetP2.y)?*?(targetP1.y?-?targetP2.y);
????????int?sourceLengthSquare?=?(P1.x?-?P2.x)?*?(P1.x?-?P2.x)?+?(P1.y?-?P2.y)?*?(P1.y?-?P2.y);
????????double?scale?=?targetLengthSquare?*?1.0?/?sourceLengthSquare;
????????return?Math.sqrt(scale);
????}
????/**
?????*?@param?targetP1?縮放目標三角形頂點
?????*?@param?targetP2?縮放目標三角形頂點
?????*?@param?targetP3?縮放目標三角形頂點
?????*?@param?P1???????待縮放三角形頂點
?????*?@param?P2???????待縮放三角形頂點
?????*?@param?P3???????待縮放三角形頂點
?????*?@return?垂直高度比值
?????*/
????public?double?computeScaleY(Point?targetP1,?Point?targetP2,?Point?targetP3,?Point?P1,?Point?P2,?Point?P3)?{
????????double?targetHeight?=?getTriangleHeight(targetP1,?targetP2,?targetP3);
????????double?sourceHeight?=?getTriangleHeight(P1,?P2,?P3);
????????return?targetHeight?/?sourceHeight;
????}
/? ?平移? ?/
因為我們的圖形是巨型,不可能從開始位置往上畫,那就需要把畫的位置通過平移,來達到第一個點的位置和對應位置的點,對應上。
?eyeAngleAndScaleCalc.topP1.x?-?(int)?(bean.topP1.x?*?eyeAngleAndScaleCalc.topScaleX),
????????????????eyeAngleAndScaleCalc.topP1.y?-?(int)?(bean.topP1.y?*?eyeAngleAndScaleCalc.topScaleY)
有了這些步驟,那既可以直接合成繪制了,代碼如下:
?public?static?void?drawLash(Context?context,?Canvas?canvas,?EyeAngleAndScaleCalc.Bean?bean,?List<Point>?pointList,?int?alpha,?boolean?needMirror)?{
????????EyeAngleAndScaleCalc?eyeAngleAndScaleCalc?=?new?EyeAngleAndScaleCalc(pointList,bean);
????????Paint?paint?=?new?Paint();
????????paint.setAlpha(alpha);
????????Bitmap?resTopBitmap?=?BitmapUtils.getBitmapByAssetsName(context,bean.resTop);
????????Bitmap?scaledBitmapTop?=?Bitmap.createScaledBitmap(resTopBitmap,?(int)?(resTopBitmap.getWidth()?*?eyeAngleAndScaleCalc.topScaleX?+?0.5),
????????????????(int)?(resTopBitmap.getHeight()?*?eyeAngleAndScaleCalc.topScaleY?+?0.5),?true);
????????resTopBitmap.recycle();
????????Bitmap?resBottomBitmap?=?null;
????????Bitmap?scaledBitmapBottom?=?null;
????????if?(!TextUtils.isEmpty(bean.resBottom))?{
????????????resBottomBitmap?=?BitmapUtils.getBitmapByAssetsName(context,bean.resBottom);
????????????scaledBitmapBottom?=?Bitmap.createScaledBitmap(resBottomBitmap,?(int)?(resBottomBitmap.getWidth()?*?eyeAngleAndScaleCalc.bottomScaleX?+?0.5),
????????????????????(int)?(resBottomBitmap.getHeight()?*?eyeAngleAndScaleCalc.bottomScaleY?+?0.5),?true);
????????????resBottomBitmap.recycle();
????????}
????????if?(needMirror)?{
????????????Matrix?matrix?=?new?Matrix();
????????????matrix.postScale(-1,?1);???//鏡像水平翻轉
????????????scaledBitmapTop?=?Bitmap.createBitmap(scaledBitmapTop,?0,?0,?scaledBitmapTop.getWidth(),?scaledBitmapTop.getHeight(),?matrix,?true);
????????????if?(resBottomBitmap?!=?null)?{
????????????????scaledBitmapBottom?=?Bitmap.createBitmap(scaledBitmapBottom,?0,?0,?scaledBitmapBottom.getWidth(),?scaledBitmapBottom.getHeight(),?matrix,?true);
????????????}
????????}
????????canvas.save();
????????//canvas.rotate(eyeAngleAndScaleCalc.getTopEyeAngle(),?eyeAngleAndScaleCalc.topP1.x,?eyeAngleAndScaleCalc.topP1.y);
????????canvas.drawBitmap(scaledBitmapTop,
????????????????eyeAngleAndScaleCalc.topP1.x?-?(int)?(bean.topP1.x?*?eyeAngleAndScaleCalc.topScaleX),
????????????????eyeAngleAndScaleCalc.topP1.y?-?(int)?(bean.topP1.y?*?eyeAngleAndScaleCalc.topScaleY),?paint);
????????canvas.restore();
????????if?(scaledBitmapBottom?!=?null)?{
????????????canvas.save();
????????????canvas.rotate(eyeAngleAndScaleCalc.getBottomEyeAngle(),?eyeAngleAndScaleCalc.bottomP1.x,?eyeAngleAndScaleCalc.bottomP1.y);
????????????canvas.drawBitmap(scaledBitmapBottom,?eyeAngleAndScaleCalc.bottomP1.x,
????????????????????eyeAngleAndScaleCalc.bottomP1.y?-?(int)?(bean.bottomP1.y?*?eyeAngleAndScaleCalc.bottomScaleY),?paint);
????????????canvas.restore();
????????????scaledBitmapBottom.recycle();
????????}
????????scaledBitmapTop.recycle();
????}
眼睛部分,略微復雜一些,具體代碼可以查看 Github Makeup ,如果你覺得還可以,可以給一個star嗎?謝謝!
/? ?其他? ?/
我們知道,上述內容只是對臉上進行了一些化妝,那要成為真正的“美女”,可能還要打上問號?那什么樣的化妝才是真正的美女呢,一般是底子好的人。在加上化妝就更漂亮了,那一張照片,要變的底子好,一般有那些方式呢?這里提供一些思路(包含美體):
public?enum?BeautyType?{
????INPAINT(1,"祛斑"),
????SMALLFACE(2,"瘦臉"),
????LONGLEG(3,"大長腿增高"),
????EYE(4,"眼睛放大"),
????BREST(5,"豐胸"),
????WHITE(7,"美白"),
????MAKEUP(8,"美妝"),
????SMALLBODY(9,"瘦臉瘦身");
????private?int?type;
????private?String?name;
????BeautyType(int?type,?String?name)?{
????????this.type?=?type;
????????this.name?=?name;
????}
????public?int?getType()?{
????????return?type;
????}
????public?String?getName()?{
????????return?name;
????}
}
如果只針對臉部,那么就只需要,磨皮,美白,祛斑,大眼,瘦臉等功能了。
/? ?文末? ?/
今天的文章分享到這就結束了,這些算法,目前知網論文庫里都有,可以查看后輕松實現。
推薦閱讀:
看一看Facebook工程師是怎么評價《第一行代碼》的
全方位了解8.0系統下的Handler
給你的Android應用穿件花衣服吧!
歡迎關注我的公眾號
學習技術或投稿
長按上圖,識別圖中二維碼即可關注
總結
以上是生活随笔為你收集整理的开发一个App来为你的女神“化妆”!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软媒体服务器,Azure 媒体服务概述
- 下一篇: 渗透测试---被动信息收集详解