如何在 R 中无损裁剪 jpeg
How can I losslessly crop a jpeg in R
我是 R 的新手。我有一个文件夹,里面装满了不同尺寸的图像 (RGB)。我的要求是让它们都处于相同的尺寸,这将涉及调整它们的大小。我写了下面的代码来完成这个
#EBImage
library(EBImage)
path = "G:/Images/"
file.names = dir(path,full.names = TRUE, pattern =".jpeg")
reqd_dim = c(3099,2329,3)
sprintf("Number of Image Files is: %d", length(file.names))
for(i in 1:length(file.names)){
correction_flag = FALSE
print("Loop Number:")
flush.console()
print(i)
flush.console()
img = readImage(file.names[i])
# Checking if the dimensions are the same
for (j in 1:length(reqd_dim)) {
if(dim(img)[j]!=reqd_dim[j]){
correction_flag = TRUE
break
}
}
if(correction_flag==TRUE){
print("Correcting dimensions of the image")
flush.console()
writeImage(img[1:3099, 1:2329, 1:3],file.names[i],quality = 100)
}
}
我的问题是,虽然图像最初的大小在 500-600 kb 之间,但调整后的图像最终大小在 1.8 到 2 Mb 之间。在我的特殊情况下,图像有两种尺寸之一 - 3100x2329 或 3099x2329。所以我调整大小涉及删除额外的像素列以使所有图像为 3099x2329。我对文件的文件大小有所下降感到满意,因为我预计会丢失一些信息;但就我而言,文件大小增加了三倍多。
或者,我考虑过将图像转换为矩阵(EBImage 支持)并删除多余的行。但是我这里有两个问题,一个是我不知道该怎么做,两个是即使我找到了一种方法,但如果我需要将其转换回,恐怕我可能会丢失一些信息一个图像。
我愿意改进这种方法,或者完全不同的方法。我唯一的要求是我需要能够在不添加或丢失任何信息的情况下在 R 中调整图像大小(除了要删除的像素中的信息)
要执行无损 JPEG 裁剪,您可以使用 jpegtran,一个作为 IJG library 的一部分分发的外部命令行工具。例如,以下命令从 768x512 图像中删除最后一列像素:
jpegtran -crop 767x512+0+0 -optimize image.jpg >image.jpg
-crop
开关指定矩形子区域 WxH+X+Y
,-optimize
是通过优化 Huffman table 在不损失质量的情况下减小文件大小的选项。有关开关的完整列表,请参阅 jpegtran -help
.
一旦 jpegtran 安装在您的系统上,就可以通过 system()
从 R 调用它。以下示例首先获取样本图像并将其保存为 JPEG。然后裁剪图像,并将像素值与原始图像的值进行比较。
library("EBImage")
# resave a sample image as JPG
f = system.file("images", "sample.png", package="EBImage")
writeImage(readImage(f), "image.jpg", quality=90)
# do the cropping
system("jpegtran -crop 767x512+0+0 -optimize image.jpg >cropped.jpg")
# compare file size
file.size("image.jpg", "cropped.jpg")
## [1] 65880 65005
original = readImage("image.jpg")
dim(original)
## [1] 768 512
cropped = readImage("cropped.jpg")
dim(cropped)
## [1] 767 512
# check whether original values are retained
identical(original[1:767,], cropped)
## TRUE
回到您的特定用例:您的脚本可以通过检查图像尺寸来进一步改进,而无需将整个像素数组实际加载到 R 中。为此,例如,您可以使用 RBioFormats 仅读取将包含图像尺寸的图像元数据导入 R。但您也可以使用另一个命令行工具 identify 作为 ImageMagick 套件的一部分分发来检索图像尺寸,如下图所示。
path = "G:/Images/"
file.names = dir(path, full.names = TRUE, pattern =".jpeg")
reqd_dim = c(3099,2329,3)
cat(sprintf("Number of Image Files is: %d\n", length(file.names)))
for (i in seq_along(file.names)) {
file = file.names[i]
cat(sprintf("Checking dimensions of image number %d: ", i))
flush.console()
cmd = paste('identify -format "c(%w, %h)"', file)
res = eval(parse(text=system(cmd, intern=TRUE)))
# Checking if the dimensions are the same
if ( all(res==reqd_dim) ) {
cat("OK\n")
flush.console()
}
else {
cat("Correcting\n")
flush.console()
system(sprintf("jpegtran -crop %dx%d+0+0 -optimize %s >%s",
reqd_dim[1], reqd_dim[2], file, file))
}
}
我是 R 的新手。我有一个文件夹,里面装满了不同尺寸的图像 (RGB)。我的要求是让它们都处于相同的尺寸,这将涉及调整它们的大小。我写了下面的代码来完成这个
#EBImage
library(EBImage)
path = "G:/Images/"
file.names = dir(path,full.names = TRUE, pattern =".jpeg")
reqd_dim = c(3099,2329,3)
sprintf("Number of Image Files is: %d", length(file.names))
for(i in 1:length(file.names)){
correction_flag = FALSE
print("Loop Number:")
flush.console()
print(i)
flush.console()
img = readImage(file.names[i])
# Checking if the dimensions are the same
for (j in 1:length(reqd_dim)) {
if(dim(img)[j]!=reqd_dim[j]){
correction_flag = TRUE
break
}
}
if(correction_flag==TRUE){
print("Correcting dimensions of the image")
flush.console()
writeImage(img[1:3099, 1:2329, 1:3],file.names[i],quality = 100)
}
}
我的问题是,虽然图像最初的大小在 500-600 kb 之间,但调整后的图像最终大小在 1.8 到 2 Mb 之间。在我的特殊情况下,图像有两种尺寸之一 - 3100x2329 或 3099x2329。所以我调整大小涉及删除额外的像素列以使所有图像为 3099x2329。我对文件的文件大小有所下降感到满意,因为我预计会丢失一些信息;但就我而言,文件大小增加了三倍多。 或者,我考虑过将图像转换为矩阵(EBImage 支持)并删除多余的行。但是我这里有两个问题,一个是我不知道该怎么做,两个是即使我找到了一种方法,但如果我需要将其转换回,恐怕我可能会丢失一些信息一个图像。 我愿意改进这种方法,或者完全不同的方法。我唯一的要求是我需要能够在不添加或丢失任何信息的情况下在 R 中调整图像大小(除了要删除的像素中的信息)
要执行无损 JPEG 裁剪,您可以使用 jpegtran,一个作为 IJG library 的一部分分发的外部命令行工具。例如,以下命令从 768x512 图像中删除最后一列像素:
jpegtran -crop 767x512+0+0 -optimize image.jpg >image.jpg
-crop
开关指定矩形子区域 WxH+X+Y
,-optimize
是通过优化 Huffman table 在不损失质量的情况下减小文件大小的选项。有关开关的完整列表,请参阅 jpegtran -help
.
一旦 jpegtran 安装在您的系统上,就可以通过 system()
从 R 调用它。以下示例首先获取样本图像并将其保存为 JPEG。然后裁剪图像,并将像素值与原始图像的值进行比较。
library("EBImage")
# resave a sample image as JPG
f = system.file("images", "sample.png", package="EBImage")
writeImage(readImage(f), "image.jpg", quality=90)
# do the cropping
system("jpegtran -crop 767x512+0+0 -optimize image.jpg >cropped.jpg")
# compare file size
file.size("image.jpg", "cropped.jpg")
## [1] 65880 65005
original = readImage("image.jpg")
dim(original)
## [1] 768 512
cropped = readImage("cropped.jpg")
dim(cropped)
## [1] 767 512
# check whether original values are retained
identical(original[1:767,], cropped)
## TRUE
回到您的特定用例:您的脚本可以通过检查图像尺寸来进一步改进,而无需将整个像素数组实际加载到 R 中。为此,例如,您可以使用 RBioFormats 仅读取将包含图像尺寸的图像元数据导入 R。但您也可以使用另一个命令行工具 identify 作为 ImageMagick 套件的一部分分发来检索图像尺寸,如下图所示。
path = "G:/Images/"
file.names = dir(path, full.names = TRUE, pattern =".jpeg")
reqd_dim = c(3099,2329,3)
cat(sprintf("Number of Image Files is: %d\n", length(file.names)))
for (i in seq_along(file.names)) {
file = file.names[i]
cat(sprintf("Checking dimensions of image number %d: ", i))
flush.console()
cmd = paste('identify -format "c(%w, %h)"', file)
res = eval(parse(text=system(cmd, intern=TRUE)))
# Checking if the dimensions are the same
if ( all(res==reqd_dim) ) {
cat("OK\n")
flush.console()
}
else {
cat("Correcting\n")
flush.console()
system(sprintf("jpegtran -crop %dx%d+0+0 -optimize %s >%s",
reqd_dim[1], reqd_dim[2], file, file))
}
}