Edit images with Jupyter and Python

Who needs to learn an image-editing application when you can do the job with open source tools you already know?
78 readers like this.
Polaroids and palm trees

Recently, my kid wanted to make a coloring page from a favorite cartoon. My first thought was to use one of the open source programs on Linux that manipulate images, but then I remembered I have no idea how to use any of them. Luckily, I know how to use Jupyter and Python.

How hard can it be, I figured, to use Jupyter for that?

To follow along, you need to have a modern version of Python (if you're a macOS user, you can follow this guide), then install and open Jupyter Labs, which you can learn more about here, and Pillow, a friendly fork of the Python Imaging Library (PIL), with:

$ python -V
Python 3.8.5
$ pip install jupyterlab pillow
# Installation process ommitted
$ jupyter lab

Imagine you want to make a coloring page with an image of a deer. The first step is probably to download a picture of a deer and save it locally. Beware of images with dubious copyright status; it's best to use something with a Creative Commons or other open access license. For this example, I used an openly licensed image from Unsplash and named it deer.jpg.

Once you're in Jupyter Lab, start by importing PIL:

from PIL import Image

With these preliminaries out of the way, open the image then look at the image size:

pic = Image.open("deer.jpg")
pic.size
(3561, 5342)

Wow, this is a bit of sticker shock—high-resolution pictures are fine if you want to make a delightful book about deer, but this is probably too big for a homemade coloring book page. Scale it waaaaaaay down. (This kindness is important so that this article loads fast in your browser, too!)

x, y = pic.size
x //= 10
y //= 10
smaller = pic.resize((x, y))

This reduced the scale of the image by 10. See what that looks like:

smaller

Beautiful! Majestic and remote, this deer should be a breeze for an edge-detection algorithm. Speaking of which, yes, that's the next step. You want to clean up the image so coloring will be is a breeze, and thankfully there's an algorithm for that. Do some edge detection:

from PIL import ImageFilter

edges = smaller.filter(ImageFilter.FIND_EDGES)
edges

This is probably the most important step. It removes all the extraneous details and leaves clear lines. The color is a little weird, but this is not a hard problem to solve. Split the image into its color bands, and choose the one where the lines are crispest:

bands = edges.split()
bands[0]

The lines are clear now, but this is not a good image to print because your printer will run out of ink, and your kid will not be happy coloring on black. So invert the colors. While you're at it, snap the colors to max-black or max-white to make the lines even crisper by using a lambda function call:

outline = bands[0].point(lambda x: 255 if x<100 else 0)
outline

The original image had a lot of nature that I mercilessly cleared. Now there's a lot of empty space, so crop the picture to the essentials:

outline.crop((10, 200, 300, 400))

All that's left is to save the picture as something easy to print, like a PDF:

outline.save("deer.pdf")

I'll let you figure out how to print from Linux.

Have fun making homemade coloring books for your kids!

What to read next
Tags
Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
Moshe has been involved in the Linux community since 1998, helping in Linux "installation parties". He has been programming Python since 1999, and has contributed to the core Python interpreter. Moshe has been a DevOps/SRE since before those terms existed, caring deeply about software reliability, build reproducibility and other such things.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.