Difference between revisions of "User:Tom"
m |
m |
||
Line 465: | Line 465: | ||
[[File:ChanelLogo6.png | left]] | [[File:ChanelLogo6.png | left]] | ||
− | [[File:ChanelSheet.jpg | left | | + | [[File:ChanelSheet.jpg | left | 720px]] |
Revision as of 16:44, 4 February 2018
Contents
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:
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.
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
Processing
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:
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
\begin{lstlisting}
(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; }
This code gave me a lot more control. For instance with the old Apple universe background image:
Other Experiments
These are experiments i tried with simpler codes. Some have also been done manually.
Sorted horizontally from dark to light colors.
Former Glory: Logo's & Icons
As I mentioned before, the result of pixel sorting reminds me of some distant memory, distorted over time. I want to recreate this feeling in a series of images.
First I needed something that counts as some sort of memory, something recognisable. Second, it had to be recognisable for a larger audience. So I had to find some sort of 'collective memory'. For this I chose to use iconic logo's of worldwide brands like McDonalds or Coca Cola. These brands are known worldwide and have been around for many years. Chances are high people will recognise them, even when distorted.