Rename images keeping the old name and adding prefix which corresponds to the order of a list

Question:

I have a list
List=["cat", "dog", "horse", "",...]
and I have images in ./images/folder/ which contains images files:

image0.png
image100.png
image2.png
...

Note images are not ordered in folder and os.listdir(path) show:

'image118.png'
'image124.png'
'image130.png'
...

My expectation is to receive files with these names.

image0_cat.png
image1_dog.png
image2_horse.png
...

This is my current code:

    import os
    path= './images/folder/'
    
    for label, filename in zip(my_label,os.listdir(path)):
        if os.path.isdir(path):
            os.rename(path + "/" +filename, path + "/" +filename + "_" + str(label) + ".png")

But the output is different than my expectations.

Output:

image0.png_horse.png
image1OO.png_horse.png
image2.png_cat.png
...
Asked By: semjad

||

Answers:

Use filename.split(".")[0] to get the root of your filename. Inside your code it would be

for label, filename in zip(my_label,os.listdir(path)):
    if os.path.isdir(path):
        name = filename.split(".")[0]
        os.rename(path + "/" + filename, path + "/" + name + "_" + str(label) + ".png")
Answered By: MarionCoutarel

If you know that the name of the images is always image<nb>.png, with ranging from 1 to len(my_label) without interruptions then you can generate the names directly instead of scanning through the folder:

for i, label in enumerate(my_label):
    filename = f"image{i+1}"
    old_file = os.path.join(path, filename + ".png")
    new_file = os.path.join(path, filename + f"_{label}.png")
    os.rename(old_file, new_file)

where os.path.join is the preferred way to actually generate file paths (it takes into account the "/", and different OS systems)

Otherwise, you will need to first parse the numbers from the list of files:

numbers = []
for image in os.listdir(path):
    number = os.path.basename(image)[len("image"):-len(".png")]
    numbers.append(int(number))

then you can sort that list:

sorted_numbers = sorted(numbers)

And finally, you can iterate through that list, to generate the filenames (that you know should exist), similarly to the previous method:

for number, label in zip(sorted_numbers, my_label):
    filename = f"image{number}"
    old_file = os.path.join(path, filename + ".png")
    new_file = os.path.join(path, filename + f"_{label}.png")
    os.rename(old_file, new_file)

Assuming that you have the right number of labels for your images.

Answered By: Florent MONIN

You can use this snippet:

import os
from pathlib import Path

path = './images/folder/'
my_label = ["cat", "dog", "horse", "",...]

for label, filename in zip(my_label, os.listdir(path)):
    if os.path.isdir(path):
        fn = Path(filename)
        os.rename(os.path.join(path, filename),os.path.join(path, f"{fn.stem}_{label}{fn.suffix}"))

This code is little more universal because you use original extension instead hardcoded ".png". You can read more about pathlib here: docs

Answered By: JacekK
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.