Help with pixel permutation?

I want you to press a key

the pixels of an image are disordered

I thought of using

pixels.[i] = img.pixels[random(img.width * img.height)]

but some pixels can be repeated

eg if random () returns 2 and the next pixel random () returns 2
how do I do that random () does not return a number that already returned.

int r = i;
while( r == i ){
 r = int(random(pixels.length));
}
pixels[i] = img.pixels[r];

but you do not have to exit the numbers that you have already returned random ()
if random () already returned 1 2 3 4 5 ā€¦ 1000
random () does not have to solve those numbers

Is there a way, without using so much use of the CPU?

boolean[] used = new boolean[pixels.length];
int r = i;
while( r == i  && !used[r] ){
 r = int(random(pixels.length));
}
used[r] = false;
pixels[i] = img.pixels[r];
2 Likes

If Iā€™m understanding right, you want to shuffle pixels, and you want it to be fast. Is that right? Pixels is an int[] array, so you effectively are asking how to efficiently shuffle an int[] array in Java.

Here are timings for three approaches. They all gave me similar performance.

/**
 * Shuffle Pixels Timings -- time different methods for shuffling a pixels array
 * Processing 3.4 2018-09-08 Jeremy Douglass
 */

import java.util.Random;
int startTime;
int endTime;
int timings;

void setup() {
  size(800, 800);
  frameRate(100);
  timings = 100;
  rainbow();
}

void rainbow() {
  pushStyle();
  loadPixels();
  colorMode(HSB, pixels.length, 1, 1);
  for (int i=0; i<pixels.length; i++) {
    pixels[i] = color(i, 1, 1);
  }
  updatePixels();
  popStyle();
}

void draw() {
  if (frameCount%timings==1) {
    startTime = millis();
  }
  loadPixels();
  shufflePixels(pixels);
  // shufflePixels2(pixels);
  // shufflePixels3(pixels);
  updatePixels();
  if (frameCount%timings==0) {
    endTime = millis();
    print((endTime - startTime)/(float)timings, ' ');
  }
}

// shuffle in-place
// timings: 27.73  26.23  25.55  24.88  30.48 
void shufflePixels (int[] pixels) {
  Random rgen = new Random();
  for (int i=0; i<pixels.length; i++) {
    int randomPosition = rgen.nextInt(pixels.length);
    int temp = pixels[i];
    pixels[i] = pixels[randomPosition];
    pixels[randomPosition] = temp;
  }
}

// shuffle using IntList, then copy
// timings: 28.5  26.38  25.58  28.25  29.43
void shufflePixels2 (int[] pixels) {
  IntList shuffler = new IntList(pixels);
  shuffler.shuffle();
  for (int i=0; i<pixels.length; i++) {
    pixels[i] = shuffler.get(i);
  }
}

// shuffle into new list, then copy
// timings: 30.29  26.17  26.29  25.73  25.44
void shufflePixels3 (int[] pixels) {
  int[] newpixels = new int[pixels.length];
  Random rgen = new Random();
  for (int i=0; i<pixels.length; i++) {
    int randomPosition = rgen.nextInt(pixels.length);
    newpixels[i] = pixels[randomPosition];
  }
  for (int i=0; i<pixels.length; i++) {
    pixels[i] = newpixels[i];
  }
}

See also a past discussion: