ravi
ravi

Reputation: 6328

Multiply matrix by each row of another matrix in Numpy

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]

Upvotes: 4

Views: 3186

Answers (4)

John Henckel
John Henckel

Reputation: 11347

Your trajectory is nx3, but in order to multiply correctly you need 3xn. Therefore you'll need to transpose twice. Once before multiply and once after.

Like this,

trajectory = (HTM[:3,:3] @ trajectory.T).T

I assume that trajectory is a vector and you want to ignore the HTM origin? If you want to also add the origin, then you can do this.

trajectory = (HTM[:3,:3] @ trajectory.T).T + HTM[:3,3]

Upvotes: 0

Divakar
Divakar

Reputation: 221524

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

Upvotes: 1

Daniel F
Daniel F

Reputation: 14399

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

Upvotes: 1

P. Camilleri
P. Camilleri

Reputation: 13218

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?

Upvotes: 1

Related Questions