Star

Created With

linkASCII ART

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.

ascii_art_hardware.js
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

ascii.vert
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}

ascii.frag
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}

linkTry it with your own camera

Now you can try these filters with your own camera.

linkComparison with Software implementation

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.

ASCII ARTTry it with your own cameraComparison with Software implementation

Home

Workshopschevron_right
Software Image & Video Processingchevron_right

Problem Statement and Background Image and Video filters Image Photographic-Mosaic Ascii art

Kernel (Image processing)chevron_right

Conclusions and References

Hardware Image & Video Processingchevron_right

Problem Statement and Background Image and Video filters Ascii art Photo Mosaic

Kernel (Image processing)chevron_right

Conclusions and References

Renderingchevron_right

Computer Graphics HCI

P5 Code Snippetschevron_right
Peoplechevron_right