Last active
June 1, 2019 15:45
-
-
Save pigeonhill/7efb6b13e34e366d2651ba574125a5fa to your computer and use it in GitHub Desktop.
Hand Held Bracketing Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--HHB Script Release 1.75 | |
--[[ | |
******************************************************************************************** | |
This script attempts to capture 'the best' bracket sequence when hand holding. | |
The bracketing scheme is based on ISO shifting as well as time shifting. | |
The general strategy being to time shift from the highlights at the lowst ISO you can, and ISO shift from the shadows from the lowest Tv you can, at ISO 100. That is try and maximise photon capture, ie for the highest DR. | |
Note pushing ISO too far is pointless, as once above a critical level, Canon cameras go into ISO invariant zone (varies with camera) and overall DR falls with no increase in (read) noise. | |
You should also be high enough to be above the 'pattern noise', but not too high. | |
On a 5D3 a figure of 6400 seems to work well, on an EOSM, say, maybe try 1600 or 3200. | |
The script is triggered by a 3+ sec half shutter press. The script will give user feedback as requested. | |
The script's menu allows you to select a 0, 2 or 5 second delay. | |
To get the best workflow, switch ETTR on and use ETTR to set the base exposure. | |
Irrespective of using ETTR, the base exposure should always be the exposure set for the highlights. | |
You can select the min shutter yourself in manual mode, the script uses the ETTR min even if you don't ETTR. | |
In auto mode (also ensure you select FF or Crop to suit your camera) the script will adjust the min shutter according to your FL. | |
You can also set an explicit min shutter for Auto mode to account for WA lenses, ie auto 1/FL too low. | |
The script will take either 3 or 6 brackets, according to the scene and your menu choices. | |
That is (3 x ISO brackets from the slowest shutter, always) plus [(3 x (highlight) time brackets if possible) or (3 x high ISO 'noise' brackets if requested)] | |
The 3 high ISO 'noise' brackets can be either at 1/3Ev or 0Ev apart: down from the menu set max ISO | |
The script can be switched off (disabled) via its menu. | |
The script will run in LV on non-LV mode. | |
The brackets need to be post processed, eg through LR HDR Merge, Photomatix or with LR/Enfuse or some other app that handles exposure bracketing, or blended with layer masks. | |
The script checks if the lens reports FL and adjusts accordingly. So the script can be used with manual lenses that don't report FL, but ensure you set ETTR min to suit your lens. | |
The script 'remembers' menu settings at camera close, so you will only need to set them once: only change things as required. | |
Garry George | |
Feb 2018 | |
www.photography.grayheron.net | |
******************************************************************************************** | |
--]] | |
require("config") | |
max_iso = 0 -- Set in menu | |
first_pass = false | |
second_pass = false | |
reset = false | |
base_shutter_apex = 0 | |
base_iso_apex = 0 | |
count = 0 | |
options0 = {"ON", "OFF"} | |
options1 = {"Auto", "Manual"} | |
options2 = {"0 delay", "2s delay", "5s delay"} | |
options3 = {"FF Sensor", "Crop Sensor"} | |
options4 = {"1600", "3200","6400"} | |
options5 = {"Auto","1/30","1/60"} | |
options6 = {"None", "Audio","Led", "Both"} | |
options7 = {"OFF", "Time only", "Time/Noise", "Noise only"} | |
options8 = {"0Ev", "1/3Ev"} | |
min_shutter_value =0 | |
min_shutter_apex = 0 | |
timer_running = false | |
time_pressed = 0 | |
run_HHB = false | |
beeped = false | |
good_to_go = false | |
function HH_bracket(arg) -- note this function is called regularly by the shoot_task event handler and does all the main work | |
if HHB_menu.submenu["Turn Script on and off"].value == "ON" then good_to_go = true else good_to_go = false end -- track the script's on/off state | |
if good_to_go and timer_running and (not beeped) and (dryos.ms_clock - time_pressed > 3000) then -- give user feedback if requested | |
if HHB_menu.submenu["User feedback"].value == "Audio" or HHB_menu.submenu["User feedback"].value == "Both" then beep() end | |
if HHB_menu.submenu["User feedback"].value == "Led" or HHB_menu.submenu["User feedback"].value == "Both" then led_blink() end | |
beeped = true -- so don't beep again | |
end | |
if good_to_go and not run_HHB then -- keep track of min shutter speed | |
if lens.focal_length == 0 then menu.set("Hand Held Bracketing", "Min Shutter options", "Manual") end -- handle lenses that don't report FL, but ensure ETTR min shutter set correctly | |
if HHB_menu.submenu["Min Shutter options"].value == "Auto" then -- set ETTR automatically based on focal length and min hand holding shutter set in script's menu | |
local x = lens.focal_length | |
if HHB_menu.submenu["Sensor Type"].value == "Crop Sensor" then x = x*1.6 end -- account for crop sensor | |
x = 8*(7+math.ceil(math.log(x)/math.log(2))) | |
if x < 96 and HHB_menu.submenu["Your min hand holding limit"].value == "1/30" then | |
x = 96 | |
elseif x < 104 and HHB_menu.submenu["Your min hand holding limit"].value == "1/60" then | |
x = 104 | |
end | |
menu.set("Auto ETTR","Slowest shutter", x) -- set slowest ETTR shutter to FL-informed value, ie 1/FL guidance + your min hand holding limit (1/30 or 1/60) | |
end | |
min_shutter_value = menu.get("Auto ETTR","Slowest shutter",1) | |
min_shutter_value = 1/(2^(min_shutter_value/8 - 7)) -- set min shutter in seconds based on ETTR setting | |
end | |
if good_to_go and run_HHB then -- capture brackets | |
-- Now manage the three phases | |
if first_pass then -- do ISO bracketing, 'up' from the min (hand held) shutter, starting at ISO 100, in an attempt to cover the shadow end | |
first_pass = false -- so don't do first pass again in this bracketing sequence | |
max_iso = tonumber(HHB_menu.submenu["Max ISO"].value) | |
second_pass = true -- do a second pass when ready | |
reset = false -- but don't do a reset yet, ie only after a second pass attempt | |
base_iso_apex = camera.iso.apex -- get base ISO value in APEX units, ie the ISO set for the highlights | |
base_shutter_apex = camera.shutter.apex -- get base shutter speed, ie the shutter value used for the highlights in APEX units | |
menu.set("Shoot", "Advanced Bracket", 0) -- switch advanced bracketing off, just in case it's on' | |
camera.shutter.value = min_shutter_value -- get ready to ISO bracket from min shutter position | |
min_shutter_apex = camera.shutter.apex -- get this shutter in APEX units | |
camera.iso.apex = 5 -- set to ISO 100 | |
if HHB_menu.submenu["Delay?"].value == "2s delay" then | |
msleep(2000) -- inject a 2 sec delay | |
elseif HHB_menu.submenu["Delay?"].value == "5s delay" then | |
msleep(5000) -- inject a 5 sec delay | |
end -- else no delay | |
count = dryos.shooting_card.file_number -- get current file counter before we start bracketing | |
camera.shoot() -- capture the 3 ISO brackets from the min shutter | |
camera.iso.value = max_iso | |
camera.shoot() | |
camera.iso.apex = (camera.iso.apex + 5)/2 | |
camera.shoot() | |
return true | |
end | |
-- Do a time or 'noise' bracket pass, from the highlight shutter time starting position or high ISO level | |
if second_pass and (dryos.shooting_card.file_number - count == 3) then -- do a second time bracket pass from the highlights, if possible | |
second_pass = false | |
camera.shutter.apex = base_shutter_apex -- set shutter to base shutter speed, ie as set for the highlights | |
camera.iso.apex = base_iso_apex -- set to base ISO, ie as set for the highlights | |
if base_shutter_apex > min_shutter_apex and (HHB_menu.submenu["2nd Pass Options?"].value == "Time only" or HHB_menu.submenu["2nd Pass Options?"].value == "Time/Noise") then -- can do 3 time brackets from the highlights | |
camera.shoot() | |
camera.shutter.apex = min_shutter_apex | |
camera.shoot() | |
camera.shutter.apex = camera.shutter.apex + (base_shutter_apex - min_shutter_apex)/2 | |
camera.shoot() | |
elseif HHB_menu.submenu["2nd Pass Options?"].value == "OFF" then | |
-- no second pass requested | |
elseif HHB_menu.submenu["2nd Pass Options?"].value == "Noise only" or HHB_menu.submenu["2nd Pass Options?"].value == "Time/Noise" then -- do some high ISO 'noise' brackets at min shutter | |
camera.shutter.iso = min_shutter_apex | |
local delta_ev = 0 | |
if HHB_menu.submenu["Noise Ev delta"].value == "1/3Ev" then delta_ev = 0.33 end | |
camera.iso.value = max_iso | |
camera.iso.apex = camera.iso.apex - delta_ev | |
camera.shoot() | |
camera.iso.apex = camera.iso.apex - delta_ev | |
camera.shoot() | |
camera.iso.apex = camera.iso.apex - delta_ev | |
camera.shoot() | |
end | |
reset = true | |
return true | |
end | |
-- Are we ready to reset? | |
if reset then -- tidy up | |
reset = false | |
camera.shutter.apex = base_shutter_apex -- reset to initial state | |
camera.iso.apex = base_iso_apex -- reset to initial state | |
count = 0 | |
menu.set("Shoot", "Advanced Bracket", 0) -- ensure advanced bracketing off so you can ETTR | |
if timer_running and (not beeped) then -- give user feedback if requested | |
if HHB_menu.submenu["User feedback"].value == "Audio" or HHB_menu.submenu["User feedback"].value == "Both" then beep() end | |
if HHB_menu.submenu["User feedback"].value == "Led" or HHB_menu.submenu["User feedback"].value == "Both" then led_blink() end | |
end | |
run_HHB = false -- signal end of bracketing sequence to event handler | |
return true | |
end | |
return true -- keep watching out | |
end | |
return true | |
end | |
function test4key(key) | |
if key == KEY.HALFSHUTTER and good_to_go and (not timer_running) and (not run_HHB) then -- note assumes the shoot_task runs at least once following camera start | |
timer_running = true -- start looking for half shutter long press | |
time_pressed = dryos.ms_clock | |
beeped = false | |
return false -- steal key press | |
elseif key == KEY.UNPRESS_HALFSHUTTER and good_to_go and timer_running and (not run_HHB) then | |
if dryos.ms_clock - time_pressed > 3000 then -- 3 sec plus half shutter press, so start HH bracketing | |
run_HHB = true -- OK to run the main script | |
timer_running = false -- stop looking for a long press | |
first_pass = true | |
return false -- steal key press | |
else -- less than 3 seconds so handle as a normal half shutter unpress | |
timer_running = false | |
return true | |
end | |
else -- must be a normal key press | |
return true | |
end | |
end | |
event.keypress = test4key | |
event.shoot_task = HH_bracket | |
HHB_menu = menu.new | |
{ | |
parent = "Shoot", | |
name = "Hand Held Bracketing", | |
help = "Start at exposure for the highlights", | |
submenu = | |
{ | |
{ | |
name = "Turn Script on and off", | |
help = "Does what it says", | |
choices = options0, | |
}, | |
{ | |
name = "Min Shutter options", | |
help = "Auto means script sets ETTR min, manual means you do", | |
help2 = "For manual, set min in ETTR menu", | |
choices = options1, | |
}, | |
{ | |
name = "Sensor Type", | |
help = "Full Frame or Crop 1.6?", | |
choices = options3, | |
}, | |
{ | |
name = "Delay?", | |
help = "Injects the requested delay before bracketing", | |
help2 = "Switch off Canon delays", | |
choices = options2, | |
}, | |
{ | |
name = "Max ISO", | |
help = "Make sure Canon Auto Max ISO is the same", | |
choices = options4, | |
}, | |
{ | |
name = "2nd Pass Options?", | |
help = "For noise options choose delta Ev", | |
help2 = "if Time/Noise then do Noise if can't do Time", | |
choices = options7, | |
}, | |
{ | |
name = "Noise Ev delta", | |
help = "Delta Ev ISO bracket", | |
choices = options8, | |
}, | |
{ | |
name = "Your min hand holding limit", | |
help = "Your hand holding shutter speed limit", | |
help2 = "Useful when in Auto mode to override 1/FL for WA lenses", | |
choices = options5, | |
}, | |
{ | |
name = "User feedback", | |
help = "To help with 3s half shutter and indicate bracket end", | |
choices = options6, | |
} | |
} | |
} | |
config.create_from_menu(HHB_menu) -- keep a track of the script's menu state at camera close |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment