3

I have a homogeneous transformation matrix of size (4x4) and a trajectory of size (nx3). Each row of this trajectory is a vector.

I want to multiply homogeneous transformation matrix by each row of trajectory. Below is the code:

#append zero column at last
trajectory = np.hstack((trajectory, np.zeros((trajectory.shape[0], 1)))) #(nx3)->(nx4)

trajectory_new = np.zeros((1, 3)) #(1x3)
for row in trajectory:
    vect = row.reshape((-1,1)) #convert (1x4) to (4x1)
    vect = np.dot(HTM, vect) #(4x4) x (4x1) = (4x1)
    vect = vect.T #(1x4)
    vect = np.delete(vect, -1, axis=1) #remove last element from vector
    trajectory_new = np.vstack((trajectory_new, vect)) #(nx3)

trajectory_new = np.delete(trajectory_new, 0, axis=0)#remove first row

The above code works. However, I am looking for simpler solution, such as following:

trajectory_new = np.apply_along_axis(np.multiply, 0, trajectory, HTM)

Any help, please.

Answer:

trajectory = np.hstack((trajectory, np.ones((trajectory.shape[0], 1))))#(nx3)->(nx4)
trajectory_new = trajectory.dot(HTM.T)[:,:-1]
ravi
  • 6,140
  • 18
  • 77
  • 154
  • You can do it without stacking, as shown in [`this post`](https://stackoverflow.com/a/44542337/3293881). – Divakar Jun 15 '17 at 10:53
  • @Divakar: Are you talking about [this](https://stackoverflow.com/a/44539320/1175065)? It is giving an error because of shape mismatch. Please see my comment in [this](https://stackoverflow.com/a/44539320/1175065) post. – ravi Jun 15 '17 at 11:40
  • I am talking about my post. The link I have posted in my earlier comment links there. – Divakar Jun 15 '17 at 11:41
  • @Divakar: Apologize however you have removed the last column from HTM, which is incorrect. You may remove the last row of HTM but not the last column. More precisely, HTM is (4x4), in which first (3x3) represents rotation matrix and the last column represents translation in 3D space. The last row of HTM is always [0, 0, 0, 1], which makes HTM (4x4) matrix. – ravi Jun 15 '17 at 11:50
  • But you are not using that last column off HTM for computing the output `trajectory_new`. That's why you need to add zeros at the start and remove the first row with the original approach. – Divakar Jun 15 '17 at 11:52
  • No. Actually, the trajectory contains only 3 columns, which is position in `x`, `y` and `z` direction. The last zero has been added just to make computation possible. `HTM` is (4x4) and `trajectory` is (4x1) after adding the zero column. Now the multiplication is `HTM` x `trajectory` which is (4x4) x (4x1) = (4x1). – ravi Jun 15 '17 at 11:59
  • Again, with `np.delete(vect, -1, axis=1) #remove last element from vector` isn't making use of it. That's why the whole point of my comment was we dont need to stack zeros at the start. – Divakar Jun 15 '17 at 12:19
  • (4x4) x (4x1) gives (4x1). Taking a transpose resulted in (1x4)This is a position vector. The last element of this vector is not useful. So I made it (1x3). What I am trying to say is that `HTM[:,:3]` is incorrect. `HTM` and `HTM[:3,:]` is fine. – ravi Jun 15 '17 at 12:35

3 Answers3

1

Could you include an example of input and output? But it seems that np.dot(HTM, trajectory.T)[:3].T could do the trick?

Rather than appending a column of 0 to trajectory, why don't you drop the last row of HTM?

P. Camilleri
  • 12,664
  • 7
  • 41
  • 76
  • `np.dot(HTM, trajectory.T)[:3].T` is returning following error: `shapes (3,4) and (3,5) not aligned: 4 (dim 1) != 3 (dim 0)` – ravi Jun 15 '17 at 05:10
1

I think what you want is something like:

trajectory_new = np.einsum('ij,kj->ik', HTM[:,:3], trajectory)

Not sure about the order, but that should work much faster than for loops

Daniel F
  • 13,620
  • 2
  • 29
  • 55
1

You can simply use matrix-multiplication with np.dot on the input before stacking zeros -

trajectory.dot(HTM[:,:3].T)[:,:3]

Approaches -

def dot_based(trajectory):
    return trajectory.dot(HTM[:,:3].T)[:,:3]

def original_app(trajectory):
    # append zero column at last
    traj_stacked = np.hstack((trajectory, np.zeros((trajectory.shape[0], 1))))

    trajectory_new = np.zeros((1, 3)) #(1x3)
    for row in traj_stacked:
        vect = row.reshape((-1,1)) #convert (1x4) to (4x1)
        vect = np.dot(HTM, vect) #(4x4) x (4x1) = (4x1)
        vect = vect.T #(1x4)
        vect = np.delete(vect, -1, axis=1) #remove last element from vector
        trajectory_new = np.vstack((trajectory_new, vect)) #(nx3)

    trajectory_new = np.delete(trajectory_new, 0, axis=0)#remove first row
    return trajectory_new

Sample run -

In [37]: n = 5
    ...: trajectory = np.random.rand(n,3)
    ...: HTM = np.random.rand(4,4)
    ...: 

In [38]: np.allclose(dot_based(trajectory), original_app(trajectory))
Out[38]: True
Divakar
  • 218,885
  • 19
  • 262
  • 358