Skip to content

Instantly share code, notes, and snippets.

@pigeonhill
Created March 5, 2018 21:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pigeonhill/185a1b72e5a909d767f0ce9bdfb259e4 to your computer and use it in GitHub Desktop.
Save pigeonhill/185a1b72e5a909d767f0ce9bdfb259e4 to your computer and use it in GitHub Desktop.
Auto Hand Held Focus Stacking
--HHFS Script Release 0.8
--[[
********************************************************************************************
This script creates a two image focus stack via aperture bracketing.
The script attempts to maintain the same exposure of the closed down aperture as the base exposure, between two limits: the minimum handheld shutter and the maximum ISO.
The script 'remembers' menu settings at camera close, so you will only need to set them once: only change things as required.
The base exposure should be taken at a wide aperture.
Garry George
March 2018
www.photography.grayheron.net
********************************************************************************************
--]]
require("config")
max_iso = 0 -- Set in menu
max_iso_apex = 0
base_shutter_apex = 0
base_iso_apex = 0
base_aperture_apex = 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"}
options8 = {"F/16", "F/22"}
min_shutter_value =0
min_shutter_apex = 0
timer_running = false
time_pressed = 0
run_HHFS = false
beeped = false
good_to_go = false
function HHFS_bracket(arg) -- note this function is called regularly by the shoot_task event handler and does all the main work
if HHFS_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 HHFS_menu.submenu["User feedback"].value == "Audio" or HHFS_menu.submenu["User feedback"].value == "Both" then beep() end
if HHFS_menu.submenu["User feedback"].value == "Led" or HHFS_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_HHFS then -- keep track of min shutter speed in auto mode
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 HHFS_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 HHFS_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 HHFS_menu.submenu["Your min hand holding limit"].value == "1/30" then
x = 96
elseif x < 104 and HHFS_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_HHFS then -- capture brackets
if HHFS_menu.submenu["Delay?"].value == "2s delay" then
msleep(2000) -- inject a 2 sec delay
elseif HHFS_menu.submenu["Delay?"].value == "5s delay" then
msleep(5000) -- inject a 5 sec delay
end -- else no delay
base_shutter_apex = camera.shutter.apex
base_iso_apex = camera.iso.apex
base_aperture_apex = camera.aperture.apex
max_iso = tonumber(HHFS_menu.submenu["Max ISO"].value)
camera.iso.value = max_iso
max_iso_apex = camera.iso.apex
camera.iso.apex = base_iso_apex
camera.shoot() -- take base image
camera.shutter.value = min_shutter_value -- set to slowest shutter
min_shutter_apex = camera.shutter.apex
local min_aperture_apex = 0
if HHFS_menu.submenu["Min aperture"].value == "F/16" then min_aperture_apex = 8 else min_aperture_apex = 9 end
camera.aperture.apex = min_aperture_apex
local delta_ev = min_aperture_apex - base_aperture_apex
local delta_tv = base_shutter_apex - min_shutter_apex
if base_shutter_apex == min_shutter_apex then -- can only use ISO
camera.iso.apex = camera.iso.apex + delta_ev
if camera.iso.apex > max_iso_apex then camera.iso.apex = max_iso_apex end
else -- can use shutter and ISO
camera.shutter.apex = min_shutter_apex
camera.iso.apex = camera.iso.apex + (delta_ev - delta_tv)
if camera.iso.apex > max_iso_apex then camera.iso.apex = max_iso_apex end
end
camera.shoot() -- take the closed down aperture image
camera.shutter.apex = base_shutter_apex -- reset settings to initial state
camera.iso.apex = base_iso_apex
camera.aperture.apex = base_aperture_apex
if timer_running and (not beeped) then -- give user feedback if requested
if HHFS_menu.submenu["User feedback"].value == "Audio" or HHFS_menu.submenu["User feedback"].value == "Both" then beep() end
if HHFS_menu.submenu["User feedback"].value == "Led" or HHFS_menu.submenu["User feedback"].value == "Both" then led_blink() end
end
run_HHFS = false
end
return true -- no reason not to
end
function test4key(key)
if key == KEY.HALFSHUTTER and good_to_go and (not timer_running) and (not run_HHFS) 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_HHFS) then
if dryos.ms_clock - time_pressed > 3000 then -- 3 sec plus half shutter press, so start HH bracketing
run_HHFS = true -- OK to run the main script
timer_running = false -- stop looking for a long press
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 = HHFS_bracket
HHFS_menu = menu.new
{
parent = "Shoot",
name = "Hand Held Focus Stacking",
help = "Start at max aperture",
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 = "Don't over push it!'",
choices = options4,
},
{
name = "Min aperture",
help = "Smallest aperture",
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(HHFS_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