import numpy as np
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt
from PIL import Image, ImageOps
import matplotlib.pyplot as plt
# Download original, full data-set or pre-sampled data
# !wget https://storage.googleapis.com/am_205_bucket/img_align_celeba.zip -P ./
# !unzip -q ./img_align_celeba.zip -d ./
!wget https://storage.googleapis.com/am_205_bucket/celeb_sample.zip -P ./
!unzip -q ./celeb_sample.zip -d ./celeb_sample
# Code for random sampling of celeba dataset
sample_size = 1000
# vals = np.random.choice(list(range(200000)), size=sample_size, replace=False)
# img_lst = [Image.open('./img_align_celeba/{}.jpg'.format( str(i).zfill(6) )) for i in vals]
# X = np.array([np.array(img) for img in img_lst])
# !mkdir celeb_sample
# [img.save('celeb_sample/{}.jpg'.format(i)) for i, img in enumerate(img_lst)]
# Loading pre-sampled celeb images
img_lst = [Image.open('./celeb_sample/{}.jpg'.format(i)) for i in range(sample_size)]
X = np.array([np.array(img) for img in img_lst]) / 255
im_shape = X[0].shape
X.shape
# Visualize some samples from the training dataset
fig, ax = plt.subplots(2, 5, figsize=(15, 7))
for i in range(5):
ax[0, i].imshow(X[i])
ax[1, i].imshow(X[i+5])
ax[0, i].axis("off")
ax[1, i].axis("off")
fig.suptitle('Sample CelebA Data')
plt.show()
# Compute SVD Compression and Decompression of an image
# rank-k approximation and rank-r reconstruction
def svd_compression(im, k, r):
m,n,p = im.shape
S = np.vstack([im[:,:,0],
im[:,:,1],
im[:,:,2]])
# compute the mean of each row to obtain a mean column.
Sm = np.mean(S, axis=1, keepdims=True)
# compute the centered matrix A.
A = S - Sm
def rank_approx(A, k):
L = []
U, s, Vt = np.linalg.svd(A, full_matrices=False)
for i in range(k):
L.append(np.dot(s[i], np.dot(U[:, i].reshape(-1, 1), Vt[i].reshape(1, -1))))
return L, U[:, :k], s[:k], Vt[:k]
def reconstruct(L, r, Sbar):
if r > len(L):
print("Error: r must be less than the length of L.")
return
m = len(Sbar)//3 # the leading dimension of a single channel
# Reconstruct the original image up to rank j.
Ar = np.sum(L[:(r-1)], axis=0)
# Add back the mean and reshape into m by n by p.
Ar += Sbar.reshape(-1,1)
imr = np.stack([Ar[:m,:],Ar[m:2*m,:],Ar[2*m:,:]], axis=2)
# truncate values and return the reconstructed image.
imr[imr<0] = 0; imr[imr>1] = 1
return imr
return rank_approx(A, k), reconstruct(rank_approx(A, k)[0], r, Sm)
# Run a test:
test_vals = [2, 4, 8, 16, 32, 64]
# compute SVD compression and decompression for a list of images and ranks
def test_SVD(ims, test_vals=test_vals):
res_mean = []
err_mean = []
for val in test_vals:
sizes = []
errs = []
for im in ims:
res, imr = svd_compression(im, val, val)
L, U, s, Vt = res
U = np.array(U)
s = np.array(s)
Vt = np.array(Vt)
L = np.array(L)
errs.append(np.mean((np.linalg.norm(im-imr, axis=2))**2))
res_mean.append((U.shape[0] * U.shape[1] + s.shape[0] + Vt.shape[0]) / (im_shape[0] * im_shape[1] * im_shape[2]) )
err_mean.append(np.mean(errs))
return res_mean, err_mean
size_svd, err_svd = test_SVD(X)
# Plot values of size and MSE accross test values
plt.scatter(test_vals, 100 * np.array(size_svd))
plt.plot(test_vals, 100 * np.array(size_svd))
plt.title('Rank vs. Size of Compression')
plt.xlabel('Rank Value')
plt.ylabel('Image Size (as % of original')
plt.show()
plt.scatter(test_vals, err_svd)
plt.plot(test_vals, err_svd)
plt.title('Rank vs. MSE')
plt.xlabel('Rank Value')
plt.ylabel('Image MSE')
plt.show()
# Plot SVD of different ranks accross test images
fig, ax = plt.subplots(len(test_vals) + 1, 5, figsize=(15, 21))
for j, val in enumerate(test_vals[::-1]):
for i in range(5):
if j == 0:
ax[j][i].imshow(X[i])
ax[j][i].axis('off')
ax[j][i].set_title(f'Image {i}')
res, imr = svd_compression(X[i], val, val)
L, U, s, Vt = res
U = np.array(U)
s = np.array(s)
Vt = np.array(Vt)
L = np.array(L)
ax[j+1][i].imshow(imr)
ax[j+1][i].axis('off')
ax[j+1][i].set_title(f'Image {i}, rank: {val}\n {round(100 * (U.shape[0] * U.shape[1] + s.shape[0] + Vt.shape[0]) / (im_shape[0] * im_shape[1] * im_shape[2]),4)}% of image size')
fig.tight_layout(pad=3)
# import and define helper functions for DCT
from scipy.fftpack import dct, idct
def dct3d(img):
return dct(dct(dct(img, norm='ortho', axis=0), norm='ortho', axis=1), norm='ortho', axis=2)
def idct3d(img):
return idct(idct(idct(img, norm='ortho', axis=0), norm='ortho', axis=1), norm='ortho', axis=2)
# run DCT accross variety of images and threshold values
def test_dct(ims, test_thresholds):
res_mean = []
err_mean = []
size_all = []
for val in test_thresholds:
sizes = []
errs = []
for im in ims:
im_red = dct3d(im)
im_comp = im_red * (abs(im_red) > val)
imr = idct3d(im_comp)
errs.append(np.mean((np.linalg.norm(im-imr, axis=2))**2))
sizes.append(300*np.mean(im_comp != 0))
size_all.append(sizes)
res_mean.append(np.mean(sizes))
err_mean.append(np.mean(errs))
return res_mean, err_mean, size_all
test_thresholds = [0.05, 0.1, 0.175, 0.25, 0.5, 0.75]
size_dct, err_dct, size_all = test_dct(X, test_thresholds)
# Plot relevant metrics of size and error accross threshold values
plt.scatter(test_thresholds, size_dct)
plt.plot(test_thresholds, size_dct)
plt.title('Test Threshold vs. Size of Compression')
plt.xlabel('Threshold Value')
plt.ylabel('% Size of Original Image')
plt.show()
plt.scatter(test_thresholds, err_dct)
plt.plot(test_thresholds, err_dct)
plt.title('Test Threshold vs. MSE')
plt.xlabel('Threshold Value')
plt.ylabel('Image MSE')
plt.show()
# Plot distribution of image sizes accross threshold values
fig, ax = plt.subplots(3, 2, figsize=(10, 15))
for i in range(6):
ax[i // 2][i % 2].hist(size_all[i])
ax[i // 2][i % 2].set_title(f'% Size of Original Image\nThreshold: {test_thresholds[i]} | Average Size: {round(np.mean(size_all[i]), 2)}%')
ax[i // 2][i % 2].set_xlabel('% Size of Original Image')
ax[i // 2][i % 2].set_ylabel('Frequency')
fig.tight_layout(pad=3)
plt.show()
# Plot DCT for sample of images accross threshold values
fig, ax = plt.subplots(len(test_thresholds) + 1, 5, figsize=(15, 21))
for i in range(5):
im_red = dct3d(X[i])
for j, val in enumerate(test_thresholds):
if j == 0:
ax[j][i].imshow(X[i])
ax[j][i].axis('off')
ax[j][i].set_title(f'Image {i}')
im_comp = im_red * (abs(im_red) > val)
imr = idct3d(im_red * (abs(im_red) > val))
ax[j+1][i].imshow(imr)
ax[j+1][i].axis('off')
ax[j+1][i].set_title(f'Image {i}, threshold: {val}\n{ round(100*(1 - np.mean(im_comp == 0)) * 3,4)}% Of Image Size')
fig.tight_layout(pad=3)
print("DCT:", err_dct[::-1])
print("SVD:", err_svd)