【问题标题】:Change image pixel colors in R and save image在 R 中更改图像像素颜色并保存图像
【发布时间】:2020-05-08 16:42:10
【问题描述】:

我有数百个小(300x300 像素)纯黑白 PNG 图像。我想将它们转换为 R 中不同的两种颜色并将它们再次保存为 PNG。 (首先,我想实际反转它们:全黑到白,全白到黑 - 但后来我需要其他颜色,例如黑色到红色和白色到绿色等)这看起来很简单,但无论我尝试什么,我都会运行遇到问题。

例如,最简单的解决方案似乎是在基础 R 中使用 as.rasterpng 包(至少用于阅读):

img = readPNG(newfile) # read black (background) and white (figure) image
img <- as.raster(img) 
img_white = img
img_white[img_white == "#000000"] <- 'red' # temporarily convert back to red as placeholder
img_white[img_white == "#FFFFFF"] <- '#000000' # convert white to black
img_white[img_white == "red"] <- '#FFFFFF' # convert originally black to white

(顺便说一下,我需要一个占位符,因为目标颜色与其他原色相同 - 但那不是重点。)

所以这很好用,我可以用plot(img_white) 绘制它,但令人难以置信的是,我找不到自动将图像保存为文件的方法。我试过了,例如writePNGwriteRasterwriteGDAL,但由于类错误或格式错误或类似原因,它们都会给出各种错误消息。 (我也尝试了各种转换都没有成功。)

除其他外,我还尝试了imager 包,它在处理图像后很好地保存了图像,但我找不到在整个图像中转换单个指定颜色的方法。

总而言之,我愿意接受任何可能的解决方案,只要它提供完整的工作代码即可。我不太关心我需要使用什么包,但如果可能的话,我更喜欢尽可能简单的代码,因此尽可能少的包。


解决方案:

根据 Allan Cameron 的回答,我写了这个函数:

change_cols = function(replace_black, replace_white, theimg) {
    r_b = col2rgb(replace_black) / 255
    r_w = col2rgb(replace_white) / 255
    theimg[theimg == 1] <- 2
    for (i in 1:3) {
        theimg[,,i][theimg[,,i] == 0] <- r_b[i]
    }
    for (i in 1:3) {
        theimg[,,i][theimg[,,i] == 2] <- r_w[i]
    }
    return(theimg)
}

那么就这么简单:

img = readPNG(newfile)
newimg = change_cols("#FF0000", "#00FF00", img)
writePNG(newimg, "fileout.png")

(另请参阅 Allan Cameron 的转换 raster 对象的函数。)

【问题讨论】:

  • writePNG 的错误信息是什么?也许问题是使用'red',你不能存储另一个虚拟颜色,它是真实颜色而不是字符串?
  • 不,'red' 确实有效,它变成了红色。无论如何,可以肯定的是,我现在尝试使用 '#FF0000',但它仍然给出与往常一样的错误:Error in writePNG(img_white, sub("_bw.", "_wb.", f_name, fixed = TRUE)) : image must be a matrix or array of raw or real numbers
  • 可能问题是转换为光栅对象,也许这会有所帮助:gis.stackexchange.com/questions/207477/…
  • 不,我也已经尝试过了:( ...数据结构非常不同,因此主要答案不起作用,并且 writeGDAL(建议在评论中)给出格式错误。

标签: r image-processing colors save png


【解决方案1】:

您需要将 PNG 编写为数值数组,就像加载它时一样。由于您只有黑白图像,因此手动交换黑白图像应该不是问题(它们的值黑色 = 0,白色 = 1)。

您只需将其转换为栅格即可进行绘图:

library(png)
newfile = "~/face.png"
img = readPNG(newfile) # read black (background) and white (figure) image
img_white = 1-img

现在

plot(raster::as.raster(img))

plot(raster::as.raster(img_white))

或者如果您想反转单个通道(在本例中为红色):

img[,,1] <- 1 - img[,,1]
plot(raster::as.raster(img))


编辑

在 OP 进一步 cmets 之后,我认为通过编写一个接受光栅对象并将其保存为 PNG 文件的函数来得出这个答案是合理的:

save_raster_as_PNG <- function(raster_object, path) 
{
  if(class(raster_object) != "raster") stop("This is not a raster object.")
  dims        <- dim(raster_object)
  red         <- as.numeric(paste0("0x", substr(raster_object, 2 , 3)))/255
  dim(red)    <- rev(dims)
  green       <- as.numeric(paste0("0x", substr(raster_object, 4 , 5)))/255
  dim(green)  <- rev(dims)
  blue        <- as.numeric(paste0("0x", substr(raster_object, 6 , 7)))/255
  dim(blue)   <- rev(dims)
  result      <- numeric(3 * dims[1] * dims[2])
  dim(result) <- c(dims, 3)
  result[,,1] <- t(red)
  result[,,2] <- t(blue)
  result[,,3] <- t(green)

  tryCatch(png::writePNG(result, path), error = function(e) stop(e))
  cat("Raster successfully saved to", path.expand(path))
}

img <- raster::as.raster(img)
save_raster_as_PNG(img, "~/face3.png")
# Raster successfully saved to C:/Users/AllanCameron/SO/R/face3.png

【讨论】:

  • 啊哇,这确实有效,非常感谢!但这只会改变“颜色强度”,如果我理解正确的话,所以只适用于黑色/白色/灰度。我将如何更改为其他颜色,例如红色还是绿色(最好是 HEX)?
  • 如果您查看dim(img),您应该会看到有三个数字。一个 x 值(像素数的宽度)、y 值(像素数的高度)和数字 3。最后一个数字告诉我们该数组实际上是 3 个数组的堆栈:一个用于红色强度,一个用于蓝色强度和绿色强度之一。我的答案有效,因为在黑白图像中,红色值 == 蓝色值 == 绿色值。
  • 哦,我明白了。实际上,您的答案并不完全是我想要的,但它使事情变得非常清楚。 (精确的解决方案将考虑到正在更改的原始颜色,例如img[,,3][img[,,3] == 0] &lt;- 0.5,因此过滤== 0 以仅选择黑色,或者过滤==1 以仅选择白色。)
  • @gaspar 我将在我的答案中添加一个函数,允许您将栅格另存为 PNG。
  • 啊我已经写了我自己的函数了!但这也很酷!我会把我的添加到问题中
猜你喜欢
  • 1970-01-01
  • 2015-07-31
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多