How to see Images the way Computer sees — Python Pandas tricks

Victor Grygorchuk
3 min readMar 21, 2021

Imagine you explain to a kid how a computer processes an image.

YOU: “The image is a bunch of numbers for the computer.”

KID: “How is it possible to see an image with numbers?”

YOU: “Well... There are numbers from 0 to 255, where 0 is dark and 255 is white, and to represent one dot on the image you need a number for red, green, and blue…”

You may do better, but it is still complicated.

The best way to explain is to show.

Python library pandas has a great instrument to bring a human and machine representation of the image as close as possible.

We downloaded a smiley emoji (link — no copyright infringement intended, Google said the image has the Creative Common License).

Get Python library Pillow to work with an image in a code.

from PIL import Image

Don’t be confused, we installed Pillow but we import PIL, as Pillow is a fork for the original PIL (and PIL is no longer supported).

Let’s start coding: img = Image.open('image.png')

This is how human see images: img.show()

Later we would like to print the image, perhaps, it’s good to downsize the image to something smaller, e.g. 32x32 pixels, as a big image might not fit our displays.

img = img.resize((32, 32), )

Right, the image is a bunch of numbers. The first step is to see those numbers. We do it with numpy :

import numpy as np

img_as_arr = np.asarray(img)
print(img_as_arr)

And result is:

[[[247 247 247 255]
[245 245 245 255]
[245 245 245 255]
...
[246 246 246 255]
[245 245 245 255]
[247 247 247 255]]
# and so on

I agree, it’s not excellent visualization for a kid. Let’s do better!

Print the shape of the image: print(img_as_arr.shape). As you can see the shape is (32, 32, 4), what means we have 32 by 32 pixels in 4 channels.

Print those 4 channels by the command: print(img.mode), what outputs us RGBA: Red, Green, Blue, Alpha.

We separate those channels into four different images:

red = img_as_arr[:,:,:1] # get 32x32 pixels and first color channel
green = img_as_arr[:, :, 1:2] # second channel for green
blue = img_as_arr[:, :, 2:3] # third channel for blue
alpha = img_as_arr[:, :, 3:] # forth for alpha

We’re almost there! The last step is to squeeze images into 2-d array. Now, if print any image shape, we get (32, 32, 1). We need to make it just 32 by 32, basically, what we want is a table of 32 columns and 32 rows.

red = np.squeeze(red, 2)
print(red.shape)
# output must be (32, 32)
blue = np.squeeze(blue, 2)
green = np.squeeze(green, 2)
alpha = np.squeeze(alpha, 2)

Let’s create a table of digits with pandas:

import pandas as pd

df_red = pd.DataFrame(red)
df_green = pd.DataFrame(green)
df_blue = pd.DataFrame(blue)
df_alpha = pd.DataFrame(alpha)

We’ve arrived at our final step before we can show results.

Now, we have the tables with numbers. How does it help to explain the concept of image with digits? We can paint each digit with appropriate color!

style_r = df_red.style.set_properties(**{'font-size': '8pt'}).background_gradient('Reds_r')
style_g = df_green.style.set_properties(**{'font-size': '8pt'}).background_gradient('Greens_r')
style_b = df_blue.style.set_properties(**{'font-size': '8pt'}).background_gradient('Blues_r')
style_a = df_alpha.style.set_properties(**{'font-size': '8pt'}).background_gradient('Greys')

When we use IPython/ Jupiter Notebook we can simply look at each style_* to see the result.

red zoomed

If we work in any other IDE or in plain notepad — just save the style_* to the html:

with open('image.html', 'w') as html:
html.write(style_r.render())
html.write(style_g.render())
html.write(style_b.render())
html.write(style_a.render())

Have a fun with explaining things (I tried to explain it to my wife, but she replied it’s boring :-)

Find here the full code https://gist.github.com/VicGrygorchyk/b2af7cd939a4ab887dcbd875b6d7bc7d

--

--