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