深度学习AI美颜系列

您所在的位置:网站首页 如何瘦腿瘦身 深度学习AI美颜系列

深度学习AI美颜系列

2024-07-13 04:52:13| 来源: 网络整理| 查看: 265

最近一段时间,抖音、微视、美图纷纷推出了视频实时瘦身的特效,可以说是火了一把!本文将给大家做个技术揭秘!

商汤基于深度学习研发了整套瘦身SDK,包括了瘦腿,瘦腰,瘦胳膊,瘦头型等等功能,并给出了酷炫的实时瘦身视频,惊艳到了众人!本文将以瘦腰和瘦腿为例,给大家详细讲解一下。

瘦身从算法角度来讲,包含两个模块:①人体轮廓特征点检测模块;②人体变形模块

[人体轮廓特征点检测模块]

人体轮廓特征点检测模块好比人脸特征点检测,需要检测到代表人体轮廓的一些点位信息,但是技术上比人脸特征点更加复杂,因为人体是非刚体,比人脸的变化更多,更复杂;

目前人体轮廓特征点检测主要方法就是人体姿态估计;从2015年开始,陆续出现了很多人体姿态估计的论文,这里举例如:

DeeperCut: A Deeper, Stronger, and Faster Multi-Person Pose Estimation Model

这篇论文中所提供的深度学习模型与效果图如下:

这里我们不详细介绍人体姿态估计的算法,主要以讲瘦身的流程为主;

上面的姿态点与我们想要的轮廓点还有差别,在掌握了上面的人体姿态估计算法之后,我们可以使用人体轮廓点的样本进行训练,这样就可以得到如下图所示的人体轮廓特征点:

图片来自网络,为了避免侵权,做了人脸遮挡;

[人体变形模块]

人体变形模块主要是依据人体特征点,将人体变形,也就是瘦身美型;

变形的算法有很多,比如MLS移动最小二乘法变形算法,IWD反距离加权变形算法,MLSR变形算法等等,相关连接如下:

MLSR变形算法实现:点击打开链接

IWD反距离加权变形算法实现:点击打开链接

MLS移动最小二乘变形算法实现:点击打开链接,代码链接点击打开链接

本人MLS代码如下:

static void setSrcPoints(const vector &qsrc, vector &newDotL, int* nPoint) { *nPoint = qsrc.size(); newDotL.clear(); newDotL.reserve(*nPoint); for (size_t i = 0; i < qsrc.size(); i++) newDotL.push_back(qsrc[i]); } static void setDstPoints(const vector &qdst,vector &oldDotL, int* nPoint) { *nPoint = qdst.size(); oldDotL.clear(); oldDotL.reserve(*nPoint); for (size_t i = 0; i < qdst.size(); i++) oldDotL.push_back(qdst[i]); } static double bilinear_interp(double x, double y, double v11, double v12, double v21, double v22) { return (v11 * (1 - y) + v12 * y) * (1 - x) + (v21 * (1 - y) + v22 * y) * x; } static double calcArea(const vector &V) { PointD lt, rb; lt.x = lt.y = 1e10; rb.x = rb.y = -1e10; for (vector::const_iterator i = V.begin(); i != V.end(); i++) { if (i->x < lt.x) lt.x = i->x; if (i->x > rb.x) rb.x = i->x; if (i->y < lt.y) lt.y = i->y; if (i->y > rb.y) rb.y = i->y; } return (rb.x - lt.x) * (rb.y - lt.y); } static void calcDelta_rigid(int srcW, int srcH, int tarW, int tarH, double alpha, int gridSize, int nPoint, int preScale, double *rDx, double *rDy, vector &oldDotL, vector &newDotL) { int i, j, k; PointD swq, qstar, newP, tmpP; double sw; double ratio; if (preScale) { ratio = sqrt(calcArea(newDotL) / calcArea(oldDotL)); for (i = 0; i < nPoint; i++) { newDotL[i].x *= 1 / ratio; newDotL[i].y *= 1 / ratio; } } double *w = new double[nPoint]; if (nPoint < 2) { //rDx.setTo(0); //rDy.setTo(0); return; } PointD swp, pstar, curV, curVJ, Pi, PiJ, Qi; double miu_r; for (i = 0;; i += gridSize) { if (i >= tarW && i < tarW + gridSize - 1) i = tarW - 1; else if (i >= tarW) break; for (j = 0;; j += gridSize) { if (j >= tarH && j < tarH + gridSize - 1) j = tarH - 1; else if (j >= tarH) break; sw = 0; swp.x = swp.y = 0; swq.x = swq.y = 0; newP.x = newP.y = 0; curV.x = i; curV.y = j; for (k = 0; k < nPoint; k++) { if ((i == oldDotL[k].x) && j == oldDotL[k].y) break; if (alpha == 1) w[k] = 1 / ((i - oldDotL[k].x) * (i - oldDotL[k].x) + (j - oldDotL[k].y) * (j - oldDotL[k].y)); else w[k] = pow((i - oldDotL[k].x) * (i - oldDotL[k].x) + (j - oldDotL[k].y) * (j - oldDotL[k].y), -alpha); sw = sw + w[k]; swp.x = swp.x + w[k] * oldDotL[k].x; swp.y = swp.y + w[k] * oldDotL[k].y; swq.x = swq.x + w[k] * newDotL[k].x; swq.y = swq.y + w[k] * newDotL[k].y; } if (k == nPoint) { pstar.x = (1 / sw) * swp.x; pstar.y = (1 / sw) * swp.y; qstar.x = 1 / sw * swq.x; qstar.y = 1 / sw * swq.y; // Calc miu_r double s1 = 0, s2 = 0; for (k = 0; k < nPoint; k++) { if (i == oldDotL[k].x && j == oldDotL[k].y) continue; Pi.x = oldDotL[k].x - pstar.x; Pi.y = oldDotL[k].y - pstar.y; PiJ.x = -Pi.y, PiJ.y = Pi.x; Qi.x = newDotL[k].x - qstar.x; Qi.y = newDotL[k].y - qstar.y; s1 += w[k] * (Qi.x*Pi.x+Qi.y*Pi.y); s2 += w[k] * (Qi.x*PiJ.x+Qi.y*PiJ.y); } miu_r = sqrt(s1 * s1 + s2 * s2); curV.x -= pstar.x; curV.y -= pstar.y; curVJ.x = -curV.y, curVJ.y = curV.x; for (k = 0; k < nPoint; k++) { if (i == oldDotL[k].x && j == oldDotL[k].y) continue; Pi.x = oldDotL[k].x - pstar.x; Pi.y = oldDotL[k].y - pstar.y; PiJ.x = -Pi.y, PiJ.y = Pi.x; tmpP.x = (Pi.x*curV.x+Pi.y*curV.y)* newDotL[k].x - (PiJ.x*curV.x+PiJ.y*curV.y)* newDotL[k].y; tmpP.y = -(Pi.x*curVJ.x+Pi.y*curVJ.y) * newDotL[k].x + (PiJ.x*curVJ.x+PiJ.y*curVJ.y) * newDotL[k].y; tmpP.x *= w[k] / miu_r; tmpP.y *= w[k] / miu_r; newP.x += tmpP.x; newP.y += tmpP.y; } newP.x += qstar.x; newP.y += qstar.y; } else { newP = newDotL[k]; } if (preScale) { rDx[j * tarW + i] = newP.x * ratio - i; rDy[j * tarW + i] = newP.y * ratio - j; } else { rDx[j * tarW + i] = newP.x - i; rDy[j * tarW + i] = newP.y - j; } } } delete[] w; if (preScale!=0) { for (i = 0; i < nPoint; i++){ newDotL[i].x *= ratio; newDotL[i].y *= ratio; } } } static void calcDelta_Similarity(int srcW, int srcH, int tarW, int tarH, double alpha, int gridSize, int nPoint, int preScale, double *rDx, double *rDy, vector &oldDotL, vector &newDotL) { int i, j, k; PointD swq, qstar, newP, tmpP; double sw; double ratio; if (preScale) { ratio = sqrt(calcArea(newDotL) / calcArea(oldDotL)); for (i = 0; i < nPoint; i++) { newDotL[i].x *= 1 / ratio; newDotL[i].y *= 1 / ratio; } } double *w = new double[nPoint]; if (nPoint < 2) { return; } PointD swp, pstar, curV, curVJ, Pi, PiJ; double miu_s; for (i = 0;; i += gridSize) { if (i >= tarW && i < tarW + gridSize - 1) i = tarW - 1; else if (i >= tarW) break; for (j = 0;; j += gridSize) { if (j >= tarH && j < tarH + gridSize - 1) j = tarH - 1; else if (j >= tarH) break; sw = 0; swp.x = swp.y = 0; swq.x = swq.y = 0; newP.x = newP.y = 0; curV.x = i; curV.y = j; for (k = 0; k < nPoint; k++) { if ((i == oldDotL[k].x) && j == oldDotL[k].y) break; w[k] = 1 / ((i - oldDotL[k].x) * (i - oldDotL[k].x) + (j - oldDotL[k].y) * (j - oldDotL[k].y)); sw = sw + w[k]; swp.x = swp.x + w[k] * oldDotL[k].x; swp.y = swp.y + w[k] * oldDotL[k].y; swq.x = swq.x + w[k] * newDotL[k].x; swq.y = swq.y + w[k] * newDotL[k].y; } if (k == nPoint) { pstar.x = (1 / sw) * swp.x; pstar.y = (1 / sw) * swp.y; qstar.x = 1 / sw * swq.x; qstar.y = 1 / sw * swq.y; // Calc miu_s miu_s = 0; for (k = 0; k < nPoint; k++) { if (i == oldDotL[k].x && j == oldDotL[k].y) continue; Pi.x = oldDotL[k].x - pstar.x; Pi.y = oldDotL[k].y - pstar.y; miu_s += w[k] * (Pi.x*Pi.x+Pi.y*Pi.y); } curV.x -= pstar.x; curV.y -= pstar.y; curVJ.x = -curV.y, curVJ.y = curV.x; for (k = 0; k < nPoint; k++) { if (i == oldDotL[k].x && j == oldDotL[k].y) continue; Pi.x = oldDotL[k].x - pstar.x; Pi.y = oldDotL[k].y - pstar.y; PiJ.x = -Pi.y, PiJ.y = Pi.x; tmpP.x = (Pi.x*curV.x+Pi.y*curV.y) * newDotL[k].x - (PiJ.x*curV.x+PiJ.y*curV.y) * newDotL[k].y; tmpP.y = -(Pi.x*curVJ.x+Pi.y*curVJ.y) * newDotL[k].x + (PiJ.x*curVJ.x+PiJ.y*curVJ.y) * newDotL[k].y; tmpP.x *= w[k] / miu_s; tmpP.y *= w[k] / miu_s; newP.x += tmpP.x; newP.y += tmpP.y; } newP.x += qstar.x; newP.y += qstar.y; } else { newP = newDotL[k]; } rDx[j * tarW + i] = newP.x - i; rDy[j * tarW + i] = newP.y - j; } } delete[] w; if (preScale!=0) { for (i = 0; i < nPoint; i++){ newDotL[i].x *= ratio; newDotL[i].y *= ratio; } } } static int GetNewImg(unsigned char* oriImg, int width, int height, int stride, unsigned char* tarImg, int tarW, int tarH, int tarStride, int gridSize, double* rDx, double* rDy, double transRatio) { int i, j; double di, dj; double nx, ny; int nxi, nyi, nxi1, nyi1; double deltaX, deltaY; double w, h; int ni, nj; int pos, posa, posb, posc, posd; for (i = 0; i < tarH; i += gridSize) for (j = 0; j < tarW; j += gridSize) { ni = i + gridSize, nj = j + gridSize; w = h = gridSize; if (ni >= tarH) ni = tarH - 1, h = ni - i + 1; if (nj >= tarW) nj = tarW - 1, w = nj - j + 1; for (di = 0; di < h; di++) for (dj = 0; dj < w; dj++) { deltaX = bilinear_interp(di / h, dj / w, rDx[i * tarW + j], rDx[i * tarW + nj], rDx[ni * tarW + j], rDx[ni * tarW + nj]); deltaY = bilinear_interp(di / h, dj / w, rDy[i * tarW + j], rDy[i * tarW + nj], rDy[ni * tarW + j], rDy[ni * tarW + nj]); nx = j + dj + deltaX * transRatio; ny = i + di + deltaY * transRatio; if (nx > width - 1) nx = width - 1; if (ny > height - 1) ny = height - 1; if (nx < 0) nx = 0; if (ny < 0) ny = 0; nxi = int(nx); nyi = int(ny); nxi1 = ceil(nx); nyi1 = ceil(ny); pos = (int)(i + di) * tarStride + ((int)(j + dj)


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭