top of page
  • doctorsmonsters

Manipulate Images in Bulk for Your NFT Collection



While coming up with an NFT collection, it’s possible that you might have to manipulate the entire collection in bulk. Python makes it very easy. Say hello to the Pillow (PIL) library. It is an acronym for Python Image Library. Let’s import it. We will also need the OS library for accessing the list of files in the folder:

import PIL
import os
from PIL import Image

Let’s define our input directory, the directory where all the images are, and the target folder, where the processed images are saved.

target = r'manipulated'
source = r'images'

Using OS library, we load all the filenames of the images in our source folder and save them to a list.

files = os.listdir(source)

Since we are doing think in bulk, it’s simple, we just need to pick a function, iterate over the list, picking a filename, loading the file, calling the desired function on it and saving the modified image into the target folder.

for file in files:
    img = Image.open(source+"/"+file)
    img = <desired function here for image manipulation>
    img.save(target+"/"+file)

Let’s load the first image in the folder and display it, we can then also use it to try our functions.

test_image = Image.open(source+"/"+os.listdir(source)[0])

Let’s display the last image. You can use test_image.show() to view the image, but for jupyter notebook, display(test_image) will show the image in the notebook instead of using system viewer.

display(test_image)


Resizing:

You can specify the width(x) and height(y) of the image and use the resize function, which takes the the x and y as parameters.

x=500
y=500for file in files:
    img = Image.open(source+"/"+file)
    img = img.resize((x,y))
    img.save(target+"/"+file)

You could also resize them to a certain percentage of the original size. However if you want all images to be the same size, then try to avoid this, as this will resize them based on the percentage of the original size and not necessarily make them the same size. However, if you know that they are already the same size, you can reduce the size by a certain percentage. For example, if you want to reduce them by 50%, you define a factor, representing the percentage, so for 50% it would be 0.5, and then multiply each dimension by that.

x=500*factor
y=500*factor

Since the number are floats, we also have to convert them to integers.

for file in files:
    img = Image.open(source+"/"+file)
    img = img.resize((int(x),int(y)))
    img.save(target+"/"+file)

Cropping:

The pillow library also provides us with the crop function. It requires four parameters, each of which the pixel value on each side where the cropped image starts/ends. For example, if we have an image that is a square with x=500 and y=500 and we want to crop out 10 pixels on each side. The top edge will start from the 5th pixel, so top=5, similarly, the left edge will start from the 5th pixel so left=5. The bottom edge will end 5 pixels before the original image’s end so it would be bottom=500–5=495. Similarly, the right edge will end 5 pixels before the end of the original image’s right edge, so right=500–5=495. Lets load the image’s dimensions first.

width, height = test_image.sizeleft =5
top = 5
right = 495
bottom = 495
 

im1 = test_image.crop((left, top, right, bottom))
display(im1)


Notice that the image is cropped however most of the image is empty. This because the original image was smaller than 500x500. But the given parameters went beyond the dimensions of the image therefore the function filled the image with empty pixels. So if you want to avoid this, resize the image first and then crop.

x=500
y=500im1 = test_image.resize((x,y))
im1 = im1.crop((left, top, right, bottom))
display(im1)

In order to crop the entire collection, you iterate over the list of files names and apply the cropping to all the images. Assuming all the images are of the same size, we load the dimensions out of the iterations.

for file in files:
    img = Image.open(source+"/"+file)
    img = img.crop((left, top, right, bottom))
    img.save(target+"/"+file)


In order to crop the entire collection, you iterate over the list of files names and apply the cropping to all the images. Assuming all the images are of the same size, we load the dimensions out of the iterations.

for file in files:
    img = Image.open(source+"/"+file)
    img = img.crop((left, top, right, bottom))
    img.save(target+"/"+file)

Rotation

Just like crop and resize, the rotate function is pretty intuitive. It takes four parameters however 3 of them are set to 0 by default, you need to specify one, the angle by which you want the image to be rotated. The image is rotated counter-clockwise.

im2 = test_image.rotate(45)
display(im2)


As you can see, the image is rotated while the size has remained the same. If you want the image to be resized (or expanded) such that it the picture is not cropped, you can pass on another parameter expand = 1. By default, expand is set to 0.

im2 = test_image.rotate(45, expand=1)
display(im2)


Now we can iterate over all the images and rotate them.

for file in os.listdir(source):
    img = Image.open(source+"/"+file)
    img = img.rotate(45, expand=1)
    img.save(target+"/"+file)

There is a lot more that one can do with the pillow library, this was just a basic introduction to how to do basic manipulation of images in bulk.

Post: Blog2_Post
bottom of page