Difference between revisions of "User:Tom"

From DigitalCraft_Wiki
Jump to navigation Jump to search
Line 84: Line 84:
  
 
[[File:Airplanesort.gif]]
 
[[File:Airplanesort.gif]]
 +
 +
The result was alright, only I had less control than I wanted to. I did research for some more codes and finally found one called 'Butter'. This code gave me a lot more control. I now had the option to sort the 'black', 'white' and 'bright' of the image.
 +
 +
<nowiki>
 +
/*
 +
  Butter.js
 +
  http://github.com/brandly/butter.js
 +
*/
 +
 +
(function () {
 +
  var validModes = ['black', 'bright', 'white'];
 +
  var defaultMode = validModes[0];
 +
 +
  function Butter(mode, threshold) {
 +
    this.mode = mode || defaultMode;
 +
    if (validModes.indexOf(this.mode) === -1) {
 +
      console.log('Butter has no mode called "' + this.mode + '".');
 +
      this.mode = defaultMode;
 +
    }
 +
 +
    // defaults
 +
    this.threshold = {
 +
      black: -10000000,
 +
      white: -6000000,
 +
      bright: 30
 +
    };
 +
 +
    if (typeof threshold !== 'undefined' && threshold !== null) {
 +
      this.threshold[this.mode] = threshold;
 +
    }
 +
  }
 +
 +
  Butter.prototype.sort = function sort(canvas, iterations) {
 +
    if (!canvas) {
 +
      throw 'Butter needs a <canvas> to sort';
 +
    }
 +
    var context = canvas.getContext('2d'),
 +
        width = canvas.width,
 +
        height = canvas.height,
 +
        // Get the current data
 +
        imageData = context.getImageData(0, 0, width, height),
 +
        // And sort it
 +
        sortedImage = this.sortImageData(imageData, width, height, iterations);
 +
 +
    context.putImageData(sortedImage, 0, 0);
 +
  };
 +
 +
  Butter.prototype.sortImageData = function sortImageData(imageData, width, height, iterations) {
 +
    this.imageData = imageData;
 +
    this.width = width;
 +
    this.height = height;
 +
    iterations || (iterations = 1);
 +
 +
    for (var i = 0; i < iterations; i++) {
 +
 +
      for (var column = 0; column < this.width; column++) {
 +
        this.sortColumn(column);
 +
      }
 +
 +
      for (var row = 0; row < this.height; row++) {
 +
        this.sortRow(row);
 +
      }
 +
    }
 +
 +
    return this.imageData;
 +
  };
 +
 +
  Butter.prototype.setThreshold = function setThreshold(value) {
 +
    this.threshold[this.mode] = value;
 +
  };
 +
 +
  Butter.prototype.sortColumn = function sortColumn(x) {
 +
    var ranges = this.getRangesForColumn(x),
 +
        range, width, pixelData;
 +
 +
    // For each range...
 +
    for (var i = 0; i < ranges.length; i++) {
 +
      range = ranges[i];
 +
      width = range.end - range.start;
 +
 +
      pixelData = new Array(width);
 +
 +
      // Get all the pixels in that range
 +
      for (var j = 0; j < width; j++) {
 +
        pixelData[j] = this.getPixelValue(x, range.start + j);
 +
      }
 +
 +
      // Sort them!
 +
      pixelData.sort();
 +
 +
      // And put the new pixels back
 +
      for (var j = 0; j < width; j++) {
 +
        this.setPixelValue(x, (range.start + j), pixelData[j]);
 +
      }
 +
    }
 +
  };
 +
 +
  Butter.prototype.sortRow = function sortRow(y) {
 +
    var ranges = this.getRangesForRow(y),
 +
        range, width, pixelData;
 +
 +
    // For each range...
 +
    for (var i = 0; i < ranges.length; i++) {
 +
      range = ranges[i];
 +
      width = range.end - range.start;
 +
 +
      pixelData = new Array(width);
 +
 +
      // Get all the pixels in that range
 +
      for (var j = 0; j < width; j++) {
 +
        pixelData[j] = this.getPixelValue(range.start + j, y);
 +
      }
 +
 +
      // Sort them!
 +
      pixelData.sort();
 +
 +
      // And put the new pixels back
 +
      for (var j = 0; j < width; j++) {
 +
        this.setPixelValue((range.start + j), y, pixelData[j]);
 +
      }
 +
    }
 +
  };
 +
 +
  Butter.prototype.getRangesForColumn = function getRangesForColumn(x) {
 +
    var ranges = [],
 +
        start = 0,
 +
        end = 0,
 +
        findFirst, findNext;
 +
 +
    switch(this.mode) {
 +
      case 'black':
 +
        findFirst = this.getFirstNotBlackY;
 +
        findNext = this.getNextBlackY;
 +
        break;
 +
 +
      case 'bright':
 +
        findFirst = this.getFirstBrightY;
 +
        findNext = this.getNextDarkY;
 +
        break;
 +
 +
      case 'white':
 +
        findFirst = this.getFirstNotWhiteY;
 +
        findNext = this.getNextWhiteY;
 +
        break;
 +
    }
 +
 +
    for ( ; end < this.height; start = (end + 1)) {
 +
      start = findFirst.call(this, x, start);
 +
      end = findNext.call(this, x, start);
 +
 +
      // No more ranges
 +
      if (start < 0 || start >= this.height) break;
 +
 +
      ranges.push({start: start, end: end});
 +
    }
 +
    return ranges;
 +
  };
 +
 +
  Butter.prototype.getRangesForRow = function getRangesForRow(y) {
 +
    var ranges = [],
 +
        start = 0,
 +
        end = 0,
 +
        findFirst, findNext;
 +
 +
    switch(this.mode) {
 +
      case 'black':
 +
        findFirst = this.getFirstNotBlackX;
 +
        findNext = this.getNextBlackX;
 +
        break;
 +
 +
      case 'bright':
 +
        findFirst = this.getFirstBrightX;
 +
        findNext = this.getNextDarkX;
 +
        break;
 +
 +
      case 'white':
 +
        findFirst = this.getFirstNotWhiteX;
 +
        findNext = this.getNextWhiteX;
 +
        break;
 +
    }
 +
 +
    for ( ; end < this.width; start = (end + 1)) {
 +
      start = findFirst.call(this, start, y);
 +
      end = findNext.call(this, start, y);
 +
 +
      // No more ranges
 +
      if (start < 0 || start >= this.width) break;
 +
 +
      ranges.push({start: start, end: end});
 +
    }
 +
    return ranges;
 +
  };
 +
 +
  /*
 +
    Finders
 +
  */
 +
 +
  Butter.prototype.getFirstNotBlackX = function getFirstNotBlackX(x, y) {
 +
    // Loop until we find a match
 +
    for ( ; this.getPixelValue(x, y) < this.threshold.black; x++) {
 +
      // Oh no, we've reached the edge!
 +
      if (x >= this.width) return -1;
 +
    }
 +
    // Return the match
 +
    return x;
 +
  }
 +
 +
  Butter.prototype.getNextBlackX = function getNextBlackX(x, y) {
 +
    // We want the _next_ one
 +
    x += 1;
 +
    for ( ; this.getPixelValue(x, y) > this.threshold.black; x++) {
 +
      if (x >= this.width) return this.width - 1;
 +
    }
 +
    return x;
 +
  }
 +
 +
 +
  Butter.prototype.getFirstBrightX = function getFirstBrightX(x, y) {
 +
    for ( ; this.getPixelBrightness(x, y) < this.threshold.bright; x++) {
 +
      if (x >= this.width) return -1;
 +
    }
 +
    return x;
 +
  }
 +
 +
  Butter.prototype.getNextDarkX = function getNextDarkX(x, y) {
 +
    x += 1;
 +
    for ( ; this.getPixelBrightness(x, y) > this.threshold.bright; x++) {
 +
      if (x >= this.width) return this.width - 1;
 +
    }
 +
    return x;
 +
  }
 +
 +
 +
  Butter.prototype.getFirstNotWhiteX = function getFirstNotWhiteX(x, y) {
 +
    for ( ; this.getPixelValue(x, y) > this.threshold.white; x++) {
 +
      if (x >= this.width) return -1;
 +
    }
 +
    return x;
 +
  }
 +
 +
  Butter.prototype.getNextWhiteX = function getNextWhiteX(x, y) {
 +
    x += 1;
 +
    for ( ; this.getPixelValue(x, y) < this.threshold.white; x++) {
 +
      if (x >= this.width) return this.width - 1;
 +
    }
 +
    return x;
 +
  }
 +
 +
 +
  Butter.prototype.getFirstNotBlackY = function getFirstNotBlackY(x, y) {
 +
    for ( ; this.getPixelValue(x, y) < this.threshold.black; y++) {
 +
      if (y >= this.height) return -1;
 +
    }
 +
    return y;
 +
  }
 +
 +
  Butter.prototype.getNextBlackY = function getNextBlackY(x, y) {
 +
    y += 1;
 +
    for ( ; this.getPixelValue(x, y) > this.threshold.black; y++) {
 +
      if (y >= this.height) return this.height - 1;
 +
    }
 +
    return y;
 +
  }
 +
 +
 +
  Butter.prototype.getFirstBrightY = function getFirstBrightY(x, y) {
 +
    for ( ; this.getPixelBrightness(x, y) < this.threshold.bright; y++) {
 +
      if (y >= this.height) return -1;
 +
    }
 +
    return y;
 +
  }
 +
 +
  Butter.prototype.getNextDarkY = function getNextDarkY(x, y) {
 +
    y += 1;
 +
    for ( ; this.getPixelBrightness(x, y) > this.threshold.bright; y++) {
 +
      if (y >= this.height) return this.height - 1;
 +
    }
 +
    return y;
 +
  }
 +
 +
 +
  Butter.prototype.getFirstNotWhiteY = function getFirstNotWhiteY(x, y) {
 +
    for ( ; this.getPixelValue(x, y) > this.threshold.white; y++) {
 +
      if (y >= this.height) return -1;
 +
    }
 +
    return y;
 +
  }
 +
 +
  Butter.prototype.getNextWhiteY = function getNextWhiteY(x, y) {
 +
    y += 1;
 +
    for ( ; this.getPixelValue(x, y) < this.threshold.white; y++) {
 +
      if (y >= this.height) return this.height - 1;
 +
    }
 +
    return y;
 +
  }
 +
 +
  /*
 +
    Utilities
 +
  */
 +
 +
  Butter.prototype.getPixelOffset = function getPixelOffset(x, y) {
 +
    return (x + y * this.width) * 4;
 +
  };
 +
 +
  Butter.prototype.setPixelValue = function setPixelValue(x, y, val) {
 +
    var offset = this.getPixelOffset(x, y),
 +
        r = (val >> 16) & 255,
 +
        g = (val >> 8) & 255,
 +
        b = val & 255,
 +
        data = this.imageData.data;
 +
 +
    data[offset] = r;
 +
    data[offset + 1] = g;
 +
    data[offset + 2] = b;
 +
  }
 +
 +
  Butter.prototype.getPixelValue = function getPixelValue(x, y) {
 +
    var offset = this.getPixelOffset(x, y),
 +
        data = this.imageData.data,
 +
        r = data[offset],
 +
        g = data[offset + 1],
 +
        b = data[offset + 2];
 +
 +
    return ( ((255 << 8) | r) << 8 | g) << 8 | b;
 +
  }
 +
 +
  Butter.prototype.getPixelBrightness = function getPixelBrightness(x, y) {
 +
    var offset = this.getPixelOffset(x, y),
 +
        data = this.imageData.data,
 +
        r = data[offset],
 +
        g = data[offset + 1],
 +
        b = data[offset + 2];
 +
 +
    return Math.max(r, g, b) / 255 * 100;
 +
  }
 +
 +
  // Let it loose
 +
  if ((typeof module !== "undefined") && (module.exports)) {
 +
    module.exports = Butter;
 +
  } else {
 +
    this.Butter = Butter;
 +
  }
 +
}());
 +
</nowiki>

Revision as of 18:41, 2 February 2018

Project (WORK IN PROGRESS)

I ran into a couple of gifs that visualised how certain sorting algorithms worked. Normally I don’t understand algorithms, but these visualisations made it so easy and insightful to understand what is going on. Besides that I think it’s cool to see an algorithm at work like this, I also think it has some artistic value. You could call it Glitch Art.

These are some examples of different codes working on a color palette:

PixelSortingExample.gif

It is a code creating a new kind of image by rearranging the original. This results in an image made anonymous. Or maybe more like a vague memory, where everything is still there but over time you start to forget what it looks like. This creates a new memory, a distorted version of the original.

Examplesort1.jpg Examplesort2.jpg
Examplesort3.jpg Examplesort4.jpg

What is Pixel Sorting?

Pixel Sorting is done with a program called Processing. It takes the pixels in a digital image and places them into a semblance of order. Pixel sorting was made popular by an artist of the name Kim Asendorf. He began sorting by developing a code in Processing.


Experiment

This is a modified version of the code written bij Kim Asendorf. It is written in Processing language, and requires a folder called ‘data’ in the same location as the .pde processing file. I used it to experiment with different images to discover what would happen.

PImage img;
PImage sorted;
int index = 0;

void setup() {
  size(800, 400);

  img = loadImage("afbeelding.jpg");
  sorted = createImage(img.width, img.height, RGB);
  sorted = img.get();
}

void draw() {
  println(frameRate);

  sorted.loadPixels();

  // Selection sort!
  for (int y = 0; y < sorted.height; y++) {

    float record = -1;
    int selectedPixel = index;

    for (int x = index; x < sorted.width; x++) {
      int loc = y * sorted.width + x;
      color pix = sorted.pixels[loc];
      float b = brightness(pix);
      if (b > record) {
        selectedPixel = loc;
        record = b;
      }
    }
    // Swap selectedPixel with i
    color temp = sorted.pixels[y * sorted.width + index];
    sorted.pixels[y * sorted.width + index] = sorted.pixels[selectedPixel];
    sorted.pixels[selectedPixel] = temp;
  }
  if (index < sorted.width -1) {
    index++;
  } else {
    save("sorted.jpg");
    frameRate(0);
  }

  sorted.updatePixels();

  background(0);
  image(img, 0, 0);
  image(sorted, 400, 0);
}

The code results in a pixel sorting visualisation:

Airplanesort.gif

The result was alright, only I had less control than I wanted to. I did research for some more codes and finally found one called 'Butter'. This code gave me a lot more control. I now had the option to sort the 'black', 'white' and 'bright' of the image.

/* Butter.js http://github.com/brandly/butter.js */ (function () { var validModes = ['black', 'bright', 'white']; var defaultMode = validModes[0]; function Butter(mode, threshold) { this.mode = mode || defaultMode; if (validModes.indexOf(this.mode) === -1) { console.log('Butter has no mode called "' + this.mode + '".'); this.mode = defaultMode; } // defaults this.threshold = { black: -10000000, white: -6000000, bright: 30 }; if (typeof threshold !== 'undefined' && threshold !== null) { this.threshold[this.mode] = threshold; } } Butter.prototype.sort = function sort(canvas, iterations) { if (!canvas) { throw 'Butter needs a <canvas> to sort'; } var context = canvas.getContext('2d'), width = canvas.width, height = canvas.height, // Get the current data imageData = context.getImageData(0, 0, width, height), // And sort it sortedImage = this.sortImageData(imageData, width, height, iterations); context.putImageData(sortedImage, 0, 0); }; Butter.prototype.sortImageData = function sortImageData(imageData, width, height, iterations) { this.imageData = imageData; this.width = width; this.height = height; iterations || (iterations = 1); for (var i = 0; i < iterations; i++) { for (var column = 0; column < this.width; column++) { this.sortColumn(column); } for (var row = 0; row < this.height; row++) { this.sortRow(row); } } return this.imageData; }; Butter.prototype.setThreshold = function setThreshold(value) { this.threshold[this.mode] = value; }; Butter.prototype.sortColumn = function sortColumn(x) { var ranges = this.getRangesForColumn(x), range, width, pixelData; // For each range... for (var i = 0; i < ranges.length; i++) { range = ranges[i]; width = range.end - range.start; pixelData = new Array(width); // Get all the pixels in that range for (var j = 0; j < width; j++) { pixelData[j] = this.getPixelValue(x, range.start + j); } // Sort them! pixelData.sort(); // And put the new pixels back for (var j = 0; j < width; j++) { this.setPixelValue(x, (range.start + j), pixelData[j]); } } }; Butter.prototype.sortRow = function sortRow(y) { var ranges = this.getRangesForRow(y), range, width, pixelData; // For each range... for (var i = 0; i < ranges.length; i++) { range = ranges[i]; width = range.end - range.start; pixelData = new Array(width); // Get all the pixels in that range for (var j = 0; j < width; j++) { pixelData[j] = this.getPixelValue(range.start + j, y); } // Sort them! pixelData.sort(); // And put the new pixels back for (var j = 0; j < width; j++) { this.setPixelValue((range.start + j), y, pixelData[j]); } } }; Butter.prototype.getRangesForColumn = function getRangesForColumn(x) { var ranges = [], start = 0, end = 0, findFirst, findNext; switch(this.mode) { case 'black': findFirst = this.getFirstNotBlackY; findNext = this.getNextBlackY; break; case 'bright': findFirst = this.getFirstBrightY; findNext = this.getNextDarkY; break; case 'white': findFirst = this.getFirstNotWhiteY; findNext = this.getNextWhiteY; break; } for ( ; end < this.height; start = (end + 1)) { start = findFirst.call(this, x, start); end = findNext.call(this, x, start); // No more ranges if (start < 0 || start >= this.height) break; ranges.push({start: start, end: end}); } return ranges; }; Butter.prototype.getRangesForRow = function getRangesForRow(y) { var ranges = [], start = 0, end = 0, findFirst, findNext; switch(this.mode) { case 'black': findFirst = this.getFirstNotBlackX; findNext = this.getNextBlackX; break; case 'bright': findFirst = this.getFirstBrightX; findNext = this.getNextDarkX; break; case 'white': findFirst = this.getFirstNotWhiteX; findNext = this.getNextWhiteX; break; } for ( ; end < this.width; start = (end + 1)) { start = findFirst.call(this, start, y); end = findNext.call(this, start, y); // No more ranges if (start < 0 || start >= this.width) break; ranges.push({start: start, end: end}); } return ranges; }; /* Finders */ Butter.prototype.getFirstNotBlackX = function getFirstNotBlackX(x, y) { // Loop until we find a match for ( ; this.getPixelValue(x, y) < this.threshold.black; x++) { // Oh no, we've reached the edge! if (x >= this.width) return -1; } // Return the match return x; } Butter.prototype.getNextBlackX = function getNextBlackX(x, y) { // We want the _next_ one x += 1; for ( ; this.getPixelValue(x, y) > this.threshold.black; x++) { if (x >= this.width) return this.width - 1; } return x; } Butter.prototype.getFirstBrightX = function getFirstBrightX(x, y) { for ( ; this.getPixelBrightness(x, y) < this.threshold.bright; x++) { if (x >= this.width) return -1; } return x; } Butter.prototype.getNextDarkX = function getNextDarkX(x, y) { x += 1; for ( ; this.getPixelBrightness(x, y) > this.threshold.bright; x++) { if (x >= this.width) return this.width - 1; } return x; } Butter.prototype.getFirstNotWhiteX = function getFirstNotWhiteX(x, y) { for ( ; this.getPixelValue(x, y) > this.threshold.white; x++) { if (x >= this.width) return -1; } return x; } Butter.prototype.getNextWhiteX = function getNextWhiteX(x, y) { x += 1; for ( ; this.getPixelValue(x, y) < this.threshold.white; x++) { if (x >= this.width) return this.width - 1; } return x; } Butter.prototype.getFirstNotBlackY = function getFirstNotBlackY(x, y) { for ( ; this.getPixelValue(x, y) < this.threshold.black; y++) { if (y >= this.height) return -1; } return y; } Butter.prototype.getNextBlackY = function getNextBlackY(x, y) { y += 1; for ( ; this.getPixelValue(x, y) > this.threshold.black; y++) { if (y >= this.height) return this.height - 1; } return y; } Butter.prototype.getFirstBrightY = function getFirstBrightY(x, y) { for ( ; this.getPixelBrightness(x, y) < this.threshold.bright; y++) { if (y >= this.height) return -1; } return y; } Butter.prototype.getNextDarkY = function getNextDarkY(x, y) { y += 1; for ( ; this.getPixelBrightness(x, y) > this.threshold.bright; y++) { if (y >= this.height) return this.height - 1; } return y; } Butter.prototype.getFirstNotWhiteY = function getFirstNotWhiteY(x, y) { for ( ; this.getPixelValue(x, y) > this.threshold.white; y++) { if (y >= this.height) return -1; } return y; } Butter.prototype.getNextWhiteY = function getNextWhiteY(x, y) { y += 1; for ( ; this.getPixelValue(x, y) < this.threshold.white; y++) { if (y >= this.height) return this.height - 1; } return y; } /* Utilities */ Butter.prototype.getPixelOffset = function getPixelOffset(x, y) { return (x + y * this.width) * 4; }; Butter.prototype.setPixelValue = function setPixelValue(x, y, val) { var offset = this.getPixelOffset(x, y), r = (val >> 16) & 255, g = (val >> 8) & 255, b = val & 255, data = this.imageData.data; data[offset] = r; data[offset + 1] = g; data[offset + 2] = b; } Butter.prototype.getPixelValue = function getPixelValue(x, y) { var offset = this.getPixelOffset(x, y), data = this.imageData.data, r = data[offset], g = data[offset + 1], b = data[offset + 2]; return ( ((255 << 8) | r) << 8 | g) << 8 | b; } Butter.prototype.getPixelBrightness = function getPixelBrightness(x, y) { var offset = this.getPixelOffset(x, y), data = this.imageData.data, r = data[offset], g = data[offset + 1], b = data[offset + 2]; return Math.max(r, g, b) / 255 * 100; } // Let it loose if ((typeof module !== "undefined") && (module.exports)) { module.exports = Butter; } else { this.Butter = Butter; } }());