【问题标题】:Processing multiple images with Magick (in R) with transformations使用带有转换的 Magick(在 R 中)处理多个图像
【发布时间】:2019-10-20 13:05:58
【问题描述】:

我需要自动化一些图像转换来执行以下操作: - 阅读 16,000 多张又短又宽的图像,大小不一样。 - 将每个图像重新缩放到 90 像素高 - 在图像的宽度上裁剪 90 像素,因此在 1 个图像上裁剪多个 90x90 - 然后为下一个图像重新做一遍 - 每张90x90的图片需要依次保存为file-name_1.png、file-name_2.png等

我已经完成了对 8 张图片的测试,并且使用了 magick 包,我能够手动重新缩放并从每张图片中创建多个裁剪。问题是当我尝试做多个时,我可以轻松地调整图像的大小,但是在保存它们时就会出现问题。

# capture images, file paths in a list
img_list <- list.files("./orig_images", pattern = "\\.png$", full.names = TRUE)

# get all images in a list
all_images <- lapply(img_list, image_read)

# scale each image height - THIS DOESN'T WORK, GET NULL VALUE
scale_images <- 
  for (i in 1:length(all_images)) {
  scale_images(all_images[[i]], "x90")
    }

# all images added into one
all_images_joined <- image_join(all_images)

# scale images - THIS WORKS to scale, but problems later
all_images_scaled <- 
  image_scale(all_images_joined, "x90")

# Test whether a single file will be written or multiple files; 
# only writes one file (even if I 
for (i in 1:length(all_images_scaled)) {
  image_write(all_images_scaled[[i]], path = "filepath/new_cropimages/filename")
}

理想情况下,我会使用 for 循环缩放图像。这样我就可以将缩放的图像保存到目录中。这不起作用-我没有收到错误,但是当我检查变量的内容时,它为空。 image_join 函数将它们放在一起并将高度缩放为 90(宽度也按比例缩放),但我无法将单独的图像写入目录。此外,下一个部分是沿宽度裁剪每个图像并保存新图像 file-name_1.png,以此类推,每个图像 90x90,移动超过 90 像素,裁剪 90x90,等等。我选择魔法是因为它很容易单独缩放和裁剪,但我对其他想法持开放态度(或学习如何使该包工作)。感谢您的帮助。

这里有一些图片:

[Original Image, untransformed][1]
[Manual 90x90 crop][2]
[Another manual 90x90 crop, farther down the same image][3]


  [1]: https://i.stack.imgur.com/8ptXv.png
  [2]: https://i.stack.imgur.com/SF9pG.png
  [3]: https://i.stack.imgur.com/NyKxS.png

【问题讨论】:

  • 我认为图表会很有帮助...显示几个不同大小的输入图像以及输出图像会产生什么结果。另外,您使用的是什么操作系统?
  • 感谢您的建议!我添加了一些希望能有所帮助的图片。
  • 那么,当您将图像大小调整为 90 px 高并且它以 110 px 宽出现时会发生什么?你会得到一张 90x90 的图像和一张 20x90 的图像?您使用的是什么操作系统?
  • 所以在 16000 个句子(图像)中,我遇到的最小的是 90 x 680 (将高度缩放到 90 像素后)。最后一张小于 90x90 的图像,我可能会丢弃,因为我会有很多其他图像,它可能会被淘汰。或者我可能会尝试一些方法来找到那些不是 90 像素宽的图像并进行某种操作以使它们成为正方形。我不确定如何处理它们。我在 R(和 Rstudio)中工作,但如果有帮助,它会安装在 Mac 上。
  • 我的回答或其他人是否解决了您的问题?如果是这样,请考虑接受它作为您的答案 - 通过单击计票旁边的空心对勾/复选标记。如果没有,请说出什么不起作用,以便我或其他人可以进一步帮助您。谢谢。 meta.stackexchange.com/questions/5234/…

标签: r image-processing magick-r-package


【解决方案1】:

我不会说 R,但我希望能够在 ImageMagick 方面提供帮助并处理 16,000 张图像。

就像您在 Mac 上一样,您可以使用 homebrew 非常轻松地安装 2 个非常有用的软件包,使用:

brew install imagemagick
brew install parallel

所以,你的原始句子图像是 1850x105 像素,你可以在终端中看到这样的:

magick identify sentence.png
sentence.png PNG 1850x105 1850x105+0+0 8-bit Gray 256c 51626B 0.000u 0:00.000

如果你将高度调整为 90px,让宽度按比例跟随,它将变为 1586x90px:

magick sentence.png -resize x90 info:
sentence.png PNG 1586x90 1586x90+0+0 8-bit Gray 51626B 0.060u 0:00.006

所以,如果你调整大小然后裁剪成 90px 宽的块:

magick sentence.png -resize x90 -crop 90x chunk-%03d.png

你会得到 18 个块,除了最后一个,每个块宽 90 px,如下所示:

-rw-r--r--  1 mark  staff  5648  6 Jun 08:07 chunk-000.png
-rw-r--r--  1 mark  staff  5319  6 Jun 08:07 chunk-001.png
-rw-r--r--  1 mark  staff  5870  6 Jun 08:07 chunk-002.png
-rw-r--r--  1 mark  staff  6164  6 Jun 08:07 chunk-003.png
-rw-r--r--  1 mark  staff  5001  6 Jun 08:07 chunk-004.png
-rw-r--r--  1 mark  staff  6420  6 Jun 08:07 chunk-005.png
-rw-r--r--  1 mark  staff  4726  6 Jun 08:07 chunk-006.png
-rw-r--r--  1 mark  staff  5559  6 Jun 08:07 chunk-007.png
-rw-r--r--  1 mark  staff  5053  6 Jun 08:07 chunk-008.png
-rw-r--r--  1 mark  staff  4413  6 Jun 08:07 chunk-009.png
-rw-r--r--  1 mark  staff  5960  6 Jun 08:07 chunk-010.png
-rw-r--r--  1 mark  staff  5392  6 Jun 08:07 chunk-011.png
-rw-r--r--  1 mark  staff  4280  6 Jun 08:07 chunk-012.png
-rw-r--r--  1 mark  staff  5681  6 Jun 08:07 chunk-013.png
-rw-r--r--  1 mark  staff  5395  6 Jun 08:07 chunk-014.png
-rw-r--r--  1 mark  staff  5065  6 Jun 08:07 chunk-015.png
-rw-r--r--  1 mark  staff  6322  6 Jun 08:07 chunk-016.png
-rw-r--r--  1 mark  staff  4848  6 Jun 08:07 chunk-017.png

现在,如果您有 16,000 个句子要处理,您可以使用 GNU Parallel 将它们全部并行完成,并为所有文件获取合理的名称。让我们先进行一次试运行,这样它实际上什么都不做,只是向您展示它会做什么:

parallel --dry-run magick {} -resize x90 -crop 90x {.}-%03d.png ::: sentence*

样本输出

magick sentence1.png -resize x90 -crop 90x sentence1-%03d.png 
magick sentence2.png -resize x90 -crop 90x sentence2-%03d.png
magick sentence3.png -resize x90 -crop 90x sentence3-%03d.png

看起来不错,所以删除 --dry-run 并再次执行此操作,您将获得以下三个(相同副本)的输出:

-rw-r--r--  1 mark  staff  5648  6 Jun 08:13 sentence1-000.png
-rw-r--r--  1 mark  staff  5319  6 Jun 08:13 sentence1-001.png
-rw-r--r--  1 mark  staff  5870  6 Jun 08:13 sentence1-002.png
-rw-r--r--  1 mark  staff  6164  6 Jun 08:13 sentence1-003.png
-rw-r--r--  1 mark  staff  5001  6 Jun 08:13 sentence1-004.png
-rw-r--r--  1 mark  staff  6420  6 Jun 08:13 sentence1-005.png
-rw-r--r--  1 mark  staff  4726  6 Jun 08:13 sentence1-006.png
-rw-r--r--  1 mark  staff  5559  6 Jun 08:13 sentence1-007.png
-rw-r--r--  1 mark  staff  5053  6 Jun 08:13 sentence1-008.png
-rw-r--r--  1 mark  staff  4413  6 Jun 08:13 sentence1-009.png
-rw-r--r--  1 mark  staff  5960  6 Jun 08:13 sentence1-010.png
-rw-r--r--  1 mark  staff  5392  6 Jun 08:13 sentence1-011.png
-rw-r--r--  1 mark  staff  4280  6 Jun 08:13 sentence1-012.png
-rw-r--r--  1 mark  staff  5681  6 Jun 08:13 sentence1-013.png
-rw-r--r--  1 mark  staff  5395  6 Jun 08:13 sentence1-014.png
-rw-r--r--  1 mark  staff  5065  6 Jun 08:13 sentence1-015.png
-rw-r--r--  1 mark  staff  6322  6 Jun 08:13 sentence1-016.png
-rw-r--r--  1 mark  staff  4848  6 Jun 08:13 sentence1-017.png
-rw-r--r--  1 mark  staff  5648  6 Jun 08:13 sentence2-000.png
-rw-r--r--  1 mark  staff  5319  6 Jun 08:13 sentence2-001.png
-rw-r--r--  1 mark  staff  5870  6 Jun 08:13 sentence2-002.png
-rw-r--r--  1 mark  staff  6164  6 Jun 08:13 sentence2-003.png
-rw-r--r--  1 mark  staff  5001  6 Jun 08:13 sentence2-004.png
-rw-r--r--  1 mark  staff  6420  6 Jun 08:13 sentence2-005.png
-rw-r--r--  1 mark  staff  4726  6 Jun 08:13 sentence2-006.png
-rw-r--r--  1 mark  staff  5559  6 Jun 08:13 sentence2-007.png
-rw-r--r--  1 mark  staff  5053  6 Jun 08:13 sentence2-008.png
-rw-r--r--  1 mark  staff  4413  6 Jun 08:13 sentence2-009.png
-rw-r--r--  1 mark  staff  5960  6 Jun 08:13 sentence2-010.png
-rw-r--r--  1 mark  staff  5392  6 Jun 08:13 sentence2-011.png
-rw-r--r--  1 mark  staff  4280  6 Jun 08:13 sentence2-012.png
-rw-r--r--  1 mark  staff  5681  6 Jun 08:13 sentence2-013.png
-rw-r--r--  1 mark  staff  5395  6 Jun 08:13 sentence2-014.png
-rw-r--r--  1 mark  staff  5065  6 Jun 08:13 sentence2-015.png
-rw-r--r--  1 mark  staff  6322  6 Jun 08:13 sentence2-016.png
-rw-r--r--  1 mark  staff  4848  6 Jun 08:13 sentence2-017.png
-rw-r--r--  1 mark  staff  5648  6 Jun 08:13 sentence3-000.png
-rw-r--r--  1 mark  staff  5319  6 Jun 08:13 sentence3-001.png
-rw-r--r--  1 mark  staff  5870  6 Jun 08:13 sentence3-002.png
-rw-r--r--  1 mark  staff  6164  6 Jun 08:13 sentence3-003.png
-rw-r--r--  1 mark  staff  5001  6 Jun 08:13 sentence3-004.png
-rw-r--r--  1 mark  staff  6420  6 Jun 08:13 sentence3-005.png
-rw-r--r--  1 mark  staff  4726  6 Jun 08:13 sentence3-006.png
-rw-r--r--  1 mark  staff  5559  6 Jun 08:13 sentence3-007.png
-rw-r--r--  1 mark  staff  5053  6 Jun 08:13 sentence3-008.png
-rw-r--r--  1 mark  staff  4413  6 Jun 08:13 sentence3-009.png
-rw-r--r--  1 mark  staff  5960  6 Jun 08:13 sentence3-010.png
-rw-r--r--  1 mark  staff  5392  6 Jun 08:13 sentence3-011.png
-rw-r--r--  1 mark  staff  4280  6 Jun 08:13 sentence3-012.png
-rw-r--r--  1 mark  staff  5681  6 Jun 08:13 sentence3-013.png
-rw-r--r--  1 mark  staff  5395  6 Jun 08:13 sentence3-014.png
-rw-r--r--  1 mark  staff  5065  6 Jun 08:13 sentence3-015.png
-rw-r--r--  1 mark  staff  6322  6 Jun 08:13 sentence3-016.png
-rw-r--r--  1 mark  staff  4848  6 Jun 08:13 sentence3-017.png

parallel的参数解释一下:

  • {}“当前文件”
  • {.} 指的是“没有扩展名的当前文件”
  • ::: 将用于 parallel 的参数与用于您的 magick 命令的参数分开

注意一点,PNG 图像可以“记住”它们的来源,这可能很有用,也可能很烦人。如果您从上方查看最后一个块,您会看到它是 56x90,但在此之后,它“记住”它来自偏移 1530,0 的 1586x90 画布:

identify sentence3-017.png 
sentence3-017.png PNG 56x90 1586x90+1530+0 8-bit Gray 256c 4848B 0.000u 0:00.000

这有时会扰乱令人讨厌的后续处理,或者有时在重新组装已切碎的图像时非常有用!如果要删除,需要重新分页,所以上面的命令就变成了:

magick input.png -resize x90 -crop 90x +repage output.png 

【讨论】:

  • 哇,感谢您提供了这个惊人而全面的答案!我真的很感激,今晚我会首先测试它——我一直在努力实现自动化,但只是找到了答案的一部分。
  • Mark 的回答非常棒,我倾向于用 ImageMagick 解决这个问题。但是,既然您要求提供 R 解决方案,那么这里也有一个!
【解决方案2】:

更新 - 更好地利用 EBImage 中的工具

ImageMagick 是一个很好的方法。但是如果你想对图像进行一些内容分析,这里有一个 R 的解决方案。R 确实提供了一些非常方便的工具。此外,图像“什么都不是”,只是矩阵,R 处理得非常好。通过将图像简化为矩阵,EBImage 包可以很好地做到这一点,并且无论好坏,它都会删除每个图像的一些元数据。这是EBImage 的 R 解决方案。不过,Mark 的解决方案可能更适合真正的大批量生产。

解决方案是围绕一个大的“for”循环构建的。在几个步骤中添加错误检查将是谨慎的。该代码利用EBImage 来管理彩色和灰度图像。

在这里,通过添加所需背景颜色的像素,最终图像在扩展图像中居中。然后将扩展图像裁剪成图块。如果需要,可以调整确定pad 值的逻辑以简单地裁剪图像或左对齐或右对齐。

首先假设您从工作目录开始,源文件位于./source,目标位于./dest。它还为每个“平铺”图像创建一个新目录。可以将其更改为让单个目录接收所有图像以及其他保护性编码。在这里,图像被假定为具有适当扩展名的 PNG 文件。应用于高度和宽度的所需图块大小 (90) 存储在变量 size 中。

# EBImage needs to be available
  if (!require(EBImage)) {
    source("https://bioconductor.org/biocLite.R")
    biocLite("EBImage")
    library(EBImage)
  }

# From the working directory, select image files
  size <- 90
  bg.col <- "transparent" # or any other color specification for R
  ff <- list.files("source", full = TRUE,
    pattern = "png$", ignore.case = TRUE)

# Walk through all files with a 'for' loop, 
  for (f in ff) {
    # Extract base name, even names like "foo.bar.1.png" 
      txt <- unlist(strsplit(basename(f), ".", fixed = TRUE))
      len <- length(txt)
      base <- ifelse(len == 1, txt[1], paste(txt[-len], collapse = "."))

    # Read one image and resize
      img <- readImage(f)
      img <- resize(img, h = size) # options allow for antialiasing

    # Determine number tiles and padding needed
      nx <- ceiling(dim(img)[1]/size)
      newdm <- c(nx * size, size) # extend final image
      pad <- newdm[1] - dim(img)[1] # pixels needed to extend 

    # Translate the image with given background fille
      img <- translate(img, c(pad%/%2, 0), output.dim = newdm, bg.col = bg.col)

    # Split image into appropriate sized tiles with 'untile'
      img <- untile(img, c(nx, 1), lwd = 0) # see the help file

    # Create a new directory for each image
      dpath <- file.path("dest", trimws(base)) # Windows doesn't like " "
      if (!dir.create(dpath))
        stop("unable to create directory: ", dpath)
      
    # Create new image file names for each frame
      fn <- sprintf("%s_%03d.png", base, seq_len(nx))
      fpaths <- file.path(dpath, fn)

    # Save individual tiles (as PNG) and names of saved files
      saved <- mapply(writeImage, x = getFrames(img, type = "render"), 
        files = fpaths)

    # Check on the results from 'mapply'
      print(saved)
  }

【讨论】:

  • 谢谢,非常感谢!我很高兴有两种不同的、描述良好的方法来做到这一点。我不知道如何使用 R magick 包做到这一点,这让我发疯了。
  • 不客气!我有时会从命令行使用 ImageMagick,尤其喜欢它用于动画。我很高兴看到 Jeroen Ooms 将它移植到 R (magick),但发现坚持使用命令行更容易。我已经用更好地使用EBImage 中的本机工具替换了我的kludgy 代码。我期待着看看它是否适合你!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 2019-10-15
  • 2020-01-14
  • 1970-01-01
  • 2014-02-23
  • 2019-10-28
  • 2017-09-23
相关资源
最近更新 更多