Если вы являетесь энтузиастом науки о данных или машинного обучения, вы, должно быть, сталкивались с PCA (анализ основных компонентов), который является популярным алгоритмом машинного обучения без учителя, в основном используемым для уменьшения размерности большого набора данных. Мы также можем использовать PCA для уменьшения размерности изображений.

Простой вариант использования

Давайте подумаем о случае, когда вы работаете над проектом AI-ML, который имеет дело с изображениями. Обычно изображения имеют много пикселей, чтобы сохранить свою четкость, но это значительно увеличивает их размер и снижает производительность системы, когда ей приходится обрабатывать несколько изображений. Чтобы преодолеть эту ситуацию, мы можем использовать технику уменьшения размерности, которая относится к неконтролируемому машинному обучению. Почему бы нам не проверить, пригодится ли PCA в этом случае или нет? В этой статье мы будем использовать одну картинку и уменьшать ее размеры или, другими словами, сжимать изображение с помощью PCA в python.

В конце статьи мы сравним полученное изображение с исходным изображением, чтобы подтвердить наши усилия.

Я объяснил математику, лежащую в основе анализа главных компонентов (PCA), в моей предыдущей статье. Если вы еще не прошли его, вы можете щелкнуть здесь, чтобы пройти то же самое.

Теперь давайте начнем!

Сначала мы разделим изображение на три канала (синий, зеленый и красный), а затем выполним PCA отдельно для каждого набора данных, представляющего каждый канал, а затем объединим их для восстановления сжатого изображения. Следовательно, если наше цветное изображение имеет форму (m, n, 3), где (m X n) — общее количество пикселей изображения на трех каналах (b, g, r).

Мы также можем выполнить то же самое без разделения на синий, зеленый и красный каналы и преобразования данных в (m, n X 3) пикселей, но мы обнаружили, что объясняемое отношение дисперсии, заданное тем же количеством компонентов PCA, лучше. если мы используем метод расщепления, как упоминалось в предыдущем абзаце.

Я буду использовать следующую фотографию для демонстрации.

Загрузить и предварительно обработать изображение

Давайте сначала импортируем библиотеки:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import cv2
from scipy.stats import stats
import matplotlib.image as mpimg

Теперь давайте прочитаем изображение rose.jpg и отобразим его.

img = cv2.cvtColor(cv2.imread('rose.jpg'), cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()

Вывод:

Проверьте форму, используя следующую строку:

img.shape

Вывод:

(485, 485, 3)

Теперь я разделю изображение на 3 канала и покажу каждое изображение:

#Splitting into channels
blue,green,red = cv2.split(img)
# Plotting the images
fig = plt.figure(figsize = (15, 7.2)) 
fig.add_subplot(131)
plt.title("Blue Channel")
plt.imshow(blue)
fig.add_subplot(132)
plt.title("Green Channel")
plt.imshow(green)
fig.add_subplot(133)
plt.title("Red Channel")
plt.imshow(red)
plt.show()

Вывод:

Проверим данные синего канала:

blue_temp_df = pd.DataFrame(data = blue)
blue_temp_df

Вывод:

Я разделю все данные всех каналов на 255, чтобы данные масштабировались между 0 и 1.

df_blue = blue/255
df_green = green/255
df_red = red/255

Подгонка и преобразование данных в PCA

Мы уже видели, что каждый канал имеет 485 измерений, и теперь мы будем рассматривать только 50 измерений для PCA, подгонять и преобразовывать данные и проверять, насколько объясняется дисперсия после сокращения данных до 50 измерений.

pca_b = PCA(n_components=50)
pca_b.fit(df_blue)
trans_pca_b = pca_b.transform(df_blue)
pca_g = PCA(n_components=50)
pca_g.fit(df_green)
trans_pca_g = pca_g.transform(df_green)
pca_r = PCA(n_components=50)
pca_r.fit(df_red)
trans_pca_r = pca_r.transform(df_red)

Мы подогнали данные в PCA, давайте проверим форму преобразованного изображения каждого канала:

print(trans_pca_b.shape)
print(trans_pca_r.shape)
print(trans_pca_g.shape)

Вывод:

(485, 50)
(485, 50)
(485, 50)

Как и ожидалось. Давайте проверим сумму объясненных коэффициентов дисперсии 50 компонентов PCA (т. е. наиболее преобладающих 50 собственных значений) для каждого канала.

print(f"Blue Channel : {sum(pca_b.explained_variance_ratio_)}")
print(f"Green Channel: {sum(pca_g.explained_variance_ratio_)}")
print(f"Red Channel  : {sum(pca_r.explained_variance_ratio_)}")

Вывод:

Blue Channel : 0.9946260772755372
Green Channel: 0.9918219615668648
Red Channel  : 0.987736292777275

Вау, это великолепно! потому что, используя только 50 компонентов, мы можем сохранить около 99% дисперсии данных.

Давайте построим гистограммы, чтобы проверить объясненный коэффициент дисперсии по каждому собственному значению отдельно для каждого из 3 каналов:

fig = plt.figure(figsize = (15, 7.2)) 
fig.add_subplot(131)
plt.title("Blue Channel")
plt.ylabel('Variation explained')
plt.xlabel('Eigen Value')
plt.bar(list(range(1,51)),pca_b.explained_variance_ratio_)
fig.add_subplot(132)
plt.title("Green Channel")
plt.ylabel('Variation explained')
plt.xlabel('Eigen Value')
plt.bar(list(range(1,51)),pca_g.explained_variance_ratio_)
fig.add_subplot(133)
plt.title("Red Channel")
plt.ylabel('Variation explained')
plt.xlabel('Eigen Value')
plt.bar(list(range(1,51)),pca_r.explained_variance_ratio_)
plt.show()

Вывод:

Реконструировать изображение и визуализировать

Мы завершили уменьшение размерности PCA. Теперь мы снова визуализируем изображение, и для этого нам нужно сначала преобразовать данные в обратном направлении, а затем объединить данные всех трех каналов в один. Давайте продолжим.

b_arr = pca_b.inverse_transform(trans_pca_b)
g_arr = pca_g.inverse_transform(trans_pca_g)
r_arr = pca_r.inverse_transform(trans_pca_r)
print(b_arr.shape, g_arr.shape, r_arr.shape)

Вывод:

(485, 485) (485, 485) (485, 485)

Мы можем обратно преобразовать данные в исходную форму (хотя каждый канал по-прежнему разделен), но, как мы знаем, все изображения уже сжаты.

Мы объединим все каналы в один и напечатаем окончательную форму:

img_reduced= (cv2.merge((b_arr, g_arr, r_arr)))
print(img_reduced.shape)

Вывод:

(485, 485, 3)

Приятно видеть точную форму исходного изображения, которое мы импортировали в самом начале. Теперь мы будем отображать оба изображения (исходное и уменьшенное) рядом.

fig = plt.figure(figsize = (10, 7.2)) 
fig.add_subplot(121)
plt.title("Original Image")
plt.imshow(img)
fig.add_subplot(122)
plt.title("Reduced Image")
plt.imshow(img_reduced)
plt.show()

Вывод:

Удивительно видеть, что сжатое изображение очень похоже (по крайней мере, мы все еще можем идентифицировать его как розу) на оригинальное, хотя мы уменьшили размер отдельно для каждого канала до 50 с 485. Но мы достигли Наша цель. Можно не сомневаться, что теперь уменьшенное изображение будет обрабатываться компьютером гораздо быстрее.

Заключение

Я объяснил, как мы можем использовать PCA для уменьшения размера цветного изображения, разбивая его на 3 канала, а затем реконструируя его обратно для визуализации.

Я надеюсь, вам понравилось читать и учиться из статьи.

Вы можете скачать полный код, а также показанное здесь изображение, которое находится в том же каталоге, по моей ссылке на github, указанной ниже: