Изменить цвета пикселя изображения в R и сохранить изображение - PullRequest
0 голосов
/ 22 января 2020

У меня есть сотни маленьких (300x300 пикселей) чистых черно-белых изображений PNG. Я хочу преобразовать их в два разных цвета в R и снова сохранить их как PNG. (Во-первых, я хочу на самом деле инвертировать их: все с черного на белый и все с белого на черный - но позже мне понадобятся другие цвета, например, черный на красный и белый на зеленый и т. Д. c.) Это кажется очень простым, но все, что я попробуйте столкнуться с проблемами.

Например, простейшее решение кажется с использованием as.raster в базе R и пакетом png (по крайней мере, для чтения):

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), но невероятно нахожу нет способа автоматического сохранения изображения в файл. Я пробовал, например, writePNG, writeRaster, writeGDAL, но все они выдают различные сообщения об ошибках из-за неправильного класса или неправильного формата или подобного. (Я также безуспешно пробовал различные преобразования.)

Среди прочего я также попробовал пакет imager, который прекрасно сохраняет изображение после манипулирования им, но я не могу найти способ преобразовать один указанный цвет в Целое изображение.

В общем, я открыт для любых возможных решений, если они дают полный рабочий код. Мне все равно, какой пакет мне нужно использовать, хотя, если возможно, я бы предпочел как можно более простой код и, следовательно, как можно меньше пакетов.


РЕШЕНИЕ:

Основываясь на ответе Аллана Кэмерона, я написал эту функцию:

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

(См. Также функцию Аллана Кэмерона, которая преобразует raster объект.)

1 Ответ

1 голос
/ 22 января 2020

Вам нужно записать PNG в виде массива чисел c, как это было при загрузке. Поскольку у вас есть только черно-белые изображения, не должно возникнуть проблем с ручной заменой черно-белых изображений (они имеют значение 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))

enter image description here И

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

enter image description here

Или, если вы хотите инвертировать один канал (в данном случае красный):

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

enter image description here


РЕДАКТИРОВАТЬ

После дальнейших комментариев от ОП я подумал, что было бы разумно принять этот ответ к своему выводу, написав функцию, которая принимает растровый объект и сохраняет его как файл 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
...