What is DIP, well I'll tell you what is it, DIP is Digital Image Processing, which take an image and process it whatever you like. And how did i ended up here, i used to work in the web for example like tinkering a server, build some feature, or fix a bug, you know the usual stuff. But as time move i suddenly realize how does image scale work, i often just use library and call .scale(px, py)
to scale an image. But i never understood what behind those function. So i try to challenge myself to build my own image scale and render the image with ASCII (for fun). So Project ASCII Renderer was born.
The step for building an ASCII Renderer are:
- Get The Image From Input
- Convert The Image to Grayscale Image
- Scale Down the Image (Since I'm gonna display it in the terminal)
- Show The Output By Render it With ASCII
The plan is using Go language since they already have build in color
to play with pixel. So i give it a go, by starting simple and what is simple mean here.
Grayscale Image
But why we convert the image to gray instead of use full colored image. Well when we want to render image to ASCII color like RGBA are not needed. What we need are the brightness color (usually represent with 0-255 int), this brightness color allow us to map each pixel to ASCII character.
Go already provide color.GrayModel.Convert()
so i use that function to convert my image to gray. Loop all pixel in image and each pixel call color.GrayModel.Convert()
and you get an image with gray color.
Scaling
For scaling, well when i look at the google they have many multiple way to scale an image and one of it is Nearest Neighbor Interpolation which it only took 2 point (x, y) and choose between two point.
Nearest Neighbor
How does Nearest Neighbor Interpolation work let's take a look. I have an image of 500 x 400 and i want to scale down the image to 200 x 150, first we need to find the scale factor from 500 -> 200 for width and 450 -> 150 for height
Scale Factor for width = 500/200 -> 2.5
Scale Factor for height = 450/150 -> 3
We find the Scale factor for width and height now what. Well it's actually simple just loop through each pixel, but which pixel that i should loop because there two image 500 x 400 and 200 x 150.
Of course the 200 x 150 image because we want to assign new pixel in this scale down image. In DIP we should never modified the image, you should create new empty image to prevent incorrect information in the pixel.
When inside the loop first thing you should do is find the original pixel. Remember we loop the image with 200 x 150 pixel not the original image, after we found original X and Y pixel we round the value.
This is where the nearest neighbor come... the rounding value, lets says i have X of 5.5. The computer must decided which pixel you must pick 5 or 6 because there's no way you pick the 5.5, pixel does not accept 5.5, same as Y if Y are... let's says 4.4, it have to pick 4 or 5.
So you have to pick, how to pick is your decision round down or round up or a new wacky way to round value, it's up to you. after you pick which value to use, get the color value in the original Image and set the value into your new image. and Done. you just build the Image Scale function.
Note*: a few consideration, you should think about type if you use static type language, int and float are matter because this can dramatically change your result. I'm not mean is not correct it just give different result.
Render
Render. Since We already already convert into Gray and have an image that scale down, we just need to render. But first we need a set of character to render it, to make it simple i just use what most people use " .:-=+*#%@"
this is what i often see. if we look the set of character it already pre-sort from light color to dark color the " " empty space represent the white color and the "@" represent the dark color. But still you can flip it if you want, it will only give different result.
So to render, you have to loop the image per pixel and this is the interesting part, you either can use normal if statement or you can use math to decide which character to use.
for if statement you have to set threshold for example color 0 to 50 you must use this " " character and if the color 50 - 75 you must use "." this character, etc.
if color > 0 && color < 50 {
print(" ")
}else if() {
} // other condition
Or you can use math example below:
index = x * len(chars) / 255
x = color number (0-255)
char = array of character
e.g:
150 * 10 / 255 -> we get 5.88 round it to 6
100 * 10 / 255 -> we get 3.99 round it to 4
255 * 10 / 255 -> we get 10
Conclusion
Ok, lets wrap this up. What did i learn about this, well i learn that math interesting just change of value can have different result, for example the math to get the index pre-sort ASCII character we can see that we got 5.88 value, with this you have to choose round it up or down if round up we get 6 which is "*" but we round down we get "+". The result will change in your Render.
As i write this, thing like scale image is a difficult topic but with enough time thing not that hard, it's hard because it's a first time for me to write that logic, but as i do it often and see the code itself i feel like... huh... i never thought i built this.
And Remember
You're not learning if you're not falling to difficulty
Leave a question or a comment if there's something wrong or missing some explanation
Top comments (0)