4

I'm trying the following:

Given a matrix A (x, y ,3) and another matrix B (3, 3), I would like to return a (x, y, 3) matrix in which the 3rd dimension of A is multiplied by the values of B (similar when an RGB image is transformed into gray, only that those "RGB" values are multiplied by a matrix and not scalars)...

Here's what I've tried:

np.multiply(B, A)
np.einsum('ijk,jl->ilk', B, A)
np.einsum('ijk,jl->ilk', A, B)

All of them failed with dimensions not aligned.

What am I missing?

DanielY
  • 1,141
  • 30
  • 58

2 Answers2

5

You can use np.tensordot -

np.tensordot(A,B,axes=((2),(1)))

Related post to understand tensordot.

einsum equivalent would be -

np.einsum('ijk,lk->ijl', A, B)

We can also use A.dot(B.T), but that would be looping under the hoods. So, might not be the most preferred one, but it's a compact solution,

Divakar
  • 218,885
  • 19
  • 262
  • 358
  • I got no error with these functions! :)) but for some reason I get wrong values...I mean when I try to display the image with the new values I get an error – DanielY Oct 25 '17 at 11:08
  • @DanielY Maybe you were meant to `sum-reduce` the first axis of `B`? Then, use : `np.tensordot(A,B,axes=((2),(0)))`? – Divakar Oct 25 '17 at 11:09
  • @DanielY Also, make sure you are not overflowing and also using uint8 dtype for image displaying. – Divakar Oct 25 '17 at 11:10
  • I get many negative values...I think my B is wrong or upside down...I'll check that. Thanks – DanielY Oct 25 '17 at 11:13
  • When trying tensordot() function I get a result matrix of (3, x, y) instead of (x, y, 3) – DanielY Oct 25 '17 at 11:44
  • @DanielY If `A` is `(x,y,3) and `B` is (3,3)`, with `np.tensordot(A,B,axes=((2),(1)))` you would have a result of shape `(x,y,3)`. So, check again. – Divakar Oct 25 '17 at 11:47
  • Please remember i'm doing B*A and not A*B, so running np.tensordot(B,A,axes=((1),(2))) which is what you wrote only with B, A and their axes upside down, I get shape (3, x, y) – DanielY Oct 25 '17 at 11:51
  • @DanielY And why would you be doing `np.tensordot(B,A,axes=((1),(2)))`, when I suggested something else? Why not try what I posted? – Divakar Oct 25 '17 at 11:55
  • In matrix multiplication as far as I know, order counts. You suggested A * B while I want B * A – DanielY Oct 25 '17 at 11:55
  • @DanielY Please read the linked - `Related post to understand tensordot`. – Divakar Oct 25 '17 at 11:56
  • @DanielY Let me ask again - Have you tried : `np.tensordot(A,B,axes=((2),(1)))`? – Divakar Oct 25 '17 at 12:00
  • Yes I did, the dimensions are right. I didn't got valid values though – DanielY Oct 25 '17 at 12:03
  • @DanielY Can you add sample case alongwith expected values into the question? – Divakar Oct 25 '17 at 12:06
  • I'm actually trying to implement RGB to YIQ transformation using numpy actions only, according to the matrix here: https://en.wikipedia.org/wiki/YIQ , so I have no specific test-case, only that the values shouldn't exceed certain range – DanielY Oct 25 '17 at 12:11
  • @DanielY Without sample that reproduces your issue, can't help really. – Divakar Oct 25 '17 at 12:11
3

Sorry for the confusion, I think you can do something like this, using simple numpy methods:

First you can reshape A in a way that its fibers (or depth vectors A[:,:,i]) will be placed as columns in matrix C:

C = A.reshape(x*y,3).T

Then using a simple matrix multiplication you can do:

D = numpy.dot(B,C)

Finally bring the result back to the original dimensions:

D.T.reshape([x,y,3])
m33n
  • 1,622
  • 15
  • 38