Yesterday I had a photo in my gallery from a little experiment with Enfuse – Since I received quite a few positive reactions and some questions via email, I decided to dedicate a second article to the topic.
If you have Enfuse installed on your system — whether through Hugin, your package manager, or directly from the Enblend-Enfuse website — you can easily merge two or more images using a single command in your terminal or command prompt. Whether this is to improve HDR images, do focus stacking, or simply merge differently exposed or mirrored photos into one image, as long as you’re feeling inspired, it can produce some fun and interesting results.
Tip:
Some of the messages I received mentioned that using commands and scripts can seem complicated—or even a bit scary. People worry about making mistakes. But here’s the good news: if you’re not familiar with this kind of thing but you’ve used ChatGPT before, just ask it to create a script for you—like one that merges photos from a specific folder. Ask it to walk you through the steps, one by one. Before you know it, you’ll be typing commands on your computer like a pro and fusing photos with ease!
What You Need
- Two or more images of the same scene, ideally taken with different exposures (bracketing).
- Enfuse, properly installed.
That’s it.
The Basic Command
enfuse -o result.jpg photo1.jpg photo2.jpg
Explanation:
-o result.jpg
tells Enfuse what to name the output file.photo1.jpg photo2.jpg
are the input images you want to fuse.
Enfuse analyzes the input and blends them by selecting the best-exposed and most detailed parts of each image. It produces a natural-looking result without complicated HDR tone-mapping.
Important Note on Alignment
Your photos must be perfectly aligned. If you shot handheld or notice any misalignment, it’s best to align the images first:
align_image_stack -m -a aligned_ photo1.jpg photo2.jpg
enfuse -o result.jpg aligned_*.tif
The align_image_stack
tool, which comes with Hugin, creates aligned TIFF files that you can feed directly into Enfuse.
Platform Notes
Windows: If you installed Hugin, you probably already have Enfuse. Just open CMD or PowerShell and run the command.
macOS: You can install Enfuse using Homebrew:
brew install enblend-enfuse
Linux: Use your system’s package manager:
sudo apt install enblend-enfuse
or
sudo dnf install enblend-enfuse
What Does Enfuse Actually Do?
Enfuse is not a traditional HDR tool. It doesn’t stretch the dynamic range or apply tone-mapping. Instead, it blends multiple exposures by evaluating local contrast, exposure, and saturation. The result is a clean, well-balanced image without halos or artificial effects.
That’s all you need to start experimenting with exposure fusion. Try it with a basic bracketed set (like -1 EV, 0 EV, +1 EV) and see what it can do.s

Top and bottom: two mirrored and fusion-created results.

And below, the two photos that were used – two photos, multiple possibilities.


Like yesterday in my gallery :
In the meantime, the script has also been updated and now includes some extra code to handle issues.
Execute it with bash [name of the script].sh
Copy and paste it into a text editor – save with a name something like this : Auto-Fusion-Utility.sh
Run chmod +x [name of the script].sh
#!/bin/bash#Auto-Fusion-Utility.shLOGFILE="debug_EnfuseUtility.log"echo "==== Nieuwe run op $(date) ====" >> "$LOGFILE"lastsettings=".lastsettings"logfile="./lastfusion.txt"print_header() { clear echo -e "\n╔══════════════════════════════════════════════╗" printf "║ %-44s ║\n" "$1" echo "╚══════════════════════════════════════════════╝"}validate_numeric() { if ! [[ "$1" =~ ^[0-9]*\.?[0-9]+$ ]]; thenecho "Invalid number: $1" >&2exit 1 fi}save_last_settings() { echo "$1" > "$lastsettings" echo "$2" >> "$lastsettings" echo "$3" >> "$lastsettings" echo "$4" >> "$lastsettings" echo "$5" >> "$lastsettings" echo "$6" >> "$lastsettings"}load_last_settings() { if [[ ! -f "$lastsettings" ]]; thenecho "No previous settings found." >&2exit 1 fi IFS=$'\n' read -r last_dir last_ext last_exposure last_saturation last_contrast hmasklog < "$lastsettings" if [[ "$hmasklog" == "YES" ]]; thenhardmask="--hard-mask" elsehardmask="" fi}ask_hardmask() { read -rp "Use hard mask? (y/n): " hardmaskchoice if [[ "$hardmaskchoice" =~ ^[Yy]$ ]]; thenhardmask="--hard-mask"hmasklog="YES" elsehardmask=""hmasklog="NO" fi}run_enfuse() { local output="$1" shift local files=("$@") if [[ ${#files[@]} -eq 0 ]]; thenecho "⚠️ Geen bestanden gevonden om te fusen." | tee -a "$LOGFILE"exit 1 fi echo "Starting enfuse with output: $output" | tee -a "$LOGFILE" echo "Input files:" | tee -a "$LOGFILE" for f in "${files[@]}"; doecho " $f" | tee -a "$LOGFILE" done enfuse --exposure-weight="$exposure_weight" --saturation-weight="$saturation_weight" --contrast-weight="$contrast_weight" $hardmask --output="$output" "${files[@]}" >> "$LOGFILE" 2>&1 local enfuse_status=$? if (( enfuse_status != 0 )); thenecho "❌ enfuse faalde met status $enfuse_status. Check $LOGFILE" | tee -a "$LOGFILE"exit $enfuse_status fi if [[ ! -f "$output" ]]; thenecho "❌ Outputbestand niet gevonden: $output" | tee -a "$LOGFILE"exit 1 fi echo "✅ Fusion succesvol, output: $output" | tee -a "$LOGFILE"}print_header "ENFUSE FUSION TOOL - MAIN MENU"echo "║ 1. Quick Fusion (default weights) ║"echo "║ 2. Custom Fusion (interactive input)║"echo "║ 3. Repeat Last Fusion ║"echo "║ Q. Quit ║"echo "╚══════════════════════════════════════════════╝"read -rp "Choose an option [1, 2, 3, Q]: " runoptioncase "$runoption" in "1")print_header "QUICK FUSION – DEFAULT SETTINGS"read -rp "Image Path (no trailing slash): " variable1if [[ -z "$variable1" || ! -d "$variable1" ]]; then echo "Invalid path." >&2 exit 1firead -rp "Image Extension (jpg, tif, etc.): " ext1# Gewichten defaultexposure_weight=1saturation_weight=1contrast_weight=1# Hardmask interactiefask_hardmasktimestamp=$(date +"%Y%m%d_%H%M%S")outputfile="$variable1/output_$timestamp.$ext1"mapfile -t files < <(find "$variable1" -maxdepth 1 -type f -iname "*.$ext1" | sort)run_enfuse "$outputfile" "${files[@]}"echo -e "\n[QUICK FUSION - $timestamp]" >> "$logfile"echo "Source: $variable1/*.$ext1" >> "$logfile"echo "Output: $outputfile" >> "$logfile"echo "Weights: exposure=$exposure_weight, saturation=$saturation_weight, contrast=$contrast_weight" >> "$logfile"echo "Hard Mask: $hmasklog" >> "$logfile"save_last_settings "$variable1" "$ext1" "$exposure_weight" "$saturation_weight" "$contrast_weight" "$hmasklog"read -rp "View output image? (y/n): " viewimg[[ "$viewimg" =~ ^[Yy]$ ]] && xdg-open "$outputfile" >/dev/null 2>&1 &;; "2")print_header "CUSTOM FUSION – YOUR SETTINGS"read -rp "Image Path (no trailing slash): " variable1if [[ -z "$variable1" || ! -d "$variable1" ]]; then echo "Invalid path." >&2 exit 1firead -rp "Image Extension (jpg, tif, etc.): " ext1read -rp "Exposure weight (e.g., 1): " exposure_weight; validate_numeric "$exposure_weight"read -rp "Saturation weight (e.g., 0.2): " saturation_weight; validate_numeric "$saturation_weight"read -rp "Contrast weight (e.g., 0.3): " contrast_weight; validate_numeric "$contrast_weight"ask_hardmasktimestamp=$(date +"%Y%m%d_%H%M%S")outputfile="$variable1/output_$timestamp.$ext1"mapfile -t files < <(find "$variable1" -maxdepth 1 -type f -iname "*.$ext1" | sort)run_enfuse "$outputfile" "${files[@]}"echo -e "\n[CUSTOM FUSION - $timestamp]" >> "$logfile"echo "Source: $variable1/*.$ext1" >> "$logfile"echo "Output: $outputfile" >> "$logfile"echo "Weights: exposure=$exposure_weight, saturation=$saturation_weight, contrast=$contrast_weight" >> "$logfile"echo "Hard Mask: $hmasklog" >> "$logfile"save_last_settings "$variable1" "$ext1" "$exposure_weight" "$saturation_weight" "$contrast_weight" "$hmasklog"read -rp "View output image? (y/n): " viewimg[[ "$viewimg" =~ ^[Yy]$ ]] && xdg-open "$outputfile" >/dev/null 2>&1 &;; "3")print_header "REPEAT LAST FUSION"load_last_settingsecho "Last settings:"echo "Source folder: $last_dir"echo "Extension: $last_ext"echo "Weights: exposure=$last_exposure, saturation=$last_saturation, contrast=$last_contrast"echo "Hard Mask: $hmasklog"# Vraag opnieuw hardmask interactiefask_hardmasktimestamp=$(date +"%Y%m%d_%H%M%S")outputfile="$last_dir/output_$timestamp.$last_ext"mapfile -t files < <(find "$last_dir" -maxdepth 1 -type f -iname "*.$last_ext" | sort)run_enfuse "$outputfile" "${files[@]}"echo -e "\n[REPEATED FUSION - $timestamp]" >> "$logfile"echo "Source: $last_dir/*.$last_ext" >> "$logfile"echo "Output: $outputfile" >> "$logfile"echo "Weights: exposure=$last_exposure, saturation=$last_saturation, contrast=$last_contrast" >> "$logfile"echo "Hard Mask: $hmasklog" >> "$logfile"save_last_settings "$last_dir" "$last_ext" "$last_exposure" "$last_saturation" "$last_contrast" "$hmasklog"read -rp "View output image? (y/n): " viewimg[[ "$viewimg" =~ ^[Yy]$ ]] && xdg-open "$outputfile" >/dev/null 2>&1 &;; "Q"|"q")echo "Bye!"exit 0;; *)echo "Invalid option. Exiting."exit 1;;esac
I don’t have any Sponsoring Companies, Patreon support, or Follower Donations.
I don’t drink Coffee, well, I do … but not the financial form you sometimes find on other websites, like ‘buy me a coffee’ 😊
However, what I truly need to keep going is Motivation, and the best part is, it won’t cost you a thing. You can offer it for free – just hit the Like button and Subscribe !
Discover more from Open Source Photography
Subscribe to get the latest posts sent to your email.
Enjoyed this post? Put your thoughts into words! Or just give a thumbs-up in the comment box!