今天总结代码, 想推导下透视投影下如何迭代求解3DMM的系数, 不经意间竟然发现如果给定Pose, 3DMM的系数竟然能够线性求解, 我很吃惊(透视投影不应该是非线性的吗?), 于是记录下来,经验证似乎没问题,验证代码如下:
带’的是乘上了R.
import numpy as np
import cv2 as cv
R = cv.Rodrigues(np.array([2, 1, 3.0]))[0].astype(np.float32)
t3d=np.array([3, 5, 100], dtype=np.float32)
nV = 30
dims = 20
E=np.random.rand(nV, 3, dims).astype(np.float32)
V=np.random.rand(nV, 3).astype(np.float32)
def comp_x(x):
S=V + E.dot(x)
TS=S.dot(R.T) + t3d
dst = TS[:, :2] / TS[:, 2:]
return dst
def solve_x(dst):
V_ = V.dot(R.T) + t3d
E_ = (R.dot(E.transpose(1, 0, 2).reshape(3, -1)).reshape(3, nV, dims)).transpose(1, 0, 2).reshape(-1, dims)
A=np.zeros((2*nV, dims), dtype=np.float32)
b=np.zeros(2*nV, dtype=np.float32)
for i in range(nV):
A[i*2:i*2+2] = E_[i*3:i*3+2] - dst[i].reshape(2, 1).dot(E_[i*3+2].reshape(1, -1))
b[i*2:i*2+2] = dst[i].reshape(-1)*V_[i, 2] - V_[i, :2]
AtA=A.T.dot(A)
Atb=A.T.dot(b)
x = np.linalg.inv(AtA).dot(Atb)
return x
def pt_x(x): p(x.astype(np.int32))
x=(np.random.rand(dims)*10).astype(np.int32).astype(np.float32)
dst = comp_x(x)
x_ = solve_x(dst)
dst_ = comp_x(x_)
pt_x(x)
pt_x(x_)
p( np.sum((dst_ - dst)**2))