Home > database >  Is there a way to bubble sort pixels back to the original image?
Is there a way to bubble sort pixels back to the original image?

Time:11-28

Thanks for reading this. I'm trying to modify a sketch.js provided by the author of this pixel sorting tutorial.

I wonder what's the best way to store the original location of each pixel in an additional texture so as to enable the image to be sorted back to the original?

So far, my goal was to put 2 conditional statements within the draw function such that at a certain point in time (or number of iterations) the pixels start bubble-sorting back to the original image, and only then sort back up again.

Things might be correct

  1. To change the sign of the comparison (i.e., from greater to minus)
  2. To copy .loadPixels() and .updatePixels() in both statements.

Things I'm not so sure about

  1. Reversing the for loop in the else statement
  2. Changing the pixel indexing from (j, i 1) to (j, i - 1)

Things I've not figured out yet

  1. A way to sort back up again once the original image gets recomposed

let panel;
let counter = 0;
const sc = 2;
const panelW = 25;
const panelH = 15;
const frameW = 20;

function preload() {
  panel = loadImage("https://www.paulwheeler.us/files/Burano-island-Venice.jpg");
}

function setup() {
  createCanvas(
    sc * (panel.width   2 * frameW),
    sc * (panel.height   2 * frameW)
  );
  pixelDensity(1);
}

function draw() {

  if (counter < 3200000) {
    panel.loadPixels();
    for (let i = 0; i < panel.height - 1; i  ) {
      for (let j = 0; j < panel.width; j  ) {
        counter = counter   1;
        if (
          hue(fGetPanelPixel(j, i)) >
          hue(fGetPanelPixel(j, i   1))
        ) {
          let hold = fGetPanelPixel(j, i   1);
          fSetPanelPixel(j, i   1, fGetPanelPixel(j, i));
          fSetPanelPixel(j, i, hold);
        }
      }
    }
    panel.updatePixels();

  } else {
    console.log("now backwards...");
    panel.loadPixels();

    for (let i = panel.height - 1; i > 0; i--) {
      for (let j = panel.width - 1; j > 0; j--) {
        if (
          hue(fGetPanelPixel(j, i)) <
          hue(fGetPanelPixel(j, i - 1))
        ) {
          let hold = fGetPanelPixel(j, i - 1);
          fSetPanelPixel(j, i - 1, fGetPanelPixel(j, i));
          fSetPanelPixel(j, i, hold);
        }
      }
    }
    panel.updatePixels();
  }

  image(panel, sc * frameW, sc * frameW, sc * panel.width, sc * panel.height);
}

function fGetPanelPixel(x, y) {
  const index = 4 * (y * panel.width   x);
  return [
    panel.pixels[index],
    panel.pixels[index   1],
    panel.pixels[index   2],
  ];
}

function fSetPanelPixel(x, y, c) {
  const index = 4 * (y * panel.width   x);
  panel.pixels[index] = c[0];
  panel.pixels[index   1] = c[1];
  panel.pixels[index   2] = c[2];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

The above code works insofar as it appears to sort backwards but the visual effect soon gets stuck without ever recomposing the original image. Since I'm a complete newbie any insights is greatly appreciated, cheers!

CodePudding user response:

In order to reverse the sort to put the pixels back in their original position you need to sort not based on hue, but based on the original position of each pixel. That means that you need a separate data structure to keep track of where each pixel originated:

let panel;
let counter = 0;
const sc = 2;
const panelW = 25;
const panelH = 15;
const frameW = 20;

let pixelOrigin = [];

function preload() {
  panel = loadImage("https://www.paulwheeler.us/files/Burano-island-Venice.jpg");
}

function setup() {
  createCanvas(
    sc * (panel.width   2 * frameW),
    sc * (panel.height   2 * frameW)
  );
  pixelDensity(1);
  for (let j = 0; j < panel.width; j  ) {
    pixelOrigin[j] = [];
    for (let i = 0; i < panel.height; i  ) {
      pixelOrigin[j][i] = i;
    }
  }
}

function draw() {
  if (counter < 3200000) {
    panel.loadPixels();
    for (let i = 0; i < panel.height - 1; i  ) {
      for (let j = 0; j < panel.width; j  ) {
        counter = counter   1;
        if (
          hue(fGetPanelPixel(j, i)) >
          hue(fGetPanelPixel(j, i   1))
        ) {
          let hold = fGetPanelPixel(j, i   1);
          fSetPanelPixel(j, i   1, fGetPanelPixel(j, i));
          fSetPanelPixel(j, i, hold);

          // Also swap origins
          let tmp = pixelOrigin[j][i   1];
          pixelOrigin[j][i   1] = pixelOrigin[j][i];
          pixelOrigin[j][i] = tmp;
        }
      }
    }
    panel.updatePixels();

  } else {
    panel.loadPixels();
    for (let i = panel.height - 2; i >= 0; i--) {
      for (let j = 0; j < panel.width; j  ) {
        if (pixelOrigin[j][i] > pixelOrigin[j][i   1]) {
          let hold = fGetPanelPixel(j, i   1);
          fSetPanelPixel(j, i   1, fGetPanelPixel(j, i));
          fSetPanelPixel(j, i, hold);

          // Also swap origins
          let tmp = pixelOrigin[j][i   1];
          pixelOrigin[j][i   1] = pixelOrigin[j][i];
          pixelOrigin[j][i] = tmp;
        }
      }
    }
    panel.updatePixels();
  }

  image(panel, sc * frameW, sc * frameW, sc * panel.width, sc * panel.height);
}

function fGetPanelPixel(x, y) {
  const index = 4 * (y * panel.width   x);
  return [
    panel.pixels[index],
    panel.pixels[index   1],
    panel.pixels[index   2],
  ];
}

function fSetPanelPixel(x, y, c) {
  const index = 4 * (y * panel.width   x);
  panel.pixels[index] = c[0];
  panel.pixels[index   1] = c[1];
  panel.pixels[index   2] = c[2];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related