def factor(W): """ This implements rigid factorization as described in Tomasi, C. & Kanade, T. "Shape and motion from image streams under orthography: a factorization method International Journal of Computer Vision, 1992 """ F = W.shape[0]/2 N = W.shape[1] # Center W T = W.mean(axis=1) W = W - T[:, np.newaxis] # Factor W M_hat, B_hat = factor_matrix(W, J=3) # Where we will build the linear system. A = np.zeros((3*F, 6)) b = np.zeros((3*F,)) for f in range(F): # Extract the two rows. x_f, y_f = M_hat[f*2:f*2+2] # Both rows must have unit length. A[f*3] = util.vc(x_f, x_f) b[f*3] = 1.0 A[f*3+1] = util.vc(y_f,y_f) b[f*3+1] = 1.0 # And be orthogonal. A[f*3+2] = util.vc(x_f - y_f, x_f + y_f) # Recovec vech(Q) and Q vech_Q = np.linalg.lstsq(A, b)[0] Q = util.from_vech(vech_Q, 3, 3, sym=True) # Factor out G recovery matrix G, Gt = factor_matrix(Q) # Upgrade M and B. M = np.dot(M_hat, G) B = np.linalg.solve(G, B_hat) # Find actual rotations matrices. Rs = np.zeros((F, 3, 3)) Rs[:,:2] = M.reshape(F,2,3) Rs[:,2] = util.normed(np.cross(Rs[:,0], Rs[:,1], axis=-1)) # And 3D translations. Ts = np.zeros((F,3)) Ts[:,:2] = T.reshape(F,2) model = BasisShapeModel(Rs, Bs = B[np.newaxis,:,:], Ts = Ts) return model
def find_G_k(M_hat): K = M_hat.shape[1] / 3 F = M_hat.shape[0] / 2 # Get the linear basis that vech(Q_k) should reside in. U = find_linear_basis_for_vech_Q_k(M_hat) # 2D subspace of vech style. B = np.asarray([ from_vech(U[:, i], 3 * K, 3 * K, sym=True).flatten() for i in range(U.shape[1]) ]).T # Coefficients correspond to taking trace. from cvxopt import matrix, solvers # Calculate the cost vector. non_diag = np.where(np.eye(3 * K).flatten() != 1)[0] c = B.copy() c[non_diag, :] = 0 c = c.sum(axis=0) # This matrix should be positive semi-definite. G = [matrix(-B)] h = [matrix(np.zeros((3 * K, 3 * K)))] # We fix the first row of the recovered M_hat to have unit length # which avoids the trivial solution. A = np.dot(vc(M_hat[0], M_hat[0]), U)[np.newaxis, :].copy() A = matrix(A) b = matrix([[1.0]]) # Disable progress reporting in solver. solvers.options['show_progress'] = False # Solve the sdp using cvxopt sol = solvers.sdp(matrix(c), Gs=G, hs=h, A=A, b=b) # Extract the solution. x = np.asarray(sol['x']) # Upgrade to vec(Q_k) y = np.dot(B, x) # And reshape to Q_k Q_k = y.reshape((3 * K, 3 * K)) # Factor into G_k Q_k_U, Q_k_s, Q_k_V = np.linalg.svd(Q_k) G_k = Q_k_U[:, :3] * np.sqrt(Q_k_s)[np.newaxis, :3] # Squared residual objective function as defined in Dai2012. def f(g_k): G_k = g_k.reshape(3 * K, 3) M_k = np.dot(M_hat, G_k) M_kx = M_k[0::2] M_ky = M_k[1::2] term1 = np.square(1 - (M_kx * M_kx).sum(axis=-1) / (M_ky * M_ky).sum(axis=-1)) term2 = np.square(2 * (M_ky * M_kx).sum(axis=-1) / (M_ky * M_ky).sum(axis=-1)) err = np.sum(term1 + term2) return err # Minimize this function with LBFGS from scipy.optimize import fmin_l_bfgs_b rc = fmin_l_bfgs_b(f, G_k.flatten(), approx_grad=True) G_k = rc[0].reshape(3 * K, 3) return G_k
def find_G_k(M_hat): K = M_hat.shape[1]/3 F = M_hat.shape[0]/2 # Get the linear basis that vech(Q_k) should reside in. U = find_linear_basis_for_vech_Q_k(M_hat) # 2D subspace of vech style. B = np.asarray([from_vech(U[:,i], 3*K, 3*K, sym=True).flatten() for i in range(U.shape[1])]).T # Coefficients correspond to taking trace. from cvxopt import matrix, solvers # Calculate the cost vector. non_diag = np.where(np.eye(3*K).flatten()!=1)[0] c = B.copy() c[non_diag,:] = 0 c = c.sum(axis=0) # This matrix should be positive semi-definite. G = [matrix(-B)] h = [matrix(np.zeros((3*K,3*K)))] # We fix the first row of the recovered M_hat to have unit length # which avoids the trivial solution. A = np.dot(vc(M_hat[0], M_hat[0]), U)[np.newaxis,:].copy() A = matrix(A) b = matrix([[1.0]]) # Disable progress reporting in solver. solvers.options['show_progress'] = False # Solve the sdp using cvxopt sol = solvers.sdp(matrix(c), Gs = G, hs = h, A = A, b = b) # Extract the solution. x = np.asarray(sol['x']) # Upgrade to vec(Q_k) y = np.dot(B, x) # And reshape to Q_k Q_k = y.reshape((3*K, 3*K)) # Factor into G_k Q_k_U, Q_k_s, Q_k_V = np.linalg.svd(Q_k) G_k = Q_k_U[:,:3] * np.sqrt(Q_k_s)[np.newaxis,:3] # Squared residual objective function as defined in Dai2012. def f(g_k): G_k = g_k.reshape(3*K, 3) M_k = np.dot(M_hat, G_k) M_kx = M_k[0::2] M_ky = M_k[1::2] term1 = np.square(1 - (M_kx * M_kx).sum(axis=-1)/(M_ky*M_ky).sum(axis=-1 )) term2 = np.square(2*(M_ky*M_kx).sum(axis=-1)/(M_ky*M_ky).sum(axis=-1)) err = np.sum(term1 + term2) return err # Minimize this function with LBFGS from scipy.optimize import fmin_l_bfgs_b rc = fmin_l_bfgs_b(f, G_k.flatten(), approx_grad=True) G_k = rc[0].reshape(3*K,3) return G_k