Load the Required Packages

library(png)
library(OpenImageR)

Load Image Data into Arrays, Vectorize the Data, and Create a Matrix Where Each Row Represents a Vectorized Image

Since the large dimensions of the shoe images was causing me some memory issues at first, I used a set of smaller (40 x 40) images for this project instead. The images I used are sprites from the Gameboy Color game Pokemon Yellow. Below, I load the image data into arrays, vectorize the RGB data, and create a matrix of the vectorized image data.

img_names <- list.files(pattern = "\\.png$")
img_num <- length(img_names)
img_test <- readPNG(img_names[1])
img_dim <- dim(img_test)
img_h <- img_dim[1]
img_w <- img_dim[2]
img_z <- img_dim[3]

a <- array(rep(0, img_num * img_h * img_w * img_z), dim =
               c(img_num, img_h, img_w, img_z))

for (i in 1:img_num){
    img <- readPNG(img_names[i])
    a[i,,,] <- array(img, dim = c(1, img_h, img_w, img_z))
}

A <- matrix(0, img_num, prod(img_dim))

for (i in 1:img_num){
    img <- readPNG(img_names[i])
    r <- as.vector(img[,,1])
    g <- as.vector(img[,,2])
    b <- as.vector(img[,,3])
    A[i,] <- t(c(r, g, b))
}

pokemon <- as.data.frame(t(A))

Plot the Original Images

Below, I plot the original images from which I will be developing eigenpokemon later.

plot_png <- function(path, add = FALSE){
    img = readPNG(path, native = TRUE)
    res = dim(img)[2:1]
    if (!add){
        plot(1,1,xlim=c(1,res[1]),ylim=c(1,res[2]),asp=1,type='n',xaxs='i',
             yaxs='i',xaxt='n',yaxt='n',xlab='',ylab='',bty='n')
        rasterImage(img,1,1,res[1],res[2])
    }
}

par(mfrow=c(9,5))
par(mai=c(.05,.05,.05,.05))
for (i in 1:img_num){
    plot_png(writePNG(a[i,,,]))
}

Covariance Matrix

Below, I calculate the covariance matrix.

scaled <- scale(pokemon, center = TRUE, scale = TRUE)
mean_pokemon <- attr(scaled, "scaled:center")
std_pokemon  <- attr(scaled, "scaled:scale")
Sigma_ <- cor(scaled)

Eigencomponents

Then I retrieve the eigencomponents from the covariance matrix.

myeigen <- eigen(Sigma_)
b <- cumsum(myeigen$values) / sum(myeigen$values)

Eigenpokemon

The number of principle components needed to capture at least 80% of the variability in the pokemon images in my original data set is 27, so that is the number of eigenimages I plot below.

scaling <- diag(myeigen$values[1:27]^(-1/2)) / (sqrt(nrow(scaled)-1))
eigenpokemon <- scaled %*% myeigen$vectors[,1:27] %*% scaling
par(mfrow=c(2,3))

a_new <- a
dim(a_new) <- c(img_num, img_h * img_w * img_z)
mypca <- princomp(t(as.matrix(a_new)), scores = TRUE, cor = TRUE)

mypca2 <- t(mypca$scores)
dim(mypca2) <- c(img_num, img_h, img_w, img_z)
par(mfrow=c(6,5))
par(mai=c(.05,.05,.05,.05))
for (i in 1:27){
    plot_png(writePNG(mypca2[i,,,]))
}

New Data Set

Now I can finally save the new (much reduced) data set, which only contains the 27 principle components for each image needed to capture 80% of the variability in all the images.

x = t(t(eigenpokemon) %*% scaled)

Resources Used

Here is a list of the resources I used to complete this project:

https://rpubs.com/R-Minator/eigenshoes

https://rpubs.com/dherrero12/543854

https://pyimagesearch.com/2021/05/10/opencv-eigenfaces-for-face-recognition

https://towardsdatascience.com/eigenfaces-recovering-humans-from-ghosts-17606c328184#:~:text=Eigenfaces%20is%20a%20method%20that,reducing%20computation%20and%20space%20complexity.