Search code examples
image-processingscriptingimagemagickphotoshop

How can I automatically generate composite images by layering source images randomly?


I am working on a personal creative project and need help finding or creating a script that will randomly select 4 images from 4 different folders, stack them and create a series of png composite images as an output. Extra points if the images of each folder can be assigned to a fixed layer (so, for example, images from the "backgrounds" folder will always appear in the back). Note: I don't know how to code.


Solution

  • Updated

    Ok, I have updated the script as follows:

    1. It produces 10 output files - you can change it by altering NFILES at the start
    2. The output files will not overwrite each other between runs, the next free name will be used starting with output-0.png then output-1.png and so on.
    3. I have corrected the alpha compositing to match your files.

    Script follows...

    #!/bin/bash
    
    # Number of output files - edit freely :-)
    NFILES=10
    
    # Build arrays of filenames in each layer, assume directories are "Layer0", "Layer1" etc
    IFS=$'\n' L0files=($(find "Layer 0" -name "*.png"))
    IFS=$'\n' L1files=($(find "Layer 1" -name "*.png"))
    IFS=$'\n' L2files=($(find "Layer 2" -name "*.png"))
    IFS=$'\n' L3files=($(find "Layer 3" -name "*.png"))
    
    # Produce NFILES output files
    for i in `seq 1 $NFILES`; do
    
       # Choose random index into each array of filenames
       index0=$( jot -r 1  0 $((${#L0files[@]} - 1)) )
       index1=$( jot -r 1  0 $((${#L1files[@]} - 1)) )
       index2=$( jot -r 1  0 $((${#L2files[@]} - 1)) )
       index3=$( jot -r 1  0 $((${#L3files[@]} - 1)) )
    
       # Pick up files as specified by the random index
       f0=${L0files[index0]}
       f1=${L1files[index1]}
       f2=${L2files[index2]}
       f3=${L3files[index3]}
    
       # Generate output filename, "output-nnn.png" 
       # ... where nnn starts at 0 and goes up till no clash
       i=0
       while :; do
          out="output-$i.png"
          [ ! -f "$out" ] && break
          ((i++))
       done
    
       echo $f0, $f1, $f2, $f3 "=> $out"
       convert "$f0" "$f1" -composite "$f2" -composite "$f3" -composite "$out"
    done
    

    Starting with the following images in your Layer[0-3] directories:

    Layer 0

    enter image description here

    Layer 1

    enter image description here

    Layer 2

    enter image description here

    Layer 3

    enter image description here

    Output files like the following are produced:

    enter image description here

    Original Answer

    I would install ImageMagick to do this - it is free and easily installed on OSX if you install homebrew first by going here. Then type the following in Terminal.

    brew install imagemagick
    

    The script would then look like this:

    #!/bin/bash
    # Build arrays of filenames in each layer, assume directories are "Layer0", "Layer1" etc
    IFS=$'\n' L0files=($(find "Layer0" -name "*.png"))
    IFS=$'\n' L1files=($(find "Layer1" -name "*.png"))
    IFS=$'\n' L2files=($(find "Layer2" -name "*.png"))
    IFS=$'\n' L3files=($(find "Layer3" -name "*.png"))
    
    # Choose random index into each array of filenames
    index0=$( jot -r 1  0 $((${#L0files[@]} - 1)) )
    index1=$( jot -r 1  0 $((${#L1files[@]} - 1)) )
    index2=$( jot -r 1  0 $((${#L2files[@]} - 1)) )
    index3=$( jot -r 1  0 $((${#L3files[@]} - 1)) )
    
    # Pick up files as specified by the random index
    f0=${L0files[index0]}
    f1=${L1files[index1]}
    f2=${L2files[index2]}
    f3=${L3files[index3]}
    
    echo Overlaying $f0, $f1, $f2, $f3 to produce "result.png"
    convert "$f0" "$f1" "$f2" "$f3" -compose over -composite result.png
    

    So, you would save the above as generate and then go to Terminal and do the following one time to make it executable

    chmod +x generate
    

    Then you can run it by double-clicking on its icon in Finder, or typing:

    ./generate
    

    in Terminal. It will then produce a random overlay of 4 images, one from each folder and save the result as result.png.

    You will need to edit the first 4 lines according to where your images are for the various layers - basically I am assuming the images are in directories called Layer0-4, but yours may be in /Users/FreddyFrog/pictures/backgrounds or somesuch, in which case you would edit

        IFS=$'\n' L0files=($(find "/Users/FreddyFrog/pictures/backgrounds" -name "*.png"))
    

    When I run it a few times on my Mac, I get:

    Overlaying Layer0/l0-5.png, Layer1/l1-0.png, Layer2/l2-3.png, Layer3/l3-3.png to produce result.png
    Overlaying Layer0/l0-3.png, Layer1/l1-4.png, Layer2/l2-3.png, Layer3/l3-3.png to produce result.png