0

I am busy writing something to manipulate a image and paste other images onto it.

I am trying to change the background and the hat on a dog to various others and output multiple files with randomly generated images. The input images come from folders (backgrounds and hats). As we take pictures and copy them into the folder called background, I want to be able to run my Python script to change the background of the dog by picking a random image from the backgrounds folder. I want to be able to do the same with images in the hats folder. Will add more folders over time, but that's another day's question.

So far, I am able to paste items onto the main image. I have multiple PNG files in the folders and I get three images out, but all three images are the same. My code only seems to load one background and one hat.

Please help on how I can paste random images from the two folders onto my main image of the dog. Dog stays static, but backgrounds and hats will change. The options should be as many as the combinations can allow. So three folders with three options each will have alot of combination options. I have set the limit to three, but each time the images should render different combinations.

My code so far:

import glob
from PIL import Image

def main():

    q = 0
    hat_image = glob.glob("hats/*.png")
    for image in hat_image:
        with open(image, 'rb') as file:
            hat = Image.open(file)

    bg_image = glob.glob("backgrounds/*.png")
    for image in bg_image:
        with open(image, 'rb') as file:
            bg = Image.open(file)

    try:
        while q < 3:
            img = Image.open("base.png")
            img.paste(hat, (276, 176), hat)
            # mouth = Image.open("./mouth/mouth1.png")
            img.paste(bg, (226,476), bg)
            img.save("final{}.png".format(q), "PNG")
            q += 1

    except IOError:
        pass

if __name__ == "__main__":
    main()
HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • Please provide a truly minimal [mre]. – martineau Aug 15 '21 at 19:32
  • https://stackoverflow.com/questions/306400/how-can-i-randomly-select-an-item-from-a-list How can I randomly select an item from a list? : example add import random, remove for loops , use with open(random.choice(hat_image), 'rb') as file: and with open(random.choice(bg_image), 'rb') as file – pippo1980 Aug 15 '21 at 19:44
  • I will try and provider a truly minimal example. – Robert Jooste Aug 16 '21 at 10:23

1 Answers1

0

If you want to have all possible combinations of background and hat images, you simply need to iterate accordingly, i.e. using nested for loops:

import glob

from PIL import Image

bg_filenames = glob.glob('backgrounds/*.png')
hat_filenames = glob.glob('hats/*.png')
dog_image = Image.open('dog.png')

for bg_filename in bg_filenames:
    for hat_filename in hat_filenames:
        output_image = Image.open(bg_filename)
        output_image.paste(dog_image)
        output_image.paste(Image.open(hat_filename))
        output_image.save('output/{}_{}.png'.format(
            bg_filename.split('\\')[1].split('.png')[0],
            hat_filename.split('\\')[1].split('.png')[0]
        ))

print(glob.glob('output/*.png'))
# ['output\\alley_baseball.png',
#  'output\\alley_cowboy.png',
#  'output\\alley_fedora.png',
#  'output\\garden_baseball.png',
#  'output\\garden_cowboy.png',
#  'output\\garden_fedora.png',
#  'output\\park_baseball.png',
#  'output\\park_cowboy.png',
#  'output\\park_fedora.png']

If you actually want a single image per execution with randomly chosen background and hat, simply use randint w.r.t. the amount of background and hat images:

import glob

from PIL import Image
from random import randint

bg_filenames = glob.glob('backgrounds/*.png')
hat_filenames = glob.glob('hats/*.png')
dog_image = Image.open('dog.png')

bg_filename = bg_filenames[randint(0, len(bg_filenames)-1)]
hat_filename = hat_filenames[randint(0, len(hat_filenames)-1)]

output_image = Image.open(bg_filename)
output_image.paste(dog_image)
output_image.paste(Image.open(hat_filename))
output_image.save('output/{}_{}.png'.format(
    bg_filename.split('\\')[1].split('.png')[0],
    hat_filename.split('\\')[1].split('.png')[0]
))

print(glob.glob('output/*.png'))
# ['output\\alley_cowboy.png',
#  'output\\garden_baseball.png',
#  'output\\garden_fedora.png']                 After three runs

For both versions, you can easily add more folders like shoes or gloves or whatever.

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19042-SP0
Python:        3.9.6
PyCharm:       2021.2
Pillow:        8.3.1
----------------------------------------
HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • Thanks, That makes sense. If I were to limit the amount of output files, I would use a while loop? ie. I don't want it run run and create 1000 pictures. I tried your example, but get error. ``` Traceback (most recent call last): File "example.py", line 17, in bg_filename.split('\\')[1].split('.png')[0], IndexError: list index out of range ``` I haven't had time to debug it yet. Will investigate this later. – Robert Jooste Aug 16 '21 at 09:53