Image processing |
Start by reading about working with bitmaps in Kotlin.
Sepia is a color-toning technique that makes a photo look as if it was taken in the early twentieth century. Here is a comparison of black-and-white versus sepia versions of the same photo:
Write a function sepia that will convert a photo to sepia and returns a new image (the function does not modify the input image):
fun sepia(img: BufferedImage): BufferedImage { // ... }For each pixel of the photo,
val v = (0.299 * red + 0.587 * green + 0.114 * blue).toInt()
Posterizing means to replace the colors in a photo with a rather small set of colors (maybe ten). To posterize a photo, you first make a list of allowed colors. Then you look at every pixel of the photo, and replace it by the color from the list that is most similar. Write a function posterize that performs the second step:
fun posterize(img: BufferedImage, colors: List<Int>): BufferedImage { // ... }(Again, your function returns a new image and does not modify the input image.)
To do this, you will need to measure the distance between two colors \((r_1, g_1, b_1)\) and \((r_2, g_2, b_2)\). The natural way to do this is to measure the distance like the (squared) Euclidean distance of three-dimensional vectors:
Write a function to compute the distance between two colors!
To test your function, you'll need to create a list of colors. Test first with a fixed list of colors like this:
val colorList = listOf(0xff0000, 0x00ff00, 0x0000ff, 0x000000, 0xffffff)
The result should like somewhat like this:
Then try other ways to select a color list. One possibility is to simple use a few random colors, for instance using this code:
val random = java.util.Random() fun randomColor(): Int = random.nextInt(0x1000000)
Write a function that generates \(k\) random colors:
fun randomColors(k: Int): List<Int> { // ... }
Here is what I got using 10 random colors (of course it will look different every time you run it):
Let's now consider the problem of selecting colors that are adapted to the photo you want to posterize. Here is a method for doing this (\(k\) is the number of colors we want to choose):
You can now use \(c_1, c_2, \ldots, c_k\) to posterize the photo. Write a function
fun selectColors(img: BufferedImage, k: Int): List<Int> { // ... }
How do newspapers print photos? Ink is black, paper is white—there is no "gray ink". And still newspapers can print photos.
Can you create a version of a photo that only uses black and white pixels, and still creates the impression of gray levels?
One idea would be to represent each pixel of the photo using a small block of pixels. Depending on how many pixels in this block you turn black, you can achieve the impression of different gray levels.
Here is an example of how I implemented this.
Image processing |