Introduction

This article will explain how to perform linear algebra operations on multi-dimensional data in NumPy in the form of graphs.

The linear algebra of multi-dimensional data is usually used in the graphic transformation of image processing. This article will use an image example to illustrate.

Graphic loading and description

Friends who are familiar with colors should know that a color can be represented by R, G, and B. If it is more advanced, then there is an A for transparency. Usually we use an array of four attributes to represent.

For a two-dimensional image, its resolution can be regarded 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 decompose the color of the image.

First, we need to load an image. We use the imageio.imread method to load a local image, as shown below:

import imageio
img=imageio.imread('img.png')
print(type(img))

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

class 'imageio.core.util.Array'

Through img.shape, we can get that img is a three-dimensional array of (80, 170, 4), which means that the resolution of this image is 80*170, and each pixel is an array of (R, B, G, A).

Finally, draw the image as shown below:

import matplotlib.pyplot as plt
plt.imshow(img)

Graphic grayscale

For a three-dimensional array, we can get the three color arrays as follows:

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

After having three colors, we can use the following formula to transform them into gray levels:

Y=0.2126R + 0.7152G + 0.0722B

In the above figure, Y represents the gray scale.

How to use matrix multiplication? Just use @:

 img_gray = img_array @ [0.2126, 0.7152, 0.0722]

Now img is an 80*170 matrix.

Now use cmap="gray" to plot:

plt.imshow(img_gray, cmap="gray")

The following grayscale image can be obtained:

Compression of grayscale images

Grayscale image is to transform the color of the image. How to deal with the image compression?

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

Suppose A is an n-order matrix. If there is a constant λ and an n-dimensional non-zero vector x such that Ax=λx, then λ is the eigenvalue of matrix A, and x is the eigenvector of A belonging to the eigenvalue λ.

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

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

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

If A is m n-order matrix, q=min(m,n), the arithmetic square root of q non-negative eigenvalues of

Eigenvalue decomposition can easily extract the features of the matrix, but the premise is that the matrix is a square matrix. If it is a non-square matrix, singular value decomposition is needed. First look at the definition of singular value decomposition:

$A=UΣV^T$

n that the target wants to decompose, U is a m, and Σ is a n whose off-diagonal elements are all 0. $V^T$ is the transpose of V, which is also a matrix of

Singular values are similar to eigenvalues. They are also arranged from large to small in the matrix Σ, and the singular values decrease extremely fast. of the first 10% or even 1% of the singular values accounts for all the singularities. More than 99% of the values is 161089c238ed9c. In other words, we can also approximate the matrix with the singular value of the first r. r is a number much smaller than m and n, so that the matrix can be compressed.

Through singular value decomposition, we can approximately replace the original matrix with a smaller amount of data.

To use singular value decomposition svd, you can directly call linalg.svd as follows:

U, s, Vt = linalg.svd(img_gray)

Where U is an m m matrix, and Vt is an n n matrix.

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

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

This means that we can take the previous part of s to reconstruct the image.

To reconstruct the image using s, you need to restore s to a matrix of 80 * 170:

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

Use U @ Sigma @ Vt to reconstruct the original matrix. You can compare the difference between the original matrix and the reconstructed matrix by calculating linalg.norm.

linalg.norm(img_gray - U @ Sigma @ Vt)

Or use np.allclose to compare the difference between two matrices:

np.allclose(img_gray, U @ Sigma @ Vt)

Or just take the first 10 elements of the s array and redraw it to compare the difference with the original image:

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

As you can see, the difference is not very big:

Compression of the original image

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

You can also use linalg.svd to decompose the matrix.

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

Before the conversion, we need to put the axis that does not need to be converted to the front, that is to say, change the index=2 to the position of index=0, and then perform the svd operation:

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

U, s, Vt = linalg.svd(img_array_transposed)
print(U.shape, s.shape, Vt.shape)

Similarly, now s is a (3, 80) matrix, and one dimension is missing. If the image is reconstructed, it needs to be filled and processed, and finally the reconstructed image is output:

Sigma = np.zeros((3, 80, 170))

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

reconstructed = U @ Sigma @ Vt
print(reconstructed.shape)

plt.imshow(np.transpose(reconstructed, (1, 2, 0)))

Of course, you can also select the previous K feature values to compress the image:

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

The reconstructed image is as follows:

The comparison shows that although some accuracy is lost, the image can still be distinguished.

Summarize

The image change will involve many linear operations. You can take this article as an example and study it carefully.

This article has been included in http://www.flydean.com/08-python-numpy-linear-algebra/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", know technology, know you better!


flydean
890 声望432 粉丝

欢迎访问我的个人网站:www.flydean.com