假设我们有一个灰度图像(128×128,即128×128像素)。我们可以使用矩阵来表示这个图像。如果我们有彩色图像,用R中的readJEPG函数读取图片就可以发现它是由一个三维数组构成(我们常说的三原色:Red, Green, Blue )它有三个矩阵,大小与图像相同, 每个矩阵表示包括RGB色标的颜色值,每个像素由0-255的整数表示。接下来,我们可以通过SVD分解矩阵,再通过消除小的奇异值,我们可以近似矩阵,选择k的值进行矩阵近似,也就是压缩原有矩阵,得到一个保留了原始矩阵大多数信息的压缩矩阵。注意:绘制奇异值图像可能有助于确定重要性显着下降的位置
假设我们选择了k的值,k = 我们希望保留的奇异值的数量,我们可以通过扩展A来生成新的图像矩阵一个使用SVD(第一个k,仅限奇异值)。如果要使用彩色图像,请分别对R,G,B矩阵进行重新组装。
如果你想要得到一个基于原有的彩色图片的灰度图片的话,可以采用: N e w . i m g = 0.299 ∗ r + 0.587 ∗ g + 0.114 ∗ b New.img = 0.299 * r + 0.587 * g + 0.114 * b New.img=0.299∗r+0.587∗g+0.114∗b的公式处理。
如果对SVD(奇异值分解)不了解的话,可以参考我另外一篇有关SVD原理的方面的文章:SVD及PCA的详细原理以及联系
library(RSpectra)
library(jpeg)
library(animation)
##灰度图片生成
png("new_pic%03d.png")
r <- 0.299
g <- 0.587
b <- 0.114
pic <- readJPEG(sprintf("sam_%03d.jpg", i))
R <- pic[,,1]
G <- pic[,,2]
B <- pic[,,3]
#通过灰度进行图像转化
new_pic <- r*R + g*G + b*B
#将转化后的灰度图导出为.jpg
writeJPEG(new_pic, sprintf("new_pic%03d.jpg", i))
dev.off()
##图像压缩
#设置读取路径
setwd("/Users/tyc_219/Desktop/tex")
#读取图片
wyz <- readJPEG("wyz.jpg")
#可以看出图片结构为三维矩阵
str(wyz)
#设置压缩向量
k <- seq(10, 200, 10)
png("Compresspics%03d.png")
compress_jpg <- function(pic, k, plots = TRUE)
{
#如果压缩向量k里面的最小值小于等于1,报错
if(min(k) <= 1) stop("The minimum of the vector must larger than 1!")
#svds()函数在给定的mxn矩阵A的前提下,可以找到其最大的k奇异值和相应的奇异向量
svd_message <- function(jpg, i)
{
r <- svds(jpg[,,1], i)
g <- svds(jpg[,,2], i)
b <- svds(jpg[,,3], i)
return(list(r = r, g = g, b = b))
}
pic <- svd_message(pic, 200)
if(plots == TRUE){
sigma <- pic$r$d
plot(1:length(sigma), sigma, xlab="i-th sigma", ylab="sigma", main="Singular Values")
plot(1:length(sigma), cumsum(sigma)/sum(sigma), main="Cumulative Percent of Total Sigmas")
}
#返回在不同取值下的压缩后图片,取值越小图片约模糊
for(m in k)
{
r <- pic$r$u[, 1:m] %*% diag(pic$r$d[1:m]) %*% t(pic$r$v[,1:m])
g <- pic$g$u[, 1:m] %*% diag(pic$g$d[1:m]) %*% t(pic$g$v[,1:m])
b <- pic$b$u[, 1:m] %*% diag(pic$b$d[1:m]) %*% t(pic$b$v[,1:m])
pics <- array(0, c(nrow(r), ncol(r), 3))
pics[,,1] <- r
pics[,,2] <- g
pics[,,3] <- b
writeJPEG(pics, sprintf("picture_svd_%03d.png", m))
}
}
compress_jpg(wyz, k, plots = TRUE)
dev.off()
#设置生成的压缩图片路径,使用im.convert函数进行GIF图生成
bm.files <- sprintf("picture_svd_%03d.png", k)
im.convert(files = bm.files, output = "Compresspics.gif")
我在这里采用的是吴彦祖的照片:
其灰度图如下:
通过上面的函数可以画出奇异值函数图:
生成的GIF图如下,从GIF图很容易看出取奇异值的个数对压缩后图片清晰度的影响:
本人所学有限,如果有错误的地方还望指正,如需转载,请标明出处,谢谢!