代码之家  ›  专栏  ›  技术社区  ›  Savvy

如何在R中无损裁剪jpeg

  •  1
  • Savvy  · 技术社区  · 8 年前

    我是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-600kb之间,但调整大小后的最终大小在1.8到2Mb之间。在我的特例中,图像大小为3100x2329或3099x2329两种。因此,我的大小调整涉及删除额外的像素列,以使所有图像都为3099x232.9。我对文件的文件大小有所下降感到满意,因为我预计一些信息会丢失;但在我的例子中,文件大小增加了三倍多。 或者,我考虑将图像转换为矩阵(EBImage支持)并删除多余的行。但我这里有两个问题,一个是我不知道怎么做,另一个是即使我找到了一种方法,我担心如果我需要将其转换回图像,我可能会丢失一些信息。 我愿意改进这种方法,或者完全不同的方法。我唯一的要求是,我需要能够在R中调整图像的大小,而不添加或丢失任何信息(除了要删除的像素中的信息)

    1 回复  |  直到 8 年前
        1
  •  3
  •   aoles    8 年前

    要执行无损JPEG裁剪,可以使用 jpegtran格式 ,作为 IJG library 例如,以下命令从768x512图像中删除最后一列像素:

    jpegtran -crop 767x512+0+0 -optimize image.jpg >image.jpg
    

    这个 -crop 开关指定矩形分区 WxH+X+Y -optimize 是一种通过优化哈夫曼表来减少文件大小而不损失质量的选项。有关交换机的完整列表,请参见 jpegtran -help .

    一旦 jpegtran格式 安装在您的系统上,可以通过从R调用 system() 。以下示例首先获取一个示例图像,并将其保存为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中。但您也可以使用另一个命令行工具 识别 作为 图像Magick 套件检索图像尺寸,如下所示。

    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))
      }
    }