Get Brackets (CHDK)
--[[ | |
Capture 'Perfect' focus brackets, with focus overlap defined in terms of defocus (CHDK Circle of Confusion (CoC)) blur | |
Focus bracketing strategies are: current position to blur-defined infinity (X2Inf); min camera focus to current position (Min2X), min camera focus to blur-defined infinity (Min2Inf); | |
current position to a delta x ahead of the current position (X2DelX); from a delta x in front of the current position to the current position (-DelX2X); | |
from a delta x in front of the current position to a delta x ahead of the current position (-D2+D). | |
Overlap, ie bracket to bracket focus insurance, is definded in terms of the defocus (CoC) blur, eg CoC/2 means focus brackets 'touch' at a blur of CoC/2. | |
Where as diff means that the defocus blur and the diffraction blur, taken in quadrature, equals the CHDK CoC value | |
None means that requested exposures will only be captured at the current focus point | |
Additional exposure brackets may be taken at each focus step, using various schemes: 1Ev, 2Ev or 3Ev steps using -/+ or -/-- or +/++; one iso-invariant at | |
ISO at 800 or 1600; or one (Zero Noise) exposure at +4Ev, +3Ev or +2Ev or auto from a shadow exposure | |
Use Bookends to help differentiate bracket set in post (reccomended) | |
Option to switch LCD screen off during shooting | |
Script will pause and display predicted number of focus brackets and, if requested, the infinity focus distance. Do a Full Shutter press to terminate or Half Shutter to run the script. | |
If you get an error message, try resetting focus as this is the usual cause | |
Tested on an S95, G5X, G7X and a G1X | |
For the EOS M3 version goto: https://chdk.fandom.com/wiki/Landscape_Focus_Bracketing_:_perfect_near_to_far_focus_brackets | |
Rev 1.9286211 | |
August 2020 | |
Garry George | |
@chdk_version 1.5 | |
@title Get Brackets | |
@subtitle Focus Stuff | |
# focus_strat = 0 "Focus logic?" {X2Inf Min2X Min2Inf X2DelX -DelX2X None -D2+D} | |
# overlap = 0 "Overlap at" {CoC 2CoC/3 CoC/2 diff} | |
# quality = 2 "Infinity quality?" {CoC/2 CoC/3 CoC/4} | |
# delx = 10 "Focus delta (mm)" [5 100] | |
@subtitle Exposure Stuff | |
# delta = 0 "Exposure delta?" {None 1Ev 2Ev 3Ev 800 1600 ZN4 ZN3 ZN2 Auto} | |
# logic = 0 "Exposure logic?" {0/-/+ 0/-/-- 0/+/++} | |
# hilit = 20 "% histo HiLit" [5 30] | |
@subtitle Other Stuff | |
# delay = 3 "Script Delay (s)" [0 5] | |
# bookends = 1 "Bookends?" {No Yes} | |
# screen_off = 0 "Screen off?" {No Yes} | |
--]] | |
capmode = require("capmode") | |
set_config_value(2151,0) -- switching these two off means we are measuring distance 'from the lens': ... | |
set_config_value(2152,0) -- ...this is the 'best' we can do without knowing the position of the front principal plane | |
function restore() -- called at script termination | |
if done == 0 then | |
if x_start == -1 then refocus(1000000) else refocus(x_start) end | |
set_tv96_direct(s) | |
set_av96_direct(av) | |
press("shoot_half") | |
release("shoot_half") | |
if current_focus_mode ~= 1 then set_mf(0) end | |
if (current_mode ~= "M") then capmode.set(current_mode) end | |
set_lcd_display(1) | |
end | |
end | |
function my_restore() | |
if x_start == -1 then refocus(1000000) else refocus(x_start) end | |
set_tv96_direct(s) | |
set_av96_direct(av) | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
sleep(100) | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
if current_focus_mode ~= 1 then set_mf(0) end | |
if (current_mode ~= "M") then capmode.set(current_mode) end | |
set_lcd_display(1) | |
done = 1 | |
end | |
function set_up() | |
current_focus_mode = get_focus_mode() | |
current_mode = capmode.get_name() | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
s = get_tv96() | |
av = get_av96() | |
if (current_mode ~= "M") then capmode.set("M") end | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
dof = get_dofinfo() | |
x = dof.focus | |
x_start = x | |
xr = x | |
base_h = dof.hyp_dist -- that is without diffraction accounted for | |
fl = dof.focal_length/100 -- focal length in mmx10 | |
if current_focus_mode ~= 1 then | |
print("MF mode not set") | |
done = 1 | |
return false | |
end | |
if x < 0 then | |
print("Refocus as at infinity") | |
done = 1 | |
return false | |
end | |
if x > base_h/3 and (focus_strat == 3 or focus_strat == 4 or focus_strat == 6) then | |
print("Too far away") | |
done = 1 | |
return false | |
end | |
return true | |
end | |
function myshoot() -- works inside X_bracket function | |
local prevcnt=hook_shoot.count() | |
local rawprevcnt=hook_raw.count() | |
press'shoot_full_only' | |
repeat sleep(10) until prevcnt ~= hook_shoot.count() | |
release'shoot_full_only' | |
repeat sleep(10) until rawprevcnt ~= hook_raw.count() | |
end | |
function bookend() | |
set_tv96_direct(960) | |
set_av96_direct(get_max_av96()) | |
local ecnt = get_exp_count() | |
shoot() | |
set_tv96_direct(s) | |
set_av96_direct(av) | |
repeat sleep(10) until (get_exp_count() ~= ecnt) | |
end | |
function refocus(xx) | |
set_focus(xx) | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
dof = get_dofinfo() -- update info | |
return dof.focus | |
end | |
function X_bracket() | |
press("shoot_half") | |
repeat sleep(10) until (get_shooting()) | |
set_tv96_direct(s) | |
if delta == 0 then | |
myshoot() | |
elseif delta < 4 and logic == 0 then | |
myshoot() | |
set_tv96_direct(s-96*delta) | |
myshoot() | |
set_tv96_direct(s+96*delta) | |
myshoot() | |
elseif delta < 4 and logic == 1 then | |
myshoot() | |
set_tv96_direct(s+96*delta) | |
myshoot() | |
set_tv96_direct(s+2*96*delta) | |
myshoot() | |
elseif delta < 4 and logic == 2 then | |
myshoot() | |
set_tv96_direct(s-96*delta) | |
myshoot() | |
set_tv96_direct(s-2*96*delta) | |
myshoot() | |
elseif delta == 4 then | |
local iso = get_sv96() | |
myshoot() | |
set_sv96(sv96_market_to_real(iso_to_sv96(800))) | |
myshoot() | |
set_sv96(iso) | |
elseif delta == 5 then | |
local iso = get_sv96() | |
myshoot() | |
set_sv96(sv96_market_to_real(iso_to_sv96(1600))) | |
myshoot() | |
set_sv96(iso) | |
elseif delta == 6 then | |
myshoot() | |
set_tv96_direct(s-96*4) | |
myshoot() | |
elseif delta == 7 then | |
myshoot() | |
set_tv96_direct(s-96*3) | |
myshoot() | |
elseif delta == 8 then | |
myshoot() | |
set_tv96_direct(s-96*2) | |
myshoot() | |
elseif delta == 9 then | |
shot_histo_enable(1) | |
myshoot() | |
sleep(100) | |
lower = 1024 - 1024*hilit/100 | |
test=get_histo_range(lower,1024) | |
step = 0 | |
while test > 0 do | |
step = step + 1 | |
set_tv96_direct(s + 96 * 2 * step) | |
myshoot() | |
sleep(100) | |
test=get_histo_range(lower,1024) | |
end | |
shot_histo_enable(0) | |
end | |
set_tv96_direct(s) | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
end | |
-- Main section | |
done = 0 | |
if not set_up() then | |
return -- exit script | |
end | |
-- Calculate the overlap h | |
h = base_h -- no overlap case: brackets 'touch' at CHDK CoC | |
if overlap == 1 then -- adjust h to achieve the requested overlap, ie 'touching' at 2*CoC/3 or CoC/2 or at the diffraction aware defocus blur | |
h = (h*3)/2 | |
elseif overlap == 2 then | |
h = 2*h | |
elseif overlap == 3 then -- use diffraction aware overlap: Assume CHDK CoC is total blur, formed in quadrature from defocus and diffraction blurs | |
temp1 = 1000*dof.coc -- total blur set up for imath | |
temp2 = (1342*dof.aperture)/1000 -- set up for imath. From diff_blur = 2.44*0.55*N (um) | |
if temp1 > temp2 then -- can use diffraction aware overlap | |
temp = imath.sqrt(imath.mul(temp1,temp1) - imath.mul(temp2,temp2)) -- diffraction aware defocus blur umx1000 | |
temp2 = imath.div(temp1,temp) | |
if temp2 > 3000 then | |
h = 3*h | |
else | |
h = (h*temp2)/1000 | |
end | |
else -- diff blur > total blur | |
h = 3*h | |
end | |
end | |
x_stop = h/3 | |
if focus_strat == 1 then | |
x = 10 | |
xr = refocus(x) | |
x_stop = x_start | |
elseif focus_strat == 2 then | |
x = 10 | |
xr = refocus(x) | |
elseif focus_strat == 3 then | |
x_stop = x_start + delx | |
elseif focus_strat == 4 then | |
x = x_start - delx | |
xr = refocus(x) | |
x_stop = x_start | |
elseif focus_strat == 5 then | |
X_bracket() | |
if bookends == 1 then bookend() end | |
my_restore() | |
return | |
elseif focus_strat == 6 then | |
x_stop = x_start + delx | |
x = x_start - delx | |
xr = refocus(x) | |
end | |
-- Keep all DoF calculations in request-space, to limit build up of image to image CHDK-Canon errors | |
if xr >= base_h then | |
bracks = 2 | |
else | |
bracks = (-h*(xr-x_stop)+3*x_stop*xr)/(2*x_stop*xr) | |
if bracks < 1 then bracks = 1 end | |
if focus_strat == 0 or focus_strat == 2 then | |
bracks = bracks + 2 | |
end | |
end | |
print("# of Brackets = "..bracks) | |
if focus_strat == 0 or focus_strat == 2 then | |
print("Inf focus @: "..(base_h*(quality+2)).."mm") | |
end | |
print("Press HS or FS") | |
repeat | |
wait_click() | |
until (is_key("shoot_half") or is_key("shoot_full")) | |
t1=os.time() | |
print("Bracketing Started") | |
if screen_off == 1 then set_lcd_display(0) end | |
if bookends == 1 then bookend() end | |
t1=(os.time()-t1) | |
if delay >= t1 then | |
t1=delay-t1 | |
sleep(t1*1000) | |
end | |
im = 0 | |
while (xr <= x_stop) do -- capture the focus brackets up to the required x_stop | |
if 2*xr >= h then break end | |
im=im+1 | |
x = refocus(xr) | |
print(im.."/"..bracks..": "..x.."mm") | |
X_bracket() | |
xr = (xr*(h*10 - 2*fl))/(h*10 - 2*xr*10) -- estimated position of next focus bracket | |
end | |
if focus_strat == 0 or focus_strat == 2 then | |
temp2 = refocus(base_h) -- take shot at the base hyperfocal | |
im=im+1 | |
print(im.."/"..bracks..": "..temp2.."mm") | |
X_bracket() | |
temp2 = base_h*(quality+2) | |
temp2 = refocus(temp2) -- take shoot at the selected infinity blur | |
im=im+1 | |
print(im.."/"..bracks..": "..temp2.."mm") | |
X_bracket() | |
end | |
if bookends == 1 then bookend() end | |
my_restore() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment