Has anyone noticed that there is a spatial and directional bias regarding the visibility of the strokes in the sketch above? This is because the pixels are being sampled in order by row from top to bottom, and that within each row the pixels are sampled from left to right. Since the strokes are drawn intentionally from each pixel in a random orientation that partially obscures neighboring strokes, the ones at the bottom and at the right, to a lesser extent, are the most visible.
In the above, compare the bristled image to the original. Note that upward strokes tend to be more visible than downward ones. This is especially evident in the flattening of the bases of the onions at the bottom, since the pixels in the black background below them are sampled and stroked later than those of the onions.
While the partial obscuring of neighboring strokes is a feature, the spatial and directional bias is a bug. In the following image, that bias has been rectified via a shuffling of the order of the pixel sampling:
Notice that the bases of the onions at the bottom are decidedly more rounded than those in the previous sketch.
Here’s the updated code:
// instance mode
new p5((p) => {
let img;
p.preload = () => {
// mixed onions image from Wikipedia: Onion
// https://en.m.wikipedia.org/wiki/Onion
img = p.loadImage("440px-Mixed_onions.jpeg");
};
p.setup = () => {
p.createCanvas(img.width, img.height);
p.noLoop();
};
p.draw = () => {
p.noFill();
img.loadPixels();
const numPixels = img.width * img.height;
// randomize order of pixel access
let pix = Array(numPixels);
for (let n = 0; n < pix.length; n++) {
pix[n] = n;
}
p.shuffle(pix, true);
for (let k = 0; k < numPixels; k++) {
let i = pix[k];
let x = p.floor(i % img.width);
let y = p.floor(i / img.width);
p.stroke(
p.color(
img.pixels[i * 4],
img.pixels[i * 4 + 1],
img.pixels[i * 4 + 2],
img.pixels[i * 4 + 3]
)
);
p.push();
p.translate(x, y);
p.rotate(p.random(2 * p.TWO_PI));
p.strokeWeight(p.random(1, 3));
p.curve(
0,
0,
p.randomGaussian() * 10,
p.randomGaussian() * 10,
(p.randomGaussian() + 1) * 10,
(p.randomGaussian() + 1) * 10,
p.randomGaussian() * 3,
p.randomGaussian() * 3
);
p.pop();
}
};
});