如何使用 Python 上的数据帧信息通过循环合并多个图像?

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

我有以下词典:

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']}

为了获得每个可能的排列而不按特定顺序重复(即笛卡尔积),我使用以下代码:

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}')

然后,为了将每次迭代保存到数据帧中,它会抛出如下输出:

   |            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    |

我使用以下代码:

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

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

现在,假设上述程序位于同一路径(即r"./"),巧合以下文件夹也位于其中:

这些文件夹只包含文件图像,巧合的是the_dictionary_list中的那些值同名。

由于 df 变量存储了正确的顺序,除了文件名和文件夹名之外,还必须合并这些图像,以及排列的总数

这个程序如何从 df 中获取信息并使用以下函数:

Image.open(r"./")

Image.alpha_composite()

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

来自 Python Imaging Library (PIL)

要按照 df 显示的顺序生成新的合并图像?

备注:

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

以下解决方案由 @christianWhosebug en español 构建,他的答案翻译如下:

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

这非常好地回答了我的问题。