使用Magick(R)处理变换处理多个图像

时间:2019-06-05 01:59:21

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

我需要自动执行一些图像转换以执行以下操作: -读取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循环缩放图像。这样,我可以将缩放后的图像保存到目录中。这没有用-我没有收到错误,但是当我检查变量的内容时,它为null。 image_join函数将它们放在一起并将高度缩放到90(宽度也按比例缩放),但是我无法将单独的图像写入目录。另外,下一块是在整个宽度上裁剪每个图像,并保存新图像文件名_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

2 个答案:

答案 0 :(得分: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

因此,如果您调整大小然后裁剪成90像素宽的块:

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

您将获得18个块,除了最后一个块外,每个块宽90像素,如下所示:

-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,但是在那之后,它“记住” 来自画布1586x90,偏移量为1530,0:

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 

答案 1 :(得分:1)

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

ImageMagick是一种很好的方法。但是,如果您想对图像执行一些内容分析,这是R的解决方案。R确实提供了一些非常方便的工具。同样,图像“什么也没有”,只是矩阵,R处理得很好。通过将图像简化为矩阵,包EBImage可以很好地做到这一点,无论好坏,包EBImage都会删除每个图像的某些元数据。这是EBImage的R解决方案。再说一次,Mark的解决方案对于真正的大批量生产可能会更好。

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

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

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

{{1}}