Permutations of Images

We can’t only create permutations of numbers but of any data. In this notebook we’ll divide an image into 4 cells and store them as files. Then we’ll calculate all permutations of this 4 image files.

To deal with images, we’ll work with Pillow (a fork of PIL).

See readthedocs.io and automate the boring stuff for more on the library.

First we’ll have a look into some functionality of pillow, before we create the permutations.

Imports

# Install PIL / pillow
!pip install pillow
!pip install sympy
Requirement already satisfied: pillow in /home/m/miniconda3/envs/exp_book/lib/python3.11/site-packages (9.5.0)
Collecting sympy
  Using cached sympy-1.12-py3-none-any.whl (5.7 MB)
Collecting mpmath>=0.19
  Using cached mpmath-1.3.0-py3-none-any.whl (536 kB)
Installing collected packages: mpmath, sympy
Successfully installed mpmath-1.3.0 sympy-1.12
from PIL import Image
from IPython.display import display
import glob
from sympy.utilities.iterables import multiset_permutations

Load an image

# Create an Image object
img = Image.open('data/Doener.png')

# Inspect the file
print('size:', img.size)
print('mode:', img.mode)
print('format:', img.format)
size: (512, 512)
mode: P
format: PNG

Display an image

Display the image with the built-in IPython.display() function:

display(img)
_images/permutations_img_7_0.png

Geometrical transformations

display(img.transpose(Image.FLIP_LEFT_RIGHT))
_images/permutations_img_9_0.png
display(img.transpose(Image.FLIP_TOP_BOTTOM))
_images/permutations_img_10_0.png

Copy and Paste

img_copy = img.copy()
img_small = img.resize((256, 256))
img_copy.paste(img_small, (0, 0))
display(img_copy)
_images/permutations_img_12_0.png
img_copy = img.copy()
img_small = img.resize((256, 256))
i = 8
steps = (img.size[0] - img_small.size[0]) / i
steps = int(steps)
print('steps:', steps)
for i in range(i+1):
    img_copy.paste(img_small, (steps * i, steps * i))
display(img_copy)
steps: 32
_images/permutations_img_13_1.png

Cropping

# Original image.
display(img)
_images/permutations_img_15_0.png
# Cropped section.
display(img.crop((0, 0, 256, 12))) # Left, upper, right, lower pixel.
_images/permutations_img_16_0.png

Save an image

# Just as an example: flip it
img_flipped = img.transpose(Image.FLIP_LEFT_RIGHT)
# Save it
img_flipped.save('data/flipped.png')

Crop an image into 4 parts and save them

Here we’ll divide an image into a grid of 4 cells. We’ll save each.

# Load the image
img = Image.open('data/Doener.png')
width, height = img.size

for x in range(2):
    for y in range(2):
        
        left = x*(width/2)
        upper = y*(height/2)
        right = left+width/2
        lower = upper+height/2
        
        file_name = f"data/doener_part_{y}{x}.png"
        
        # crop the image and save it
        img_cropped = img.crop((left, upper, right, lower))
        img_cropped.save(file_name)
        
        display(img_cropped)
_images/permutations_img_20_0.png _images/permutations_img_20_1.png _images/permutations_img_20_2.png _images/permutations_img_20_3.png

Create an image out of 4 parts

We’ll use an iterator to iterate over a list of images. You may have a look at https://www.w3schools.com/python/python_iterators.asp

# Create an empty image
width, height = 512, 512
img = Image.new('RGB', size=((width, height)))

# Create a list of images
img_list = glob.glob('data/doener_*.png')
# Sort it
img_list.sort()
# Turn it into an iterator
img_iter = iter(img_list)

for x in range(2):
    for y in range(2):
        # Get the next file name
        file_name = next(img_iter)
        # Open the image
        img_part = Image.open(file_name)
        
        left = int(y*(width/2)) # Swap x and y because we've swapped
        upper = int(x*(height/2))  # it for the cropping as well
        
        # paste the partial image
        img.paste(img_part, ((left, upper)))
        
# Display the image
display(img)
_images/permutations_img_22_0.png

Put it into a function

def create_img_from_list_of_4(width, height, img_list, name, show=False):
    width, height = width, height
    
    # Create an empty image with given width and height
    img = Image.new('RGB', size=((width, height)))

    # Turn the list (input) into an iterator
    img_iter = iter(img_list)

    # Nested (2d) loop
    for x in range(2):
        for y in range(2):
            # Get the next file name
            file_name = next(img_iter)
            # Open the image
            img_part = Image.open(file_name)

            left = int(y*(width/2)) # Swap x and y because we've swapped
            upper = int(x*(height/2))  # it for the cropping as well

            # paste the partial image
            img.paste(img_part, ((left, upper)))
            
    # Save image
    img.save(name)
    
    # if show = True: display the image
    if show:
        display(img)

Create and store all permutations

# Create a list of images
img_list = glob.glob('data/perm_part_*.png')
print(img_list)
# Create a list of all permutations
permutations = list(multiset_permutations(img_list))
print(len(permutations))
for p in permutations[:4]:
    print(p)
['data/doener_part_10.png', 'data/doener_part_11.png', 'data/doener_part_00.png', 'data/doener_part_01.png']
24
['data/doener_part_00.png', 'data/doener_part_01.png', 'data/doener_part_10.png', 'data/doener_part_11.png']
['data/doener_part_00.png', 'data/doener_part_01.png', 'data/doener_part_11.png', 'data/doener_part_10.png']
['data/doener_part_00.png', 'data/doener_part_10.png', 'data/doener_part_01.png', 'data/doener_part_11.png']
['data/doener_part_00.png', 'data/doener_part_10.png', 'data/doener_part_11.png', 'data/doener_part_01.png']
# Iterate over the list and save every created image

for index, permutation in enumerate(permutations):
    # Call the function and insert a specific name to save each file
    name = f"data/img_permutations/img_{index}.png" # make sure the folder exists
    create_img_from_list_of_4(512, 512, permutation, name=name, show=True)
    print('\n')
_images/permutations_img_27_0.png

_images/permutations_img_27_2.png

_images/permutations_img_27_4.png

_images/permutations_img_27_6.png

_images/permutations_img_27_8.png

_images/permutations_img_27_10.png

_images/permutations_img_27_12.png

_images/permutations_img_27_14.png

_images/permutations_img_27_16.png

_images/permutations_img_27_18.png

_images/permutations_img_27_20.png

_images/permutations_img_27_22.png

_images/permutations_img_27_24.png

_images/permutations_img_27_26.png

_images/permutations_img_27_28.png

_images/permutations_img_27_30.png

_images/permutations_img_27_32.png

_images/permutations_img_27_34.png

_images/permutations_img_27_36.png

_images/permutations_img_27_38.png

_images/permutations_img_27_40.png

_images/permutations_img_27_42.png

_images/permutations_img_27_44.png

_images/permutations_img_27_46.png