Problem Statement and Background Image and Video filters Ascii art Photo Mosaic
This section was based on the code of the following url https://www.shadertoy.com/view/lssGDj?ref=dtf.ru of shadertoy.
ASCII ART has been used in multiple situations for transforming videos and images to ascii characters in areas such as art, marketing or images analysis, but that kind of tasks are complex and can consume a lot of resources. That's the reason why this kind of tasks can be preferable done using shaders.
The implementation of the shader starts by the segmentation of the image on blocks of 8x8, then we take the upper left pixel of that segment and extract its level of brightness. With that level of brightness we can determine what character do we need to use depending on the density of the character, then we encode that character by a number which represents a bit of size 25 (5x5), because we left blank spaces at the left and right of the block, which encodes on which pixels do the character will have a brightness of 1 and on which pixels it will have 0.
As the shader iterates pixel by pixel we are sending the (x,y) coordinate, the block and the number that encodes the character of the block to a function that checks if the position of the pixel is encoded as 1 in the character number and returns the corresponding value so that the expected texture is created pixel by pixel on the gl_FragColor vector. The result of the fragment shader is then used as a texture of a 2D plane, thus generating the desired result.
1linklet asciiShader;
2linklet shaderTexture;
3link
4link
5linkfunction preload() {
6link img = loadImage('/vc/docs/sketches/lenna.png');
7link video = createVideo(['/vc/docs/sketches/fingers.mov', '/vc/docs/sketches/fingers.webm']);
8link asciiShader = loadShader('/vc/docs/sketches/ascii.vert', '/vc/docs/sketches/ascii.frag');
9link video.hide();
10link}
11link
12linkfunction setup() {
13link createCanvas(768, 393, WEBGL);
14link shaderTexture = createGraphics(393, 393, WEBGL);
15link shaderTexture.noStroke();
16link
17link video.loop();
18link noStroke();
19link}
20link
21linkfunction draw() {
22link shaderTexture.shader(asciiShader);
23link asciiShader.setUniform('tex', img);
24link texture(shaderTexture);
25link shaderTexture.rect(0,0,393,393);
26link rect(-393,-393/2.0,393,393)
27link asciiShader.setUniform('tex', video);
28link texture(shaderTexture);
29link shaderTexture.rect(0,0,393,393);
30link rect(0,-393/2.0,393,393)
31link}
32link
1link#ifdef GL_ES
2linkprecision mediump float;
3link#endif
4link
5linkattribute vec3 aPosition;
6linkattribute vec2 aTexCoord;
7link
8linkvarying vec2 vTexCoord;
9link
10linkvoid main() {
11link vTexCoord = aTexCoord;
12link
13link vec4 positionVec4 = vec4(aPosition, 1.0);
14link positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
15link
16link gl_Position = positionVec4;
17link}
1link#ifdef GL_ES
2linkprecision mediump float;
3link#endif
4link
5linkuniform sampler2D tex;
6link
7linkint getBit(int n, int a) {
8link float value = float(n);
9link for(float i = 27.0; i >= 0.0; i -= 1.0) {
10link float val = pow(2.0,i*1.0);
11link
12link if (val <= value) {
13link value -= val;
14link if(i == float(a)) return 1;
15link }
16link }
17link return 0;
18link}
19link
20linkfloat character(int n, vec2 p)
21link{
22link p = floor(p*vec2(4.0, -4.0) + 2.5);
23link if (clamp(p.x, 0.0, 4.0) == p.x)
24link {
25link if (clamp(p.y, 0.0, 4.0) == p.y)
26link {
27link int a = int(floor(p.x+0.5) + 5.0 * floor(p.y+0.5));
28link if (getBit(n,a) == 1) return 1.0;
29link }
30link }
31link return 0.0;
32link}
33link
34linkvoid main() {
35link vec2 pix = gl_FragCoord.xy;
36link pix.y = 393.0*2.0 - pix.y;
37link vec2 resol = vec2(393.0*2.0, 393.0*2.0);
38link vec3 col = texture2D(tex, floor(pix/8.0)*8.0/resol).rgb;
39link
40link float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;
41link
42link int n = 4096; // .
43link if (gray > 0.2) n = 65600; // :
44link if (gray > 0.3) n = 332772; // *
45link if (gray > 0.4) n = 15255086; // o
46link if (gray > 0.5) n = 23385164; // &
47link if (gray > 0.6) n = 15252014; // 8
48link if (gray > 0.7) n = 13199452; // @
49link if (gray > 0.8) n = 11512810; // #
50link
51link vec2 p = mod(pix/4.0, 2.0) - vec2(1.0);
52link
53link col = vec3(character(n, p));
54link
55link gl_FragColor = vec4(col, 1.0);
56link}
Now you can try these filters with your own camera.
When we measure the framerate of both implementations we found an improvement 448% in the frameRate, on the software implementation the value of the frameRate was around 8.28 frames per second, while in the hardware implementation we have 45.45 frames per second on average. Additionally the lag on the software implementation video is evident and detectable for the human sight, while in the hardware implementation the fluency is evident.
Problem Statement and Background Image and Video filters Ascii art Photo Mosaic