3D人脸重构里的渲染质心(barycentric coordinates)坐标计算原理。

一、什么是质心坐标?

在几何结构中,质心坐标是指图形中的点相对各顶点的位置。

以图1的线段 AB 为例,点 P 位于线段 AB 之间,

  图1 线段AB和点P

 

此时计算点 P 的公式为 

 

同理,在三角形 ABC 中,三角形内点 P 的计算公式为:——公式一。

 公式一的最终表示形式为:

 

那么如何计算参数 m 和 n 呢?

下面给出推导过程:

根据公式一可得:

我们将  记作向量  ,将  记作向量  , 将  记作向量 ,则公式为:

然后分别乘以 v0  和 v1 得到如下两个公式:

  

继续化解方程式得:

 令:

继续化简方程式得:

根据莱布尼茨公式可得:

 

其中d = 

注意:到此整个系数的计算已经完成,质心的应用场景为:

  • 判断一个点是否在三角形内。即根据计算处理的系数是否可以到相等的x,y坐标。
  • 根据三角形的三个顶点得到三角形内任何一点P
  • 可以把系数当作权重,即三个点的任何属性,例如颜色、深度等信息,也可以使用这里的m、n、(1-m-n)得出对应的加权后的值。例如3D人脸的渲染跟深度计算就是根据这个原理得出的。

C++实现代码:

//vPos1, vPos2,vPos3 分别代表三角形的三个顶点
//vP代表三角形内的一个点、
//fI代表 vPos1的系数
//fJ代表 vPos2的系数
//fK 代表 vPos3的系数
bool GetBarycentricCoord(vec2 vPos1, vec2 vPos2, vec2 vPos3, vec2 vP, float& fI, float& fJ, float& fK)
{
    // Compute vectors
    vec2 v0 = vPos2 - vPos1;
    vec2 v1 = vPos3 - vPos1;
    vec2 v2 = vP - vPos1;

    // Compute dot products
    float fDot00 = Dot(v0, v0);
    float fDot01 = Dot(v0, v1);
    float fDot02 = Dot(v0, v2);
    float fDot11 = Dot(v1, v1);
    float fDot12 = Dot(v1, v2);

    // Compute barycentric coordinates
    float fInvDenom = 1 / (fDot00 * fDot11 - fDot01 * fDot01);
    float fTempU = (fDot11 * fDot02 - fDot01 * fDot12) * fInvDenom;
    float fTempV = (fDot00 * fDot12 - fDot01 * fDot02) * fInvDenom;

    // Check if point is in triangle or edge
    bool bIsInTri = (fTempU >= 0) && (fTempV >= 0) && (fTempU + fTempV <= 1);
    if (bIsInTri)
    {
        fJ = fTempU;
        fK = fTempV;
        fI = 1 - fJ - fK;
    }
    return bIsInTri;
}

python实现代码:

## 获得重心权重的函数
def get_point_weight(point, tri_points):
    ''' Get the weights of the position
    Args:
        point: (2,). [u, v] or [x, y] 
        tri_points: (3 vertices, 2 coords). three vertices(2d points) of a triangle. 
    Returns:
        w0: weight of v0
        w1: weight of v1
        w2: weight of v3
     '''
    tp = np.array(tri_points)
    # vectors
    v0 = tp[2,:] - tp[0,:]
    v1 = tp[1,:] - tp[0,:]
    v2 = np.array(point) - tp[0,:]

    # dot products
    dot00 = np.dot(v0.T, v0) # distance of p2 and p0
    dot01 = np.dot(v0.T, v1) # 
    dot02 = np.dot(v0.T, v2)
    dot11 = np.dot(v1.T, v1)
    dot12 = np.dot(v1.T, v2)

    # barycentric coordinates
    if dot00*dot11 - dot01*dot01 == 0:
        inverDeno = 0
    else:
        inverDeno = 1/(dot00*dot11 - dot01*dot01)

    u = (dot11*dot02 - dot01*dot12)*inverDeno
    v = (dot00*dot12 - dot01*dot02)*inverDeno

    w0 = 1 - u - v
    w1 = v
    w2 = u

    return w0, w1, w2

 

使用到的人脸3d重构参考工程:

https://github.com/cleardusk/3DDFA

渲染工程:

https://github.com/cleardusk/SimRender/blob/master/lib/CMakeLists.txt

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值