Note: Source code is available on Github — it’s open source and anyone is welcome to use it themselves or contribute! As a disclaimer, I want to say there are absolutely better ways to approach image processing, but this is meant to be educational and exploratory of pixel manipulation itself. Cheers!

In my upcoming talk at KotlinConf, I’m demonstrating crosscutting with image processing— along the way I discovered some neat things about functional programming. Today, we get to go through all the things I learned by failing repeatedly (and learning from those failures). I’ll be using TornadoFX as an easy vehicle to facilitate this discussion. For anyone that might want to try out image processing themselves, feel free to refer to an old Kotlin Thursday to get set up with IntelliJ.

Image processing is the ability to pass filters in images by analyzing their pixels. In a very tiny paper I cowrote with while completing research at Grinnell College, we used image processing as a way for people to develop computational thinking through a social outlet creating math-over-images. For this reason, I’ve always found that playing with pictures is a great way to visualize algorithms and create a more tangible conversation on processing.

First things first

Choose any photo, or choose this one and save it in a resource folder in your project. But whatever you do, make sure it’s square — unless you feel like doing math in your head today. I just kept my images 400px each side.

As always, make sure you can spin something up quick — I used the MainView class generated with the TornadoFX plugin.

Once you’re able to render a quick component, we can go ahead and get into it. To be able to play with the pixels in your image, you’ll have to pull the photo URI into an image variable and create a writeable image of it. The JavaFX WritableImage allows a canvas while storing the URI as an Image gives us access to the PixelReader and PixelWriter. Super convenient!

Always run a check to make sure everything works!

We’ll start with something easy — making the entire image duller. Of course, the ColorAdjust would meet these needs and be more performant, but this is for the sake of just getting something to work and we’ll build from there. Now that we have access to our pixels, we simply need to iterate through and pass a filter through every pixel. Within your MainView class go ahead and try out this function.

before and after

And of course, we can change out color.desaturate() for color.brighter() for the opposite effect.

Now we got the hang of how to grab these pixels and do something with them, lets expand this to operational pixel manipulation. We will now switch to pure black and white pixel images. I tried to do this with colors, but it’s a lot more difficult (impossible) to work with RGB values as opposed to just black or white.

Pixel Math!

One of the core concepts of computer operations is and , or , and not . Let’s start with binary numbers.

We can apply the same concept with numbers. If we denote white to be 0 and black to be 1, we can write code to reflect binary math. We’ll call these primitive filters.

Now that we have these color operations, we’re going to start sending two images through and analyze their respective pixels so that we can apply the following primitive functions to create a new image.

The result?

Why yes. Terrifying

And of course, there’s a lot more we can do:

We already saw how to apply the orFilter to two images — we can also subtract the difference of one image for another. topEdge takes the same image, shifts every single pixel up by 1 and leaves one white pixel row at the bottom. Then, we compare the results to the original image and inverse the results.

Interested in image processing yourself? I wrote this example up in Kotlin, but you’re welcome to try the same thing in other languages you might feel comfortable with, whether it be C, Java, or even Lisp. This is only a background sneak peek for my talk— since I am only using image processing as a vehicle to visually demonstrate crosscutting, I thought I’d love to get a chance to talk about the mechanics behind it!

There’s a lot of other amazing topics I’m looking forward to checking out at KotlinConf, and be sure to check out last year’s talks on JetBrainsTV. I’ll see you all in Amsterdam in October!