Home > Net >  How can I merge several images via loop using the information of a dataframe on Python?
How can I merge several images via loop using the information of a dataframe on Python?

Time:12-30

I have the following dictionary:

the_dictionary_list = {'Fondo': ['Oceano.png'],
                       'Cuerpo': ['Cuerpo_cangrejo.png'], 
                       'Ojos': ['Antenas.png', 'Pico.png', 'Verticales.png'],
                       'Color': ['Amarillo.png', 'Blanco.png', 'Rojirosado.png', 'Turquesa.png', 'Verde_oscuro.png', 'Zapote.png'], 
                       'Pinzas': ['None', 'Pinzitas.png', 'Pinzotas.png', 'Pinzota_pinzita.png'], 
                       'Puas': ['None', 'Arena.png', 'Marron.png', 'Purpura.png', 'Verde.png']}

To get each possible permutation without repetition in a specific order (i.e. cartesian products) I use the following code:

import itertools as it

AllKeysNames = ['Fondo', 'Cuerpo', 'Ojos', 'Color', 'Pinzas', 'Puas']
Combinations = list(it.product(*(the_dictionary_list[Name] for Name in AllKeysNames)))
print(f'{Combinations}')

Then, for saving each iteration to a dataframe such as it throws an output like this one:

   |            Permutations            |                                    FilePermutations                                      |
  0|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png None None                         |
  1|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png None Arena.png                    |
  2|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png None Marron.png                   |
  3|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png None Purpura.png                  |
  4|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png None Verde.png                    |
  5|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png Pinzitas.png None                 |
  6|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png Pinzitas.png Arena.png            |
  7|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png Pinzitas.png Marron.png           |
  8|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png Pinzitas.png Purpura.png          |
  9|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Antenas.png Amarillo.png Pinzitas.png Verde.png            |
  .
  .
  .
358|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Verticales.png Zapote.png Pinzota_pinzita.png Purpura.png  |
359|Fondo Cuerpo Ojos Color Pinzas Puas |Oceano.png Cuerpo_cangrejo.png Verticales.png Zapote.png Pinzota_pinzita.png Verde.png    |

I use the following code:

new = [' '.join(x) for x in 
                        it.product(*(the_dictionary_list[Name] for Name in AllKeysNames))]

df = pd.DataFrame({'Permutations':" ".join(AllKeysNames), 'FilePermutations':new})

Now, suppose that the above program is located in the same path (i.e. r"./") in which coincidentally the following folders are also located:

Folders

These folders only contain file images, which also coincidentally have the same name of those values in the_dictionary_list.

As the df variable has stored the right order in which these images must be merged besides the filenames and foldernames, and also the total amount of permutations

How could this program take that information from the df and use the functions of:

Image.open(r"./")

Image.alpha_composite()

resize((350, 350), resample=Image.NEAREST

from Python Imaging Library (PIL)

To produce the new merged images in the order in which the df shows it?

Notes:

The image filenames can be equal to the respective index of df.

As the None element doesn't actually exist in the folders, when needed, the program would have to merge the previous images with the next one (i.e. not calling Image.open(r"./") nor Image.alpha_composite() when 'None' appears and continue to do so with the next element)

Only after having merged the file images of a row, it would call resize((350, 350), resample=Image.NEAREST for then saving the final output using .save(r"./Test/str(Index(i)) ".png") and then repeat the process until it has reached the final index of df

CodePudding user response:

The following solution was built by @christian from stackoverflow en español, the translation of his answer is the following:

Pandas DataFrames have a method called iterrorws() that returns a generator and we can iterate through it, this returns the row itself as a tuple that contains two objects, the first one is the index of the row and the second one is a Pandas Series that contains the values of the next columns.

I would not recommend joining the names with a , you can simply leave them in list format since later we will need them as lists again and you can save that conversion to a list by avoiding using ' '.join(x).

for i, per in df.iterrows(): 
    images = per["FilePermutations"].split(" ")
    files = per["Permutations"].split(" ")

With this we are obtaining the value of the respective column and we convert it back to a list with the help of the split method. Once we have this we can move on to create the new image that is the result of joining all the images specified in the images list. For this, we must first know the directory of each image and "coincidentally" the first element of files list is the directory where the image of the first element of the images list is located, and so on for each of the images. It happened to use the zip() function that matches each of those elements (in case a list has fewer elements, it will only match up to the smallest list and will not include the others, in case there is that scenario you can use the zip_longest function from itertools module) . With that we would already have the path of the image, we would only have to open it, combine it and at the end of all resize it and save it.

for i, per in df.iterrows():
    images = per["FilePermutations"].split(" ")
    files = per["Permutations"].split(" ")
    result_image = None #aquí se almacenará la imagen resultante 

    for direc, img in zip(files, images): #iteramos
        if img=="None": continue #si es None omitimos

        path = f"{direc}/{img}" #definimos la ruta donde se encuentra la imagen
        
        #en la primera iteración no habrá imagen inicial por lo que no podrá combinarse con otra
        # por lo que asignamos la imagen
        if result_image == None: 
            result_image = Image.open(f"./{path}")
        else: #combinamos la imagen
            img2 = Image.open(f"./{path}")
            result_image = Image.alpha_composite(result_image, img2)
    # redimensionamos y guardamos
    result_image = result_image.resize((350, 350), resample=Image.NEAREST)
    result_image.save(f"./Test/image_{i}.png")

This will combine all the specified images in each row and save them to the specified path. As you have seen there is not much magic in this, just a couple of for loops, the first to iterate through the rows and the second to create the path and get the images. In each iteration of the second for the result of result_image is overwritten so that it always contains the result of the combination of the current image and the previous one, in this way all the images are mixed, obviously those that do not exist marked as 'None' are omitted

This answered my question incredibly well.

  • Related