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: