Поэлементное матрично-векторное произведение с NumPy

#numpy

#numpy

Вопрос:

У меня есть изображение MxN RGB, представленное в виде (M, N, 3) массива A . И у меня есть другая (3, 3) матрица B . Я хочу умножить каждый пиксель (3-вектор) на A на B , чтобы получить (M, N, 3) выходную матрицу C , так что C[i][j] = B @ A[i][j] . Как я могу это сделать, не перебирая пиксели внутри A ?

Ответ №1:

Вы можете просто сделать это

 C = (B @ A[...,None]).reshape(A.shape)
 

Ответ №2:

Я думаю, вам нужно будет использовать einsum для этого типа операций:

 import numpy as np

shape = 10, 20, 3
A = np.random.random(np.product(shape)).reshape(shape)
B = np.random.random(9).reshape((3, 3))

print(np.einsum("ijk,lk", A, B).shape)
 

Документацию смотрите здесь.

Ответ №3:

Давайте перепишем:

 C[i][j] = B @ A[i][j]
 

как:

 C[i,j,:] = B[:,:] @ A[i,j,:]  
 

на самом деле я не думаю, что это правильно, потому @ что соединяет последнее из первого, со 2-го по последнее из второго. A требуется дополнительное «фиктивное» измерение.

На самом деле его проще выразить как:

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

итак

 A @ B.T
(B @ A[:,:,:,None]).squeeze()
 

с числами:

 In [33]: A = np.arange(24).reshape(2,4,3)
In [34]: B = np.arange(9).reshape(3,3)
In [35]: np.einsum('ijk,lk->ijl',A,B)
Out[35]: 
array([[[  5,  14,  23],
        [ 14,  50,  86],
        [ 23,  86, 149],
        [ 32, 122, 212]],

       [[ 41, 158, 275],
        [ 50, 194, 338],
        [ 59, 230, 401],
        [ 68, 266, 464]]])
In [36]: A@B.T
Out[36]: 
array([[[  5,  14,  23],
        [ 14,  50,  86],
        [ 23,  86, 149],
        [ 32, 122, 212]],

       [[ 41, 158, 275],
        [ 50, 194, 338],
        [ 59, 230, 401],
        [ 68, 266, 464]]])
In [37]: (B@A[...,None]).squeeze()
Out[37]: 
array([[[  5,  14,  23],
        [ 14,  50,  86],
        [ 23,  86, 149],
        [ 32, 122, 212]],

       [[ 41, 158, 275],
        [ 50, 194, 338],
        [ 59, 230, 401],
        [ 68, 266, 464]]])