更改 R 中的图像像素颜色并保存图像

Change image pixel colors in R and save image

我有数百张小型(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,但由于错误的 class 或错误的格式或类似原因,它们都会给出各种错误消息。 (我也尝试过各种转换都没有成功。)

除此之外,我还尝试了 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 对象的函数。)

您需要将 PNG 写为数值数组,就像加载它时一样。由于您只有黑白图像,因此手动交换黑白应该不成问题(它们的值 black = 0,white = 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 的进一步评论之后,我认为通过编写一个接受光栅对象并将其保存为 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