본문 바로가기
재미로 하는 코딩

numpy를 사용한 이미지 압축해보기!

by 헬푸밍 2023. 3. 30.

오늘 사용할 이미지는...

주말에 찍은 사진이다... ㅎㄷㄷ 소녀다리... 재성합니다...

 

일단 필요라이브러리 업로드!

import numpy as np
from sys import getsizeof
import os
import matplotlib.pyplot as plt
%matplotlib inline

 

그러면... 이미지를 불러오자!

posing_ori = plt.imread("data/image/posing_original.png")
posing_ori

대충 보면... 이미 정규화된 데이터같다!

 

확인해보면...

posing_ori.max(), posing_ori.min()

역시나 정규화가 되어있는데이터네...?

 

shape값을 한번 보면...

posing_ori.shape

채널 값이 4라서 RGB가 아닌 RGBA데이터 임을 알 수 있다!

 

한 번 R, G, B, A를 분리해보면...

 

R

plt.imshow(posing_ori[:, :, 0], cmap='Reds')

G

plt.imshow(posing_ori[:, :, 1], cmap='Greens')

 

B

plt.imshow(posing_ori[:, :, 2], cmap='Blues')

 

A

a는 투명도를 결정하는 것인데... cmap을 어떻게 설정하는지 모르겠다.

그래서 기본값인... 보랑, 노라가 나온다...

plt.imshow(posing_ori[:, :, 3])

이렇고...

 

합쳐서보면... 이렇고...

저장도 해준다!

plt.imshow(posing_ori)
plt.savefig('data/image/posing_ori')

이렇다...

 

넘파이의 linalg.svd를 사용하려 하는데...

채널이 4개여서...

계산 문제로...

전치행렬을 만들어주자!

posing_ori_transposed = np.transpose(posing_ori, (2, 0, 1))
posing_ori_transposed.shape

채널이 앞으로 빠졌다!

 

그럼 U, s Vt값을 만들어주자!

U, s, Vt = np.linalg.svd(posing_ori_transposed)
U.shape, s.shape, Vt.shape

이렇게 U, s, Vt가 만들어졌다!

 

복원하려면...

U, s, Vt를 곱해야하는데... s가 채널 각각의 shape은 (1,1051)이여서...

(1411, 1051)값으로 변경해 행렬을 만들어주자!

Sigma = np.zeros(posing_ori_transposed.shape)
for i in range(4):
    np.fill_diagonal(Sigma[i, :, :], s[i, :])

 

채널 하나하나 Sigma의 값을 보면...

Sigma[0, :, :].shape, Sigma[1, :, :].shape, Sigma[2, :, :].shape, Sigma[3, :, :].shape

 

그럼...

복원해보면...

reconstructed = U @ Sigma @ Vt
reconstructed.shape

이렇게 원래대로 돌아왔다!

 

부동소수점 오류가 있나 확인해보자!

reconstructed.min(), reconstructed.max()

역시 오류가 생겼다!

 

그럼 clip을 사용해서 최대, 최소를, 0, 1로 하자!

reconstructed = np.clip(reconstructed, 0, 1)
reconstructed.min(), reconstructed.max()

 

그럼 원래 것과 비교를 해보자!

np.allclose로 비교해보면...

 

 

그럼 복원한 파일을 보자!

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

 

그럼 돌아가서...

R,G,B,A값의 s크기를... 보면...

plt.plot(np.linspace(0, 1051, 1051), s[0], color='red', marker='.')
plt.plot(np.linspace(0, 1051, 1051), s[1], color='green', marker='*')
plt.plot(np.linspace(0, 1051, 1051), s[2], color='blue', marker='x')
plt.plot(np.linspace(0, 1051, 1051), s[3], color='purple', marker='+')

겹쳐서 잘 안보이지만...

A값만 매우 살짝? 다르고... 추세가 거의 같다...

s에서 뒤로갈수록 숫자가 거의 0이다!

 

그러면 k=10으로 특이값 분해를 해보자!

분해를 한 뒤 저장까지 해준다!

k = 10
posing_10 = U @ Sigma[..., :k] @ Vt[:, :k, :]
posing_10 = np.clip(posing_10, 0, 1)
posing_10 = np.transpose(posing_10, (1, 2, 0))
plt.imshow(posing_10)
plt.savefig('data/image/posing_10.png')

화질.. ㅎㄷㄷ 하다!

 

이번엔 k=50으로 해보자!

k = 50
posing_50 = U @ Sigma[..., :k] @ Vt[:, :k, :]
posing_50 = np.clip(posing_50, 0, 1)
posing_50 = np.transpose(posing_50, (1, 2, 0))
plt.imshow(posing_50)
plt.savefig('data/image/posing_50.png')

화질이 좀 나아지긴 하지만 딱 모나리자 수준이다!

 

각각 파일의... 크기를 확인해보면...

print(format(os.stat("data/image/posing_10.png").st_size, ","))
print(format(os.stat("data/image/posing_50.png").st_size, ","))
print(format(os.stat("data/image/posing_ori.png").st_size, ","))

조금 차이가 있긴하지만...

그렇게 크지는? 않은 것 같다!

'재미로 하는 코딩' 카테고리의 다른 글

시각화 뽀개기13  (0) 2023.03.30
시각화 뽀개기12  (0) 2023.03.23
시각화 뽀개기11  (0) 2023.03.19
다이아몬드 가격 예측해보기  (4) 2023.03.19
시각화 뽀개기10  (0) 2023.03.16

댓글