2014-05-03 92 views
3

我在Autodesk Maya中使用Python編程函數(使用PyMel for Maya)在Python中仿射3D轉換

我有三個3D點; p0,p1,p2。然後他們做了一個嚴格的轉換,所以在轉換之後(仿射變換),我有了他們的新位置; q0,q1,q2。

我也有轉型前的第四點; P3。我想在相同的轉換之後計算它的位置; Q4。

所以我需要計算轉換矩陣,然後將其應用於p4。我也不知道該怎麼做。 List =一組對象

import pymel.core as pm 
import pymel.core.datatypes as dt 

p0 = dt.Vector(pm.getAttr(list[0]+".tx"), pm.getAttr(list[0]+".ty"), pm.getAttr(list[0]+".tz")) 
p1 = dt.Vector(pm.getAttr(list[1]+".tx"), pm.getAttr(list[1]+".ty"), pm.getAttr(list[1]+".tz")) 
p2 = dt.Vector(pm.getAttr(list[2]+".tx"), pm.getAttr(list[2]+".ty"), pm.getAttr(list[2]+".tz") 
p3 = dt.Vector(pm.getAttr(list[3]+".tx"), pm.getAttr(list[3]+".ty"), pm.getAttr(list[3]+".tz")) 

從Maya場景中的動畫對象中讀取3D點。因此,在另一幀, 我運行此代碼以獲得

q0 = dt.Vector(pm.getAttr(list[0]+".tx"), pm.getAttr(list[0]+".ty"), pm.getAttr(list[0]+".tz")) 
q1 = dt.Vector(pm.getAttr(list[1]+".tx"), pm.getAttr(list[1]+".ty"), pm.getAttr(list[1]+".tz")) 
q2 = dt.Vector(pm.getAttr(list[2]+".tx"), pm.getAttr(list[2]+".ty"), pm.getAttr(list[2]+".tz")) 
#q3 = TransformationMatrix between (p0,p1,p2) and (q0,q1,q2), applied to p3 

我試着用向量來計算的,但我結束了錯誤,由於被零師...... 所以我想,一個變換矩陣應解決它沒有問題。

我已經有一個截止日期不遠了,我真的需要幫助解決這個問題! 請幫助!

編輯: how to perform coordinates affine transformation using python?

我需要這個功能「solve_affine」,但它應該從每個組的而不是4只取3分,我不能使用numpy的...

+0

考慮到本網站上很少有人會理解你的問題(因爲它是特定的),你最好的行動方式是發佈你的代碼,因爲我們可能真的能夠幫助你接着就,隨即。 – sshashank124

+0

對不起,沒想到我的代碼會有任何幫助。我迄今爲止所做的只是分配點數。我現在添加了它,希望它能讓我的問題更容易理解 – user1066278

回答

0

我我們計算出它

p0p1 = p1-p0 
p0p2 = p2-p0 
p0p3 = p3-p0 

q0q1 = q1-q0 
q0q2 = q2-q0 
q0q3 = q3-q0 

before = dt.Matrix([p0.x, p0.y, p0.z, 0],[p1.x, p1.y, p1.z, 0],[p2.x, p2.y, p2.z, 0], [0,0,0,1]); 
after = dt.Matrix([q0.x, q0.y, q0.z, 0],[q1.x, q1.y, q1.z, 0],[q2.x, q2.y, q2.z, 0], [0,0,0,1]); 

normal = p0p1.cross(p0p2).normal() 
dist = p0p3.dot(normal) 
q3 = p3 - dist*normal 

transformMatrix = before.inverse()*after 
solve = dt.Matrix(q3.x, q3.y, q3.z, 1)*transformMatrix 

q3 = dt.Vector(solve[0][0], solve[0][1], solve[0][2]) 

newNormal = q0q1.cross(q0q2).normal() 
q3 = q3 + newNormal*dist 

pm.move(list[3], q3, r=False) 

轉換矩陣只適用於平面p0p1p2內的點。所以我通過轉換p3的投影點來解決它,然後將它從平面上移出相同的距離。

如果你有一個解決方案,只涉及矩陣,隨意分享,它可能仍然幫助我! :)

2

這是一個使用numpy和scipy的解決方案。 scipy主要用於產生隨機旋轉,除了scipy.linalg.norm易於自己編碼。 numpy使用的主要內容是叉積和矩陣乘法,它們也很容易編碼。基本思想是這樣的:給出三個非共線點x1,x2,x3,可以找到向量(軸)v1,v2,v3的正交三元組,其中v1在x2-x1的方向上, v2在由(x2-x1)和(x3-x1)跨越的平面中,並且v3完成三元組。

點y1,y2,y3相對於x1,x2,x3旋轉和平移。由y1,y2,y3生成的軸w1,w2,w3從v1,v2,v3旋轉(即不翻譯)。這兩套三元的分別正交的,所以很容易從中找到旋轉:R = W * transpose(V)

一旦我們有了轉動,尋找翻譯很簡單:y1 = R*x + t,所以t = y1 - R*x。使用最小二乘解算器並結合所有三個點來獲得t的估計可能會更好。

import numpy 
import scipy.linalg 


def rand_rot(): 
    """Return a random rotation 

    Return a random orthogonal matrix with determinant 1""" 
    q, _ = scipy.linalg.qr(numpy.random.randn(3, 3)) 
    if scipy.linalg.det(q) < 0: 
     # does this ever happen? 
     print "got a negative det" 
     q[:, 0] = -q[:, 0] 
    return q 


def rand_noncollinear(): 
    """Return 3 random non-collinear vectors""" 
    while True: 
     b = numpy.random.randn(3, 3) 
     sigma = scipy.linalg.svdvals(b) 
     if sigma[2]/sigma[0] > 0.1: 
      # "very" non-collinear 
      break 
     # "nearly" collinear; try again 

    return b[:, 0], b[:, 1], b[:, 2] 


def normalize(a): 
    """Return argument normalized""" 
    return a/scipy.linalg.norm(a) 


def colstack(a1, a2, a3): 
    """Stack three vectors as columns""" 
    return numpy.hstack((a1[:, numpy.newaxis], 
         a2[:, numpy.newaxis], 
         a3[:, numpy.newaxis])) 


def get_axes(a1, a2, a3): 
    """Generate orthogonal axes from three non-collinear points""" 
    # I tried to do this with QR, but something didn't work 
    b1 = normalize(a2-a1) 
    b2 = normalize(a3-a1) 
    b3 = normalize(numpy.cross(b1, b2)) 
    b4 = normalize(numpy.cross(b3, b1)) 
    return b1, b4, b3 

# random rotation and translation 
r = rand_rot() 
t = numpy.random.randn(3) 

# three non-collinear points 
x1, x2, x3 = rand_noncollinear() 
# some other point 
x4 = numpy.random.randn(3) 

# the images of the above in the transformation. 
# y4 is for checking only -- won't be used to estimate r or t 
y1, y2, y3, y4 = [numpy.dot(r, x) + t 
        for x in x1, x2, x3, x4] 


v1, v2, v3 = get_axes(x1, x2, x3) 
w1, w2, w3 = get_axes(y1, y2, y3) 

V = colstack(v1, v2, v3) 
W = colstack(w1, w2, w3) 

# W = R V, so R = W * inverse(V); but V orthogonal, so inverse(V) is 
# transpose(V): 
rfound = numpy.dot(W, V.T) 

# y1 = R x1 + t, so... 
tfound = y1-numpy.dot(r, x1) 

# get error on images of x2 and x3, just in case 

y2err = scipy.linalg.norm(numpy.dot(rfound, x2) + tfound - y2) 
y3err = scipy.linalg.norm(numpy.dot(rfound, x3) + tfound - y3) 

# and check error image of x4 -- getting an estimate of y4 is the 
# point of all of this 
y4err = scipy.linalg.norm(numpy.dot(rfound, x4) + tfound - y4) 

print "y2 error: ", y2err 
print "y3 error: ", y3err 
print "y4 error: ", y4err 
1

說明和代碼都很混亂。描述有點含糊,而代碼示例缺少重要的零碎。所以這裏是我如何理解這個問題:

知道兩個空間中的三個點如何構建從空間A到空間B的變換?

two spaces transformed

圖像1:如何以形成2個空間之間的轉換。

答案取決於空間所具有的變換類型。你看到三個點總是形成一個平面跨度。這意味着你可以知道新空間的旋轉,變換和統一尺度是什麼。你也可以知道飛機上的剪切力,以及不均勻的尺度。但是,您無法知道平面法線方向上的剪切或不均勻尺度。

因此,有意義的問題變成如何旋轉和翻譯兩個空間匹配?這是很容易做到的翻譯部分是直接:

反= Q0 - P0

這使得你已在幾個職位進行了說明旋轉:

您也可以在此之後計算比例因子。