0

I'm trying to create a series of black and white images of visual noise, in which each image is identical to the previous one except for a proportion of random pixels which have swapped colours (black pixels turn white, and white pixels turn black).

I can generate the images individually, but now I want to put the code in a loop so I can generate and save a sequence of 300 images. However, I am having some trouble. There are multiple problems with my loop as I've tried to cobble it together from a combination of other questions and answers on stack overflow, and I don't fully understand what I'm doing (I'm new to programming).

Here's my code:

file_names <- c("VN1", "VN2", "VN3", "VN4", "VN5")
next_image <- c()

for (i in 1:5) {
    im <- if (i == 1) {        
    load.image("C:/Users/Ali/Desktop/VN_images/VN.png")
    } else {
    load.image(next_image)
    }
        df <- as.data.frame(im) %>%
        mutate(colour = case_when(value == 0 ~ "black", TRUE ~ "white")) %>%
        group_by(colour) %>%
        mutate(value = replace(value, sample(row_number(), size = ceiling(0.05 * n()), replace = FALSE), 3))
    df$value[df$value == 3 & df$colour == "black"] <- 1
    df$value[df$value == 3 & df$colour == "white"] <- 0
    df1 <- df[, -4]
    new_image <- as.cimg(df1, dims = c(150,100))
    save.image(new_image, "C:/Users/Ali/Desktop/VN_images/", file_names[i], ".png")
    next_image <- c(next_image, new_image)    
}

EDIT: question edited to fix error highlighted by @nrennie below

My main problem at the moment appears to be saving the new image that is generated by the code - I need each new file to have a different name and for the names to preserve the sequence in which they were generated - and then loading the new image in the next iteration of the loop.

With the code as above I get the error message "Error in save.image(new_image, "C:/Users/Ali/Desktop/VN_images/", : unused argument (".png")"

If I change the file path to "C:/Users/Ali/Desktop/VN_images/A.png" the code will run once and save an image named "A.png", but also return the error "Error in if (is.url) { : the condition has length > 1" so there also appears to be a problem loading the new image in the second iteration.

I've looked at several previous answers to similar questions (e.g., here, here, here,here, and here, but I'm struggling to apply the answers to my own problem.

alim
  • 1
  • 2
  • Did you try running it line by line - does it fail on the first iteration (e.g. when i = 1), or on one of the others? Can you also clarify which packages you are using? – nrennie Jun 19 '23 at 08:54
  • @nrennie I don't actually know how to run it line by line - I'm using RStudio if that makes a difference? For the entire sequence, including generating the first image I'm using imager, dplyr, tidyr and magick. I think this bit of code only uses imager and dplyr, but I'm not 100% sure – alim Jun 19 '23 at 09:07
  • In your else statement, `next_image` has initially been defined as an empty vector, and then you run `load.image(next_image)`. You appear to be loading an empty vector - the error may be coming from `load.image` here? Should your for loop also be `i in 1:5`, not `i in 5`? – nrennie Jun 19 '23 at 09:11
  • @nrennie changing `i in 5` to `i in 1:5` produces a different error: Error in `mutate()`: ℹ In argument: `colour = case_when(value == 0 ~ "black", TRUE ~ "white")`. Caused by error in `case_when()`: ! Failed to evaluate the left-hand side of formula 1. Caused by error: ! object 'value' not found Yes you're right about the empty vector - what I want to do is create `next_image` within the loop and use that as the input for each iteration after the first one – alim Jun 19 '23 at 09:17

1 Answers1

0

I managed to get this to work through trial and error and a bit of help offline. Posting the code below in case it helps anyone else in future

library(imager)
library(dplyr)

file_names <- c("VN1", "VN2", "VN3", "VN4", "VN5")
next_image <- NULL

for (i in 1:5) {
  if (i == 1) {
    im <- load.image("C:/Users/Ali/Desktop/VN_images/VN.png")
  } else {
    im <- next_image
  }

  df <- as.data.frame(im) %>%
    mutate(colour = case_when(value == 0 ~ "black", TRUE ~ "white")) %>%
    group_by(colour) %>%
    mutate(value = replace(value, sample(row_number(), size = ceiling(0.05 * n()), replace = FALSE), 3))

  df$value[df$value == 3 & df$colour == "black"] <- 1
  df$value[df$value == 3 & df$colour == "white"] <- 0
  df1 <- df[, -4]
  new_image <- as.cimg(df1, dims = c(150, 100))
  save.image(new_image, paste0("C:/Users/Ali/Desktop/VN_images/", file_names[i], ".png"))

  next_image <- new_image    
}
alim
  • 1
  • 2