基于源图像分层自动生成无重复的随机合成图像
Hey there! I see you're running into duplicate generated images with your current script—totally makes sense when relying purely on random selection, especially when you need hundreds of unique variants. Let's fix that by tracking which layer combinations we've already used, so we never repeat a composite.
The Core Idea
Instead of just picking random layers each time, we'll keep a record of every combination of Layer0/Layer1/Layer2/Layer3 files we've already used. Before generating a new composite, we'll check if the random combination we picked is already in that record; if it is, we'll keep re-rolling until we get a fresh one. We'll also add a safety check to stop the script if we've exhausted all possible unique combinations (so we don't end up in an infinite loop).
Modified Script
Here's the updated version of Marc's script with duplicate prevention built in:
#!/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")) # Calculate total possible unique combinations to avoid infinite loops totalCombos=$(( ${#L0files[@]} * ${#L1files[@]} * ${#L2files[@]} * ${#L3files[@]} )) if [ $NFILES -gt $totalCombos ]; then echo "Error: Requested $NFILES files, but only $totalCombos unique combinations exist." exit 1 fi # Initialize an associative array to track used layer combinations declare -A usedCombos # Produce NFILES output files for ((i=0; i<NFILES; i++)); do # Keep generating random indices until we find an unused combination while :; 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 )) ) # Create a unique key for this combination (using | as a separator, since it won't appear in file paths) comboKey="${L0files[index0]}|${L1files[index1]}|${L2files[index2]}|${L3files[index3]}" # Check if this combination is new if [ -z "${usedCombos[$comboKey]}" ]; then # Mark it as used usedCombos[$comboKey]=1 break fi done # 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" out="output-$i.png" echo "$f0, $f1, $f2, $f3 => $out" convert "$f0" "$f1" -composite "$f2" -composite "$f3" -composite "$out" done
Key Changes Explained
- Associative Array for Tracking: The
usedCombosassociative array stores each unique layer combination as a key. This lets us check if a combination has been used in O(1) time, which is efficient even for hundreds of files. - Combination Key: We use
|to join the four file paths into a single string—this separator is safe because it's not allowed in Unix file paths, so we won't get false matches. - Safety Check: Before starting, we calculate the total number of unique possible combinations. If you request more files than exist, the script will error out instead of looping forever.
- Simplified Output Naming: Since we're looping with a counter from 0 to NFILES-1, we don't need the inner while loop to find an unused filename anymore—each output will be
output-0.png,output-1.png, etc., which is cleaner.
This way, every generated composite will be unique, no manual checking required!
内容的提问来源于stack exchange,提问作者Ben Johnson

