// (c) Alex McLean 2005 // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. PImage image; int threshold; int sample = 9; float thresholdTweak = 0.04; float brightThreshold = 255; float curve = 4; int attempts = 2000; int strokewidth = 3; int strokerate = 12; int minline = 20; color[] pix; float[] b; float tracex = 40; float tracey = 40; float direction = 0; float speed = 0.5; int maxx; int maxy; color white = color(255, 255, 255); int points = 0; void setup () { image = loadImage("metro.jpg"); maxx = image.width; maxy = image.height; size(image.width, image.height * 3); background(255); image(image, 0, 0); int foo = 0; pix = image.pixels; int maxx = image.width; int maxy = image.height; int maxpix = maxx * maxy; b = new float[maxpix]; float maxc, minc; maxc = minc = brightness(pix[0]); for (int c = 1; c < maxpix; c++) { if (brightness(pix[c]) > maxc) { maxc = brightness(pix[c]); } if (brightness(pix[c]) < minc) { minc = brightness(pix[c]); } } threshold = int((maxc - minc) * thresholdTweak); edge(); framerate(200); } void edge() { int border = ((sample - 1) / 2); for (int x = border; x < (maxx - border); ++x) { for (int y = border; y < (maxy - border); ++y) { int value = pix[x + (y * maxx)]; int total = 0; for (int x1 = 0 - border; x1 <= border; ++x1) { for (int y1 = 0 - border; y1 <= border; ++y1) { total += brightness(pix[x + x1 + ((y + y1) * maxx)]); } } int average = total / (sample * sample); int diff = abs(average - int(brightness(value))); if (diff > threshold) { stroke(brightness(value)); point(x, y + maxy); b[x + (maxx * y)] = brightness(value); } else { b[x + (maxx * y)] = 255; } } } } void check() { if (! (tracex >= 0 && tracex < maxx && tracey >= 0 && tracey < maxy)) { if (random(1) > 0.7) { tracex = random(maxx); tracey = 0; direction = random(PI) - HALF_PI; } else { tracex = 0; tracey = random(maxy); direction = random(PI); } length = 0; on = false; } } void move() { float hyp = speed; float opp = sin(direction) * hyp; float adj = cos(direction) * hyp; float newx = tracex + opp; float newy = tracey + adj; if (on) { boolean ant1on = false, ant2on = false; float ant1direction = direction - PI/curve; float ant1x = tracex + sin(ant1direction) * hyp; float ant1y = tracey + cos(ant1direction) * hyp; if (ant1x < maxx && ant1y < maxy) { ant1on = b[int(ant1x) + (maxx * int(ant1y))] < brightThreshold; } float ant2direction = direction + PI/curve; float ant2x = tracex + sin(ant2direction) * hyp; float ant2y = tracey + cos(ant2direction) * hyp; if (ant2x < maxx && ant2y < maxy) { ant2on = b[int(ant2x) + (maxx * int(ant2y))] < brightThreshold; } if (ant1on && (!ant2on)) { newx = ant1x; newy = ant1y; } else if ((!ant1on) && ant2on) { newx = ant2x; newy = ant2y; } } tracex = newx; tracey = newy; } boolean on = false; int length = 0; float startx, starty, startdirection; void draw() { if (attempts-- > 0) { for (int i = 0; i < 1000; ++i) { drawframe(); } } } void drawframe() { move(); check(); float brightness = b[int(tracex) + (maxx * int(tracey))]; if (! on) { if (brightness < brightThreshold) { on = true; startx = tracex; starty = tracey; startdirection = direction; length = 1; } } else { if (brightness < brightThreshold) { length++; } else { if (length > minline) { direction = startdirection; tracex = startx; tracey = starty; float prevx = 0, prevy = 0; for (int i = 0; i < length; ++i) { stroke(get(int(tracex), int(tracey))); float foo = strokewidth * sin((PI / strokerate) * points++); float x1 = tracex + sin(direction + PI / 2) * foo; float y1 = tracey + cos(direction + PI / 2) * foo; if (prevx != 0 && prevy != 0) { line(prevx, prevy + (maxy * 2), x1, y1 + (maxy * 2)); } prevx = x1; prevy = y1; //ellipse(x1, y1 + (maxy * 2), 2, 2); move(); } } on = false; length = 0; } } }