SoFunction
Updated on 2024-10-30

NumPy implementation of linear algebra in multidimensional arrays

synopsis

This article will explain how to perform linear algebra operations on multidimensional data in NumPy in the form of diagrams.
Linear algebra for multidimensional data is often used in graphical transformations for image processing, which will be illustrated in this paper using an example of an image.

Graphics loading and description

Those of you who are familiar with colors should know that a color can be represented by R, G, B, and if it's a little more advanced, then there is an A for transparency. Usually we represent this with an array of four attributes.

For a two-dimensional image, its resolution can be viewed as an X*Y matrix, and the color of each point in the matrix can be represented by (R, G, B).

With the above knowledge, we can break down the colors of an image.

First an image needs to be loaded, we use the method to load a local image as shown below:

import imageio
img=('')
print(type(img))

The above code reads the image from local to img object, use type to see the type of img, from the running result, we can see the type of img is an array.

class ''

By can get img is a (80, 170, 4) 3D array, that means the resolution of this image is 80*170 and each pixel is an array of (R, B, G, A).

Finally the image is drawn as shown below:

import  as plt
(img)

Grayscale of graphics

For three dimensional arrays, we can get three separate color arrays as shown below:

red_array = img_array[:, :, 0]
green_array = img_array[:, :, 1]
blue_array = img_array[:, :, 2]

Once we have the three colors we can grayscale transform them using the following formula:

Y=0.2126R + 0.7152G + 0.0722B

Y in the above figure represents the gray scale.
How do you use multiplication of matrices? Just use @:

 img_gray = img_array @ [0.2126, 0.7152, 0.0722]

Now img is an 80 * 170 matrix.
Now graph using cmap="gray":

(img_gray, cmap="gray")

The following grayscale image can be obtained:

Compression of grayscale images

A grayscale image is a transformation of the color of an image, what should be done if the image is to be compressed?

There is a concept in matrix operations called singular values and eigenvalues.

Let A be an n-order matrix, if there exists a constant λ and an n-dimensional nonzero vector x such that Ax = λx, then λ is said to be an eigenvalue of the matrix A, and x is an eigenvector of A belonging to the eigenvalue λ.

A set of eigenvectors of a matrix is a set of orthogonal vectors.

That is, a linear transformation A applied to an eigenvector will only lengthen or shorten the vector without changing its direction.

Eigendecomposition, also known as Spectral decomposition, is a method of decomposing a matrix into a product of matrices represented by their eigenvalues and eigenvectors.

If A is a matrix of order m * n with q = min(m,n), the arithmetic square root of the q non-negative eigenvalues of A*A is called the singular value of A.

The eigenvalue decomposition makes it easy to extract the features of a matrix, but only if the matrix is a square matrix. If it is a non-square matrix, you need to use the singular value decomposition. Let's look at the definition of singular value decomposition:

A=UΣVT

where A is the m * n matrix that the objective is to be decomposed into, U is an m * m square matrix, and Σ is an m * n matrix whose elements on the off-diagonal are 0. VTV^TVT is the transpose of V, which is also an n * n matrix.

The singular values, similar to the eigenvalues, are arranged from largest to smallest in the matrix Σ. Moreover, the singular values decrease particularly fast, and in many cases the sum of the first 10% or even 1% of the singular values accounts for more than 99% of the sum of all the singular values. That is, we can also approximate the matrix with the first r large singular values. r is a much smaller number than m and n, so that the compression of the matrix can be performed.

With singular value decomposition, we can approximate the replacement of the original matrix by a much smaller amount of data.

To use the singular value decomposition svd can be called directly as shown below:

U, s, Vt = (img_gray)

where U is an m * m matrix and Vt is an n * n matrix.

In the above image, U is a matrix of (80, 80) and Vt is a matrix of (170, 170). And s is an array of 80 and s contains the singular values in the img.

If s is represented as an image, we can see that most of the singular values are concentrated in the front part:

This also means that we can take some of the previous values in s for image reconstruction.
Reconstructing an image using s requires reducing s to an 80 * 170 matrix:

# Reconstruction
import numpy as np
Sigma = ((80, 170))
for i in range(80):
    Sigma[i, i] = s[i]

The original matrix can be reconstructed using U @ Sigma @ Vt. A calculation can be done to compare the difference between the original and reconstructed matrices.

(img_gray - U @ Sigma @ Vt)

Or use to compare the difference between two matrices:

(img_gray, U @ Sigma @ Vt)

Or take only the first 10 elements of the s array, do a redraw, and compare the difference with the original:

k = 10
approx = U @ Sigma[:, :k] @ Vt[:k, :]
(approx, cmap="gray")

As you can see, the difference is not that great:

Compression of the original image

In the previous section we talked about how to do grayscale image compression, so how do you compress the original image?

The same can be done using a decomposition of the matrix.

However, some processing is required before use, as the img_array of the original image is a (80, 170, 3) matrix - here we have removed the transparency and kept only the R, B, and G attributes.

Before performing the transformation, we need to put the axis that does not need to be transformed to the top, that is, change index=2, to index=0, and then perform the svd operation:

img_array_transposed = (img_array, (2, 0, 1))
print(img_array_transposed.shape)

U, s, Vt = (img_array_transposed)
print(, , )

Similarly, s is now a (3, 80) matrix, still one dimension short, which needs to be filled and processed if the image is reconstructed, and finally the reconstructed image is output:

Sigma = ((3, 80, 170))

for j in range(3):
    np.fill_diagonal(Sigma[j, :, :], s[j, :])

reconstructed = U @ Sigma @ Vt
print()

((reconstructed, (1, 2, 0)))

Of course, it is also possible to select the previous K eigenvalues to compress the image:

approx_img = U @ Sigma[..., :k] @ Vt[..., :k, :]
print(approx_img.shape)
((approx_img, (1, 2, 0)))

The reconstructed image is as follows:

The comparison shows that the image is still distinguishable despite the loss of some accuracy.

summarize

There will be a lot of linear operations involved in the change of the image, so you can use this article as an example to scrutinize it.

This article on NumPy to achieve linear algebra in multi-dimensional arrays is introduced to this article, more related NumPy multi-dimensional arrays linear algebra content please search my previous posts or continue to browse the following related articles I hope that you will support me more in the future!