Image to ASCII
Explanations
File Input
The drag-image-here area is essentially just a canvas element.
When a valid image file is given it'll render it to the canvas.
The placeholder is just text rendered with canvas.getContext("2d").fillText()
Auto Colour picker
If compressed mode is used, the image is split into "chunks" to get the colour.
If full-image mode is used, then the colours are just directly taken from
each individual pixel.
Colours that are close-enough to being greyscale are interpereted as white (#FFFFFF).
Colours with an alpha below 127 or value below 50 are ignored. The colours
are put into an array and sorted by frequency.
The top 9 are chosen (bcs thats the limit on fastfetch).
Resample Method
This just changes how the rendering and colour-picking works.
| Method | |
|---|---|
| Averaged | Gets the RGB values from all the colours in a chunk and finds the average (mean). |
| Most Frequent | Picks the most common colour from a chunk. If multiple colours have equal frequency, the top-left most colour is used. |
Rendering
The image gets split into chunks based off the
width and height.
The colour of the chunk gets matched against the
list of colours in the input area and the closest one is chosen.
The ASCII character chosen is based off the colours HSV value.
Edge detection
See here
TL;DR do some math to figure out how much colour changes and in what direction
For each pixel in the image (excluding outer-most edges), get the 8
neighbouring pixels (top-left,top,top-right,right, etc.) and convert
them to greyscale, multiply neighbours with the sobel operator kernels,
then use that to get the magnitude and direction
Equations
(and/or pseudocode)
Chunks
chunk width = image width / input width
chunk height = image height / input height
Is Grey Enough
PARAMS = rgb, hsv
IF r == g AND g == b:
RETURN true
IF s < 10:
RETURN true
IF v < 15:
RETURN true
IF s + v < 100:
RETURN true
ELSE:
RETURN false
Colour Distance (HSV)
PARAMS = hsv1, hsv2
hd (hue distance) = min(abs(h1 - h2), 360 - abs(h1 - h2))
sd (saturation distance) = abs(s1 - s2)
vd (value distance) = abs(v1 - v2)
RETURN 50 * hd + 30 * sd + 20 * vd
Size adjust
PARAMS = input width
ratio = input width / new image width
height = new image height * ratio
RETURN height / 2
height is divided by 2 as characters in most fonts have heights that are double
their width Sobel kernel multiplication thing
PARAMS = x, y # pixel coordinates
sobelX = [-1, 0, 1, -2, 0, 2, -1, 0, 1];
sobelY = [-1, -2, -1, 0, 0, 0, 1, 2, 1];
gx = 0
gy = 0
FOR ky = -1; ky <= 1; ky++:
FOR kx = -1; kx <= 1; kx++:
ox = x + kx
oy = y + ky
pixel = pixels[ox][oy]
grey = greyscale(pixel) # gets the V from HSV
kernel_index = (ky + 1) * 3 + (kx + 1)
gx += grey * sobelX[kernel_index]
gy += grey * sobelY[kernel_index]
RETURN gx, gy
Magnitude
PARAMS = gx, gy
magnitude = square_root(gx^2 + gy^2)
RETURN magnitude
Direction
PARAMS = gx, gy
direction = atan2(gx, gy)
RETURN direction
atan2 is "The angle in radians (between -π and π, inclusive) between the positive x-axis and the ray from (0, 0) to the point (x, y)." (according to mdn)
Credits
Originally based on raffimolero/ascii
Edge detection based off ascii-view and Real-Time-Edge-Detection-Viewer