A script that uses Blender's compositor to reliably merge exposure brackets to 32-bit EXR files in bulk.
- Hugin 2021 (aligning images)
- Rawtherapee (processing from raw files)
- Install the required software above.
- If the optional software is not installed, the relevant options will be disabled
- Download the latest release and run
hdr_merge_master.exe
Ensure you have uv installed. If you don't have it yet:
Windows:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"macOS/Linux:
curl -LsSf https://astral.sh/uv/install.sh | shgit clone https://github.com/gregzaal/HDR-Merge-Master.git
cd HDR-Merge-MasterYou do not need to manually create a virtual environment or install dependencies. Simply run:
uv run python hdr_brackets.pyuv will automatically create a .venv, install the correct Python version (3.12+), and fetch all dependencies defined in pyproject.toml before launching the app.
Running the script for the first time will prompt you to edit exe_paths.json to fill in the paths to your blender.exe, luminance-hdr-cli.exe and align_image_stack.exe executable files. It should look something like this (note the double backslashes; you can use forward slashes as well):
{
"blender_exe": "C:\\Program Files\\Blender 2.79\\blender.exe",
"luminance_cli_exe": "C:\\Program Files\\LuminanceHDR\\luminance-hdr-cli.exe",
"align_image_stack_exe": "C:\\Program Files\\Hugin\\bin\\align_image_stack.exe"
"rawtherapee_cli_exe": "C://Program Files//RawTherapee//5.12//rawtherapee-cli.exe"
}
Note: Do not use the align_image_stack.exe that comes with LuminanceHDR, as this is a different version which won't work. Only use the one that comes with Hugin itself.
Then:
- Select a folder that contains your full set of exposure brackets (see Example Folder Structure below). You can now add multiple folders to the input folders for batch processing.
- Choose a pattern to match the files (e.g.
.tifto get all TIFF files). All formats that Blender supports should work, but if you want to use RAW files from your camera, you need to install RawTherapee and enable the RAW option in the UI. Make sure to match the pattern to your camera's output file format. I typically do some minor tweaks to the RAW files in Lightroom first (e.g. chromatic aberration correction) and then export 16-bit.tiffiles to merge with this script. - Choose the number of threads (the number of simultaneous bracketed exposures to merge). Use as many threads as you can without running out of RAM or freezing your computer. In my experience 6 threads usually works fine for 32 GB RAM.
- Choose whether to align the images before merging.
- Choose whether you want the scrpit to look for subfolders inside the selected folders recursivly.
- Click Create HDRs, and monitor the console window for progress and errors.
- The merged HDR images will be in a folder called
Mergednext to your original files. Theexrsubfolder contains the actual 32-bit HDR files, while thejpgfolder contains tonemapped versions of those files.
The application supports a headless CLI mode for automated batch processing without the GUI.
Basic Usage:
python hdr_brackets.py --cli [options]Options:
| Option | Short | Description |
|---|---|---|
--cli |
Run in headless CLI mode (no GUI) | |
--batch <FILE> |
-b |
Load batch folder list from a JSON file |
--folder <PATH> |
-f |
Add a single folder to process |
--recursive |
-r |
Process subfolders recursively (with --folder) |
--profile <NAME> |
-p |
PP3 profile name to use (for RAW files) |
--align |
-a |
Enable image alignment |
--threads <N> |
-t |
Number of worker threads (default: 6) |
--cleanup |
-c |
Cleanup temporary files after processing |
--verbose |
-v |
Print detailed progress information |
Examples:
# Process folders from a batch JSON file
python hdr_brackets.py --cli --batch batch.json
python hdr_brackets.py --cli -b batch.json
# Process a single folder with default settings
python hdr_brackets.py --cli --folder /path/to/images
python hdr_brackets.py --cli -f /path/to/images
# Process a folder with alignment and custom profile
python hdr_brackets.py --cli --folder /path/to/images --align --profile "My Profile"
python hdr_brackets.py --cli -f /path/to/images -a -p "My Profile"
# Process with more threads and cleanup
python hdr_brackets.py --cli --batch batch.json --threads 8 --cleanup
python hdr_brackets.py --cli -b batch.json -t 8 -c
# Process folder recursively with verbose output
python hdr_brackets.py --cli --folder /path/to/images --recursive --verbose
python hdr_brackets.py --cli -f /path/to/images -r -vBatch JSON File Format:
You can export and import batch lists from the GUI using the Export/Import buttons. The JSON format is:
{
"version": "0.1.0",
"folders": [
{
"path": "C:/Images/Folder1",
"profile": "My Profile",
"align": true,
"extension": ".tif",
"is_raw": false,
"brackets": 3,
"sets": 10
}
]
}Note: In CLI mode, processing begins automatically once all folders are loaded.
Note: This tool does not do any ghost removal, so it's important that you use a steady tripod when shooting.
The intended use here is for creating HDRIs, allowing you to stitch with the JPG files (which load quickly and, being tonemapped, show more dynamic range), and then swap the JPGs out with the EXR files at the end before your final export. If you are using PTGui, you can do this using the included ptgui_jpg_to_hdr.py file - just drag your .pts project file onto that script and it will replace the JPG paths with EXR ones.
The script will automatically read the metadata and determine which images should be grouped together and merged. The entire folder of images will be merged based on the pattern determined by the first set.
The bracket matching works by checking the exposure metadata of the first image and searching for the next image with the same exposure:
- C:/Foo/bar/
IMG001.tif- 1/4000 F/8 ISO100IMG002.tif- 1/1000 F/8 ISO200IMG003.tif- 1/250 F/8 ISO400IMG004.tif- 1/4000 F/8 ISO100IMG005.tif- 1/1000 F/8 ISO200IMG006.tif- 1/250 F/8 ISO400
The script will discover that images IMG001.tif and IMG004.tif have the same exposure settings, and thus the images will be grouped into threes:
- Exposure set 1 (merged to
merged_000.exr):IMG001.tifIMG002.tifIMG003.tif
- Exposure set 2 (merged to
merged_001.exr):IMG004.tifIMG005.tifIMG006.tif
Exposures can be in any order (0 + ++, 0 - --, 0 + -, - 0 +, etc.).
The distribution can be built using:
uv run python -m nuitka hdr_brackets.py
hdr_brackets.py has nuitka options preconfigured inside of it, so appropriate The build will be located inside /build
-
Update your version in pyproject.toml (e.g., to 0.1.4).
-
Tag your commit in your terminal: '''Bash git add . git commit -m "Prepare release v0.1.4" git tag v0.1.4 git push origin main --tags '''
-
This will add a new tag to the project and will trigger the action to make a build
