Process folder of PNGs after quicksorting pixels?

Hi everyone!

So I’m sort of new to Processing / coding and am having a great time, but stuck at a bit of a hurdle here.

I’ve made a modified version of one of these pixel sorting projects by volfegan (specifically the QuickSorting one). I’ve got it to work exactly how I want on a single image (including the options to select one image, select a random file from folder which is great). The next step is to get it working with PNG sequences so that I can take the sorted pixels and make them into video files. But for some reason I cannot get this code to load the next image when the QuickSort is done / stackcall is empty.

The fileSelect block deals with loading a folder and loads the names of all files into an array. This works for loading single files, and even later in the draw block where there’s a for loop that should only advance if the stackcall queue is empty. But for some reason it just dumps all the filenames and doesn’t wait until stackcalls.isEmpty() returns true. I’ve tried a bunch of different things like delays, trying to make a boolean for when the frame is finished processing, but I’m having no luck so I’m hoping somebody of better knowledge here would be able to assist me! The code should work as is if you copy and paste it into processing,

Hoping someone can help and if you can: thanks in advance!

import java.util.Queue;
import java.util.LinkedList;

//image and movie object globals
PImage img;
PImage sorted;
Movie movie;
//filepath globals
String filepath;
String foldername;
String[] filenames;
String dirpath;
//sorting globals
int multiStep = 5;
boolean showBoth = true;
int showOriginal = 1;
String sortPixelMethod = "hue";
//other globals
int width = 0;
int height = 0;
Queue<int[]> stackcalls = new LinkedList();
boolean started = false;

// Select mode of importing file(s)
// 1 = single file
// 2 = random file from chosen folder
// 3 = process a whole folder of files in sequence
int fileMode = 3;
boolean useTestFolder = false;

//list the names of whatever is selected in an array
String[] listFileNames (String dir) {
  File file = new File(dir);
  String names[] = file.list();
  return names;
}

void fileSelect (File selection) {
  if (selection == null) {
    //if user selects nothing, print and exit program
    println("Nothing selected!");
    exit();
  } else {
    // if its a folder
    if (selection.isDirectory()) {
      println("Selecting a random file from", selection);
      dirpath = selection.getAbsolutePath();
      filenames = listFileNames(dirpath);
      if (fileMode == 2) {
        //if fileMode is random from folder: get a random index and change the filepath
        int indexToDisplay = (int) Math.floor(Math.random() * (filenames.length));
        filepath = dirpath + "\\" + filenames[indexToDisplay];
        println("File selected: " + filepath);
      } else if (fileMode == 3) {
        //if processing a whole folder in sequence, just get the first file in the folder
        println("Processing folder of", filenames.length, "images in sequence\r");
        filepath = dirpath + "\\" + filenames[0];
      }
    } else {
      //if selecting a single image
      filepath = selection.getAbsolutePath();
      String filename = selection.getName();
      int pos = filename.lastIndexOf(".");
      if (pos != -1) filename = filename.substring(0, pos);
      println("File selected" + filepath);
    }
    //load whatever image is first
    img = loadImage(filepath);
  }
}

void interrupt () {
  while (img == null) delay(200);
}

void settings () {
  if (fileMode == 1) {
    //select a single image
    selectInput("Select an image", "fileSelect");
  } else if (fileMode != 1 && !useTestFolder) {
    // if the filemode is anything but single image
    selectFolder("Select a folder of images", "fileSelect");
  } else if (useTestFolder) {
    //just for testing, set to whatever if you want to avoid having to go through dialogs every time you run the program
    File file = new File("");
    fileSelect(file);
  } else {
    exit();
  }
  
  //don't do anything until a file is selected
  interrupt();
  
  //resize the canvas
  width = img.width;
  height = img.height;

  if (width > displayWidth) {
    float resizer = width / (displayWidth * 0.8);
    width = (int)((float) displayWidth * 0.8);
    height = (int)((float) height / resizer);
    img.resize(width, height);
  } else if (height > displayHeight) {
    float resizer = height / (displayHeight * 0.8);
    height = (int)((float) displayHeight * 0.8);
    width = (int)((float) width / resizer);
    img.resize(width, height);
  }

  if (showBoth && 2 * img.width < displayWidth) {
    width = img.width * 2;
  }
  //print the dimensions of original image)
  println("width:", img.width, "/", "height:", img.height);
  size(width, height);
}

void setup() {
  //canvas set in void settings
  sorted = createImage(img.width, img.height, HSB);
  sorted = img.get();
  background(0);
}

void draw() {
  
  if (fileMode != 3) {
    sorted.loadPixels();
    quickMe();
    sorted.updatePixels();
    if (stackcalls.size() != 0) {
      println("Quicksort: " + String.format ("%.2f", frameRate)
        + " frameRate / steps to finish: " + stackcalls.size());
    } else if (stackcalls.isEmpty() && started) {
      print("You're done baby!\r");
      noLoop();
    }
  } else {
    for (int x = 0; x < filenames.length && stackcalls.isEmpty() && !started; x++) {
      String filename = filenames[x];
      filepath = dirpath + "\\" + filename;
      img = loadImage(filepath);
      sorted = img.get();
      sorted.loadPixels();
      started = false;
      println(filepath);
      noLoop();
    }
  }


  if (showBoth && 2 * img.width < displayWidth) {
    image(img, 0, 0);
    image(sorted, img.width, 0);
  } else if (!showBoth) {
    image(sorted, 0, 0);
  }
}

void quickMe() {
  for (int steps = 0; steps < multiStep; steps++) {
    if (stackcalls.isEmpty() && !started) {
      quickSort(sorted.pixels, 0, sorted.pixels.length-1);
      started = true;
    } else if (!stackcalls.isEmpty()) {
      int[] indexes = stackcalls.remove();
      quickSort(null, indexes[0], indexes[1]);
    }
  }
}

void quickSort (int[] array, int lowerIndex, int higherIndex) {
  float pivotPix = 0;
  int i = lowerIndex;
  int j = higherIndex;
  if (array == null) array = sorted.pixels;
  int pivot = array[lowerIndex + (higherIndex - lowerIndex) / 2];

  //get pivotPix
  if (sortPixelMethod.equals("hue")) {
    pivotPix = hue(pivot);
  } else if (sortPixelMethod.equals("saturation")) {
    pivotPix = saturation(pivot);
  } else if (sortPixelMethod.equals("brightness")) {
    pivotPix = brightness(pivot);
  }

  //change pivot pixel depending on sortPixelMethod
  while (i <= j) {
    if (sortPixelMethod.equals("hue")) {
      while (hue(array[i]) > pivotPix) i++;
      while (hue(array[j]) < pivotPix) j--;
    } else if (sortPixelMethod.equals("saturation")) {
      while (saturation(array[i]) > pivotPix) i++;
      while (saturation(array[j]) < pivotPix) j--;
    } else if (sortPixelMethod.equals("brightness")) {
      while (brightness(array[i]) > pivotPix) i++;
      while (brightness(array[j]) < pivotPix) j--;
    }

    if (i <= j) {
      exchangePixel(array, i, j);
      //move index to next position on both sides
      i++;
      j--;
    }
  }

  if (lowerIndex < j) {
    //quickSort(array, lowerIndex, j);
    stackcalls.add(new int[]{lowerIndex, j});
  }
  if (i < higherIndex) {
    //quickSort(array, i, higherIndex);
    stackcalls.add(new int[]{i, higherIndex});
  }
}

void exchangePixel (int[] array, int i, int j) {
  color temp = array[i];
  array[i] = array[j];
  array[j] = temp;
}

If anyone far into the future is looking for a solution to this I managed to solve it in the end. I know from my experience that googling your problem sometimes returns a result so I thought I’d post my solution to loading a new image when the stackcalls are empty:

//in a fileSelection function, use this if you want to process a whole folder of images
//dir = File data for folder you're using
//filenames = string array containing the names of all files in a folder
if (frame == -1) {
  dirname = dir.getName();
  println("Processing folder " + dirname + " in sequence.");
}

if (frame < filenames.length-1) {
  frame++;
  framename = filenames[frame];
  filepath = dir.getAbsolutePath() + "\\" + framename;
  println("Current frame:", frame + 1, "of", filenames.length);
}

//in void draw()
//quickMe is function that starts the QuickSorting process
sorted.loadPixels();
quickMe(sorted.pixels);
sorted.updatePixels();
if (stackcalls.isEmpty() && frame < filenames.length-1) {
  if (saveFile) {
    save(savePath + "\\" + dirname + "_sorted_" + sortPixelMethod + "_" + DDMMYY_HHMMSS + "\\" 
    + dirname + "_sorted_" + sortPixelMethod + "_" + nf(frame+1, 5) + ".png");
  }
  started = false;
  fileSelect(dir);
} else if (stackcalls.isEmpty() && frame == filenames.length-1) {
  println("Done!");
  noLoop();
}     

1 Like