Image conversion to ascii art.
This implementation uses the list given by Paul Bourke in Character representation of grey scale images. The "Standard" character ramp for grey scale pictures, black -> white.
"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,"^`'. "
An image of 64x64 is created for each character. Then, the images are concatenated and passed to the shaders. The shaders have the logic to select the part of this new large image to choose the proper character. The creation of the characters images was developed in Python, code below:
1linkimport cv2
2linkfrom glob import glob
3linkfrom PIL import Image,ImageStat, ImageDraw,>>ImageFont
4linkimport math
5link
6linkdef brightness( img_file ):
7link im = Image.open(img_file)
8link stat = ImageStat.Stat(im)
9link r,g,b = stat.rms
10link bright= math.sqrt(0.241*(r**2) + 0.691*(g**2) >>+ 0.068*(b**2))
11link return { 'brightness': bright, 'filename': >>img_file }
12link
13linkdef orderByBrightness(files):
14link dataset= []
15link for f in files:
16link img_brightness = brightness(f)
17link dataset.append(img_brightness)
18link return sorted(dataset, key = lambda i: i>>['brightness'])
19link
20linkdef createCharFromImage(char):
21link W, H = (64,64)
22link img = Image.new('RGB', (W, H), color = (255, >>255, 255))
23link d = ImageDraw.Draw(img)
24link w, h = d.textsize(char)
25link fnt = ImageFont.truetype("./font2.otf", 70)
26link d.text(((W-w)/2,0), char, font=fnt, fill=(0,0,>>0))
27link img.save('characters/_{}_.jpg'.format(char))
28link
29linkcharacters = "$@B%8&>>WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft()1{}[]?-_>>+~<>i!lI;:,\"^`'. "
30link
31linkfor char in characters:
32link createCharFromImage(char)
33link
34linkimg_w = None
35linkfor i, char in enumerate(characters):
36link file = 'characters/_{}_.jpg'.format(char)
37link if i==0:
38link img_w = cv2.imread(file)
39link continue
40link img = cv2.imread(file)
41link img_w = cv2.hconcat([img_w, img])
42link
43linkcv2.imwrite('Characters.jpg', img_w)
1linklet mosaic;
2linklet symbol1;
3linklet myImage;
4linklet debug;
5linklet slider;
6linklet slider2;
7linkconst WIDTH_PIXEL = 64;
8linkconst HEIGHT_PIXEL = 64;
9linkconst NUM_IMAGES = 70;
10link
11link
12linkfunction preload() {
13link myImage = loadImage("/vc/docs/sketches/images/mandrill.png");
14link symbol1 = loadImage("/vc/docs/sketches/images/Characters.jpg");
15link mosaic = loadShader(
16link "/vc/docs/sketches/shaders/shader.vert",
17link "/vc/docs/sketches/shaders/hardwarePhotomosaic.frag"
18link );
19link}
20link
21linkfunction setup() {
22link slider = createSlider(1, 9, 1,1);
23link slider.position(10, 30);
24link slider.style('width', '100px');
25link slider2 = createSlider(0,5,3,1);
26link slider2.position(10,10);
27link slider2.style('width', '100px');
28link createCanvas(600, 600, WEBGL);
29link textureMode(NORMAL);
30link noStroke();
31link shader(mosaic);
32link mosaic.setUniform("image", myImage);
33link mosaic.setUniform("WIDTH_PIXEL", WIDTH_PIXEL);
34link mosaic.setUniform("NUM_IMAGES", NUM_IMAGES);
35link mosaic.setUniform("HEIGHT_PIXEL", HEIGHT_PIXEL);
36link debug = true;
37link mosaic.setUniform("debug", debug);
38link let img = symbol1;
39link mosaic.setUniform("symbol1", img);
40link}
41link
42linkfunction draw() {
43link const pow = Math.pow(10,slider2.value())
44link mosaic.setUniform("resolution", pow*slider.value());
45link background(33);
46link cover(true);
47link}
48link
49linkfunction cover(texture = false) {
50link beginShape();
51link if (texture) {
52link vertex(-width / 2, -height / 2, 0, 0, 0);
53link vertex(width / 2, -height / 2, 0, 1, 0);
54link vertex(width / 2, height / 2, 0, 1, 1);
55link vertex(-width / 2, height / 2, 0, 0, 1);
56link } else {
57link vertex(-width / 2, -height / 2, 0);
58link vertex(width / 2, -height / 2, 0);
59link vertex(width / 2, height / 2, 0);
60link vertex(-width / 2, height / 2, 0);
61link }
62link endShape(CLOSE);
63link}
64link
65linkfunction keyPressed() {
66link if (key === "d") {
67link debug = !debug;
68link mosaic.setUniform("debug", debug);
69link }
70link}
1linkprecision highp float;
2linkattribute vec3 aPosition;
3linkattribute vec2 aTexCoord;
4linkattribute vec4 aVertexColor;
5linkuniform mat4 uProjectionMatrix;
6linkuniform mat4 uModelViewMatrix;
7linkvarying vec4 vVertexColor;
8linkvarying vec2 vTexCoord;
9link
10linkvoid main() {
11link vVertexColor = aVertexColor;
12link vTexCoord = aTexCoord;
13link gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
14link}
1linkprecision mediump float;
2linkuniform sampler2D image;
3linkuniform sampler2D symbol1;
4linkuniform bool debug;
5linkuniform float resolution;
6linkuniform float NUM_IMAGES;
7linkuniform float WIDTH_PIXEL;
8linkuniform float HEIGHT_PIXEL;
9linkvarying vec2 vTexCoord;
10linkvarying vec4 vVertexColor;
11link
12linkfloat module( float x , float y ){
13link float flt_res = x-(y*(floor(x/y)));
14link return flt_res;
15link}
16link
17linkvoid main() {
18link vec2 symbolCoord=vTexCoord*resolution;
19link vec2 imageCoord=floor(symbolCoord);
20link symbolCoord=symbolCoord-imageCoord;
21link imageCoord=imageCoord*vec2(1.0)/vec2(resolution);
22link vec4 col=texture2D(image,imageCoord);
23link float brightness = dot(col.xyz, vec3(0.2126, 0.7152, 0.0722));
24link float temp=brightness*(NUM_IMAGES);
25link float level=floor(temp);
26link float scalingfactor = 1.0/NUM_IMAGES;
27link float y0=0.0;
28link float x0= module(level,NUM_IMAGES)*scalingfactor;
29link vec2 myCoord=(symbolCoord*vec2(1.0)/vec2(NUM_IMAGES,1))+vec2(x0,y0);
30link vec4 finalColor=texture2D(symbol1,myCoord);
31link gl_FragColor = debug?finalColor:col;
32link}
There are two sliders that allow configuring the resolution. The First Slider decide the pow(1,100,1.000,10.000,100.000).The Second Slider is a number from 1 to 10. This configuration lets the users visualize multiple resolutions that generate a variety of results
1linklet mosaic;
2linklet symbol1;
3linklet myImage;
4linklet debug;
5linklet slider;
6linklet slider2;
7linkconst WIDTH_PIXEL = 64;
8linkconst HEIGHT_PIXEL = 64;
9linkconst NUM_IMAGES = 70;
10link
11link
12linkfunction preload() {
13link myImage = createCapture(VIDEO);
14link myImage.hide();
15link symbol1 = loadImage("/vc/docs/sketches/images/Characters.jpg");
16link mosaic = loadShader(
17link "/vc/docs/sketches/shaders/shader.vert",
18link "/vc/docs/sketches/shaders/hardwarePhotomosaic.frag"
19link );
20link}
21link
22linkfunction setup() {
23link slider = createSlider(1, 9, 1,1);
24link slider.position(10, 30);
25link slider.style('width', '100px');
26link slider2 = createSlider(0,5,3,1);
27link slider2.position(10,10);
28link slider2.style('width', '100px');
29link createCanvas(600, 600, WEBGL);
30link textureMode(NORMAL);
31link noStroke();
32link shader(mosaic);
33link mosaic.setUniform("image", myImage);
34link mosaic.setUniform("WIDTH_PIXEL", WIDTH_PIXEL);
35link mosaic.setUniform("NUM_IMAGES", NUM_IMAGES);
36link mosaic.setUniform("HEIGHT_PIXEL", HEIGHT_PIXEL);
37link debug = true;
38link mosaic.setUniform("debug", debug);
39link let img = symbol1;
40link mosaic.setUniform("symbol1", img);
41link}
42link
43linkfunction draw() {
44link const pow = Math.pow(10,slider2.value())
45link mosaic.setUniform("resolution", pow*slider.value());
46link background(33);
47link cover(true);
48link}
49link
50linkfunction cover(texture = false) {
51link beginShape();
52link if (texture) {
53link vertex(-width / 2, -height / 2, 0, 0, 0);
54link vertex(width / 2, -height / 2, 0, 1, 0);
55link vertex(width / 2, height / 2, 0, 1, 1);
56link vertex(-width / 2, height / 2, 0, 0, 1);
57link } else {
58link vertex(-width / 2, -height / 2, 0);
59link vertex(width / 2, -height / 2, 0);
60link vertex(width / 2, height / 2, 0);
61link vertex(-width / 2, height / 2, 0);
62link }
63link endShape(CLOSE);
64link}
65link
66linkfunction keyPressed() {
67link if (key === "d") {
68link debug = !debug;
69link mosaic.setUniform("debug", debug);
70link }
71link}
1linkprecision highp float;
2linkattribute vec3 aPosition;
3linkattribute vec2 aTexCoord;
4linkattribute vec4 aVertexColor;
5linkuniform mat4 uProjectionMatrix;
6linkuniform mat4 uModelViewMatrix;
7linkvarying vec4 vVertexColor;
8linkvarying vec2 vTexCoord;
9link
10linkvoid main() {
11link vVertexColor = aVertexColor;
12link vTexCoord = aTexCoord;
13link gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
14link}
1linkprecision mediump float;
2linkuniform sampler2D image;
3linkuniform sampler2D symbol1;
4linkuniform bool debug;
5linkuniform float resolution;
6linkuniform float NUM_IMAGES;
7linkuniform float WIDTH_PIXEL;
8linkuniform float HEIGHT_PIXEL;
9linkvarying vec2 vTexCoord;
10linkvarying vec4 vVertexColor;
11link
12linkfloat module( float x , float y ){
13link float flt_res = x-(y*(floor(x/y)));
14link return flt_res;
15link}
16link
17linkvoid main() {
18link vec2 symbolCoord=vTexCoord*resolution;
19link vec2 imageCoord=floor(symbolCoord);
20link symbolCoord=symbolCoord-imageCoord;
21link imageCoord=imageCoord*vec2(1.0)/vec2(resolution);
22link vec4 col=texture2D(image,imageCoord);
23link float brightness = dot(col.xyz, vec3(0.2126, 0.7152, 0.0722));
24link float temp=brightness*(NUM_IMAGES);
25link float level=floor(temp);
26link float scalingfactor = 1.0/NUM_IMAGES;
27link float y0=0.0;
28link float x0= module(level,NUM_IMAGES)*scalingfactor;
29link vec2 myCoord=(symbolCoord*vec2(1.0)/vec2(NUM_IMAGES,1))+vec2(x0,y0);
30link vec4 finalColor=texture2D(symbol1,myCoord);
31link gl_FragColor = debug?finalColor:col;
32link}