SVD Image Compression
Purpose
Use SVD to perform image compression.
> library(grid) > library(RColorBrewer) > vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y) > color.data <- matrix(data = 0, nrow = 15, ncol = 40) |
Draw HELLO
> grid.newpage() > pushViewport(viewport(layout = grid.layout(15, 40))) > for (i in 1:15) { + for (j in 1:40) { + grid.rect(gp = gpar(fill = "black"), vp = vplayout(i, + j)) + } + } > H <- rbind(cbind(2:9, 2), cbind(2:9, 3), cbind(2:9, 6), cbind(2:9, + 7), cbind(5, 2:7), cbind(6, 2:7)) > for (i in 1:dim(H)[1]) { + grid.rect(gp = gpar(fill = "white"), vp = vplayout(H[i, 1], + H[i, 2])) + color.data[H[i, 1], H[i, 2]] <- 1 + } > E <- rbind(cbind(3, 10:15), cbind(4, 10:15), cbind(6, 10:15), + cbind(7, 10:15), cbind(9, 10:15), cbind(10, 10:15), cbind(3:10, + 10), cbind(3:10, 11)) > for (i in 1:dim(E)[1]) { + grid.rect(gp = gpar(fill = "white"), vp = vplayout(E[i, 1], + E[i, 2])) + color.data[E[i, 1], E[i, 2]] <- 1 + } > L <- rbind(cbind(10, 18:23), cbind(11, 18:23), cbind(4:11, 18), + cbind(4:11, 19)) > for (i in 1:dim(L)[1]) { + grid.rect(gp = gpar(fill = "white"), vp = vplayout(L[i, 1], + L[i, 2])) + color.data[L[i, 1], L[i, 2]] <- 1 + } > L <- rbind(cbind(11, 26:31), cbind(12, 26:31), cbind(5:12, 26), + cbind(5:12, 27)) > for (i in 1:dim(L)[1]) { + grid.rect(gp = gpar(fill = "white"), vp = vplayout(L[i, 1], + L[i, 2])) + color.data[L[i, 1], L[i, 2]] <- 1 + } > O <- rbind(cbind(6, 34:39), cbind(7, 34:39), cbind(12, 34:39), + cbind(13, 34:39), cbind(6:13, 34), cbind(6:13, 35), cbind(6:13, + 38), cbind(6:13, 39)) > for (i in 1:dim(O)[1]) { + grid.rect(gp = gpar(fill = "white"), vp = vplayout(O[i, 1], + O[i, 2])) + color.data[O[i, 1], O[i, 2]] <- 1 + } |
Lets do SVD
> a.svd <- svd(color.data) |
Function to draw image
> draw.image <- function(factors, A1, a.svd) { + A1 <- a.svd$d[1] * a.svd$u[, 1] %*% t(a.svd$v[, 1]) + if (factors > 1) { + for (fac in 2:factors) { + A1 <- A1 + a.svd$d[fac] * a.svd$u[, fac] %*% t(a.svd$v[, + fac]) + } + } + for (i in 1:15) { + for (j in 1:40) { + if (A1[i, j] < 10^(-9)) + A1[i, j] <- 0 + A1[i, j] <- A1[i, j] + 10^(-12) + } + } + grid.newpage() + pushViewport(viewport(layout = grid.layout(15, 40))) + for (i in 1:15) { + for (j in 1:40) { + if (A1[i, j] > 0 & A1[i, j] < 1) { + grid.rect(gp = gpar(fill = grey(A1[i, j])), vp = vplayout(i, + j)) + } + if (A1[i, j] > 1) { + grid.rect(gp = gpar(fill = "white"), vp = vplayout(i, + j)) + } + } + } + } |
Store 15 + 40 numbers instead of 600
> factors <- 1 > draw.image(factors, A1, a.svd) |
Store 2(15 + 40) numbers instead of 600
> factors <- 2 > draw.image(factors, A1, a.svd) |
Store 3(15 + 40) numbers instead of 600
> factors <- 3 > draw.image(factors, A1, a.svd) |
Store 4(15 + 40) numbers instead of 600
> factors <- 4 > draw.image(factors, A1, a.svd) |
Store 5(15 + 40) numbers instead of 600
> factors <- 5 > draw.image(factors, A1, a.svd) |
Store 6(15 + 40) numbers instead of 600
> factors <- 6 > draw.image(factors, A1, a.svd) |
Store 7(15 + 40) numbers instead of 600
> factors <- 7 > draw.image(factors, A1, a.svd) |
Store 8(15 + 40) numbers instead of 600
> factors <- 8 > draw.image(factors, A1, a.svd) |
Store 9(15 + 40) numbers instead of 600
> factors <- 9 > draw.image(factors, A1, a.svd) |
Store 10(15 + 40) numbers instead of 600
> factors <- 10 > draw.image(factors, A1, a.svd) |
Learnings
- Pivot is about 10 and hence 10 rank 1 matrices reproduce the graph entirely 2.As you add more rank 1 matrices the clarity of the picture improves
- Instead of storing 600 numbers, you can just store 15+40 times number of rank 1 matrices