/* @pjs preload="https://www.ktbyte.com/showcase/images/mona-lisa.jpg"; */
//By Ben (ktbyte.com)
PImage im = loadImage("https://www.ktbyte.com/showcase/images/mona-lisa.jpg"); //right-click thickness
float th = 2,
imw = 200,
imh = 286; //To run, use Processing. put jpg in folder called "data"
void setup() { //such that /data is in the same folder as VanGoghify.pde
frameRate(2);
size(200, 286);
im = loadImage("https://www.ktbyte.com/showcase/images/mona-lisa.jpg");
size(im.width, im.height);
} //rename all mona-lisa.jpg strings if you change it
void draw() {
image(vanGogh(im, int(mouseY * 1.0 / height * 40) + 1, 10, th, mouseX * 1.0 / width), 0, 0);
}
void mousePressed() {
int m = mouseButton;
if (m == 37) noLoop();
else if (m == 39) th = (th) % 4 + 1;
}
PImage vanGogh(PImage im, int scaleDown, float lineLength, float t, float blendRatio) {
im.loadPixels();
PImage copy = copyArr(new PImage(im.width, im.height), im.pixels);
copy.resize(copy.width / scaleDown, copy.height / scaleDown);
float[][] s2 = sobelas(copy);
for (int i = 0; i < 10000; i++) { //draw 10,00 0 lines on along the correct angle
int x = int(random(imw)),
y = int(random(imh)),
r = int(y * s2.length / imh),
c = int(x * s2[0].length / imw);
float a = s2[r][c] + PI / 2,
len = random(0, lineLength / 2);
stroke(random(255));
strokeWeight(t);
line(x - len * cos(a), y - len * sin(a), x + len * cos(a), y + len * sin(a));
}
return blendSimple(im, screenshot(), blendRatio);
}
float[][] sobelas(PImage img) { //Computes a simple sobel conv and returns the gradient a
float[][] kX = {
{
1,
0,
-1
},
{
2,
0,
-2
},
{
1,
0,
-1
}
},
kY = {
{
1,
2,
1
},
{
0,
0,
0
},
{ - 1,
-2,
-1
}
};
float[][] out = new float[img.height][img.width]; //Sketch designed to work in both Java and js
for (int i = 0; i < img.width * img.height; i++) {
int r = int(i / img.width),
c = i % img.width;
float sX = conv(c, r, kX, img),
sY = conv(c, r, kY, img),
z = out[r][c] = atan2(sY, sX);
}
return out;
}
float conv(int x, int y, float[][] ker, PImage img) { //given a 3 by 3 ker,applies ker to one pixel
float sum = 0.0;
for (int kx = -1; kx <= 1; kx++) for (int ky = -1; ky <= 1; ky++) {
int pos = (x + kx) + (y + ky) * img.width;
if (pos >= 0 && pos < img.pixels.length) sum += ker[ky + 1][kx + 1] * (brightness(img.pixels[pos]) / 256);
}
return sum;
}
PImage copyArr(PImage c, color[] src) { //Build in arrayCopy doesn't work on color[] in js mode
c.loadPixels();
for (int i = 0; i < src.length; i++) c.pixels[i] = src[i];
c.updatePixels();
return c;
}
PImage screenshot() {
loadPixels();
return copyArr(new PImage(width, height), pixels);
}
PImage blendSimple(PImage a, PImage b, float amntB) { //Built in blend function is buggy in js
PImage out = new PImage(a.width, a.height);
out.loadPixels();
for (int i = 0; i < a.width * a.height; i++) {
float ar = red(color(a.pixels[i])),
ag = green(color(a.pixels[i])),
ab = blue(color(a.pixels[i]));
float br = red(color(b.pixels[i])),
bg = green(color(b.pixels[i])),
bb = blue(color(b.pixels[i]));
out.pixels[i] = color(ar * (1 - amntB) + br * amntB, ag * (1 - amntB) + bg * amntB, ab * (1 - amntB) + bb * amntB);
}
out.updatePixels();
return out;
}