如何在 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))
  }
}