Skip to content

Image Matrix Transformations

If \(A\) is a \(3\times 3\) matrix then we can apply a linear transformation to each rgb vector via matrix multiplication, where \([r,g,b]\) are the original values and \([r',g',b']\) are the new values.

\[\begin{bmatrix} r' \\ g' \\ b' \end{bmatrix} = \begin{bmatrix} a_{1,1} & a_{1,2} & a_{1,3} \\ a_{2,1} & a_{2,2} & a_{2,3} \\ a_{3,1} & a_{3,2} & a_{3,3} \end{bmatrix} \begin{bmatrix} r \\ g \\ b \end{bmatrix} \]

If img is an image then we can apply a matrix transformation A to the pixel at location \((i,j)\) by

A @ img[i,j,:]

This is a matrix-vector product. Alternatively, if we are viewing the rgb vector as a row vector then we would compute:

img[i,j,:] @ A.T

or using dot we could do

img[i,j,:].dot(A.T)

The latter is best practice, since this allows us to avoid looping over rows/columns of the image, we could just call

img.dot(A.T)

and it will automatically compute the vector/matrix product for each pixel, and return a new image. This is the method we will use below.

For quick reference, some common matrices we will use are:

sepia_matrix = np.array([[ 0.393, 0.769, 0.189],
                         [ 0.349, 0.686, 0.168],
                         [ 0.272, 0.534, 0.131]])

gray_const_matrix = np.array([[ 0.333, 0.333, 0.333],
                              [ 0.333, 0.333, 0.333],
                              [ 0.333, 0.333, 0.333]])

gray_matrix = np.array([[0.2989, 0.5870, 0.1140],
                        [0.2989, 0.5870, 0.1140],
                        [0.2989, 0.5870, 0.1140],])

red_matrix = np.array([[ 1, 0, 0],
                       [ 0, 0, 0],
                       [ 0, 0, 0]])

grn_matrix = np.array([[ 0, 0, 0],
                       [ 0, 1, 0],
                       [ 0, 0, 0]])

blu_matrix = np.array([[ 0, 0, 0],
                       [ 0, 0, 0],
                       [ 0, 0, 1]])

Sepia Tone

Sepia (tone) is similar to black-and-white in that it is one colour, but it is more brown or tan. This is typically what you see in historic photos. We can convert a colour image to sepia as follows.

The sepia values of a pixel with rgb values \([r,g,b]\) are:

\(\text{sepia}_r = 0.393r + 0.769g + 0.189b\)
\(\text{sepia}_g = 0.349r + 0.686g + 0.168b\)
\(\text{sepia}_b = 0.272r + 0.534g + 0.131b\)

We can write this as a matrix transformation:

\[ \begin{bmatrix} \text{sepia}_r \\ \text{sepia}_g \\ \text{sepia}_b \end{bmatrix} = \begin{bmatrix} 0.393 & 0.769 & 0.189\\ 0.349 & 0.686 & 0.168\\ 0.272 & 0.534 & 0.131 \end{bmatrix} \begin{bmatrix} r \\ g \\ b \end{bmatrix} \]

To apply this filter to a colour image img we call

sepia_img = img.dot(sepia_matrix.T)

Since sepia matrix rows do not have unit sums, once the full sepia image is constructed, we need to rescale the result

sepia_img /= sepia_img.max()

then extend values from 0 to 255:

sepia_img *= 255

We'll put all these steps into a function called apply_matrix:

def apply_matrix(img,A):
    trans_img = img/256
    trans_img = trans_img.dot(A.T)
    trans_img /= trans_img.max()
    trans_img *= 255
    trans_img = trans_img.astype('uint8')
    return(trans_img)

In this example we use this photo of a dog.

img = plt.imread('dog.jpg')
img_gray = apply_matrix(img,gray_matrix) # construct gray scale image
img_sepia = apply_matrix(img,sepia_matrix) # construct sepia tone image

# display all three images
fig = plt.figure(figsize=(12,10))
plt.imshow(np.concatenate((img, img_gray, img_sepia),axis=1))

Image Image

Gray Scale

We've already covered how to convert an image to gray scale in the Image Manipulation Basics section. However, we can also do this using matrix multiplication. There are two gray scale matrices listed above, the second one give the channels different weights. This is the one we used in converting the dog image to gray scale above.

Red, Green, and Blue Channels

We've already covered how to convert an image to gray scale in the Image Manipulation Basics section. Here we just demonstrate how it could be done with matrix multiplication.

img = plt.imread('dog.jpg')
img_r = apply_matrix(img,red_matrix)
img_g = apply_matrix(img,grn_matrix)
img_b = apply_matrix(img,blu_matrix)


# dispaly all three images
fig = plt.figure(figsize=(12,10))
plt.imshow(np.concatenate((img_r, img_g, img_b),axis=1))

Image Image