Skip to content

Instantly share code, notes, and snippets.

@pigeonhill
Last active March 2, 2019 08:24
Show Gist options
  • Save pigeonhill/10a43f5ba543bc758f1ce21d28981a89 to your computer and use it in GitHub Desktop.
Save pigeonhill/10a43f5ba543bc758f1ce21d28981a89 to your computer and use it in GitHub Desktop.
CHDK Landscape Bracketing
--[[
@title Landscape Bracketing
'Perfect' focus brackets from near to blur defined 'infinity': overlap defined at a fraction of camera's CoC
Plus option of two additional exposure brackets at each focus step, at 1Ev, 2Ev or 3Ev using -/+ or -/-- or +/++ logic
More info at https://chdk.wikia.com/wiki/Landscape_Focus_Bracketing_:_perfect_near_to_far_focus_brackets
Camera should be in manual focus mode and M mode
Release 1.9985
Tested on a G7X & G1X
(c) Garry George
@chdk_version 1.5
@param u Focus stack mode?
@default u 0
@values u X2Inf Mac2Inf Mac2X X2delX
@param g Overlap at?
@default g 3
@values g CoC 2CoC/3 CoC/2 diff
@param p Exposure bracket delta?
@default p 0
@values p None 1Ev 2Ev 3Ev 800 1600 ZN
@param j Exposure bracket logic?
@default j 0
@values j 0/-/+ 0/-/-- 0/+/++
@param m Delta from X (mm)
@default m 25
@range m 1 200
@param n Max number of focus brackets?
@default n 0
@values n Inf <10 <20 <30
@param c Script Delay (s)
@default c 3
@range c 0 5
@param b Bookends?
@default b 1
@values b No Yes
@param q Infinity focus quality?
@default q 1
@values q CoC/2 CoC/3 CoC/4
@param v Show bracket pos?
@default v 1
@values v No Yes
@param k Log?
@default k 0
@values k No Yes
@param e Delete Log File?
@default e 0
@values e No Yes
--]]
capmode = require("capmode")
if (capmode.get_name() ~= "M") then
print("Switch to M mode")
return -- exit script
end
if get_focus_mode() ~= 1 then
print("Switch to MF mode")
return -- exit script
end
if e == 1 then
local fp = io.open("A/CHDK/DATA/LBS.CFG")
local str = fp:read("*all")
fp:close()
temp = string.sub(str, 1, 1)
temp = "A/CHDK/DATA/LBS."..temp
fp = io.open (temp,"r")
if fp == nil then
print("No ConFig file found")
return
else
str = fp:read("*all")
fp:close()
if string.find(str,"e=0") == nil then
str = string.gsub(str,"#e=1","#e=0")
fp = io.open (temp,"w")
fp:write(str)
fp:close()
os.remove("A/CHDK/LOGS/LOG_2306.TXT")
print("Log File Deleted")
return -- exit script
end
end
end
if (get_focus() == -1) then
print("@ Infinity")
return -- exit script
end
press("shoot_half") -- get current exposure
t = get_tick_count()
repeat
sleep(50)
if get_tick_count() - t > 5000 then
print("Unknown Error")
release("shoot_half")
return
end
until (get_shooting() == true)
release("shoot_half")
s = get_tv96()
av = get_av96()
dof = get_dofinfo()
x = dof.focus
x_start = x
last_x = x
base_h = dof.hyp_dist
temp = 0
temp1 = 0
temp2 = 0
ok = true
fl = dof.focal_length/100
log = {}
count = 0
ecnt = get_exp_count()
if u == 1 or u == 2 then -- change focus to min focus
set_focus((4*fl)/10)
press("shoot_half")
repeat
x = get_focus()
sleep(100) -- seems to work on G7X & G1X, may need changing on other cams
until x == get_focus()
release("shoot_half")
end
-- A few Functions
function myshoot()
ecnt = get_exp_count()
shoot()
end
function bookend()
if b == 1 then
set_tv96(960)
set_av96(640)
myshoot()
set_tv96_direct(s)
set_av96_direct(av)
repeat sleep(20) until(get_exp_count()~=ecnt)
end
end
function refocus(xx)
local dis = 0
set_focus(xx)
press("shoot_half")
repeat
dis = get_focus()
sleep(200) -- seems to work on G7X & G1X, may need changing on other cams
until dis == get_focus()
release("shoot_half")
end
function X_bracket()
set_tv96_direct(s)
count = count + 1
if p == 0 then
myshoot()
elseif p < 4 and j == 0 then
myshoot()
set_tv96_direct(s-96*p)
myshoot()
set_tv96_direct(s+96*p)
myshoot()
elseif p < 4 and j == 1 then
myshoot()
set_tv96_direct(s+96*p)
myshoot()
set_tv96_direct(s+2*96*p)
myshoot()
elseif p < 4 and j == 2 then
myshoot()
set_tv96_direct(s-96*p)
myshoot()
set_tv96_direct(s-2*96*p)
myshoot()
elseif p == 4 then
local iso = get_sv96()
set_sv96(sv96_market_to_real(iso_to_sv96(100)))
myshoot()
set_sv96(sv96_market_to_real(iso_to_sv96(800)))
myshoot()
set_sv96(iso)
elseif p == 5 then
local iso = get_sv96()
set_sv96(sv96_market_to_real(iso_to_sv96(100)))
myshoot()
set_sv96(sv96_market_to_real(iso_to_sv96(1600)))
myshoot()
set_sv96(iso)
elseif p == 6 then
myshoot()
set_tv96_direct(s-96*4)
myshoot()
end
set_tv96_direct(s)
end
h = base_h -- no overlap case: brackets 'touch' at CHDK CoC
if g == 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 g == 2 then
h = 2*h
elseif g == 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
temp2 = imath.div(temp1,temp)
if temp2 > 3000 then
h = 3*h
print("Warning: High Diff: using CoC/3")
else
h = (h*temp2)/1000
end
else -- diff blur > total blur
h = 3*h
print("Warning: Diff>Defocus: using CoC/3")
end
end
if (x > base_h or x == -1) then
print("@/beyond H")
sleep(c*1000)
bookend()
X_bracket()
temp = get_exp_count().." @ "..x_start.."mm"
if v == 1 then print(temp) end
bookend()
return -- exit script
else
num = ((10*(h + x))/(2*x) + 5)/10
end
if u == 2 or u == 3 then
dof = get_dofinfo()
x = dof.focus -- register actual x
last_x = x
sleep(c*1000)
bookend()
if u == 3 then x_start = x_start+m end
repeat -- to capture focus brackets from min focus up to x
X_bracket()
temp = get_exp_count().." @ "..x.."mm"
if v == 1 then print(temp) end
x = (x*(h*10 - 2*fl))/(h*10 - 2*x*10) -- position of next focus bracket
if (x - last_x) == 0 then x = last_x + 1 end
if x < last_x or x <= 0 then
print("Unknown Error")
refocus(x_start)
return
end
refocus(x) -- request move to x
dof = get_dofinfo()
x = dof.focus -- register actual x moved by cam
last_x = x
until (x > x_start)
refocus(x_start)
dof = get_dofinfo()
x = dof.focus -- register actual x moved by cam
X_bracket()
bookend()
temp = get_exp_count().." @ "..x.."mm"
if v == 1 then print(temp) end
return -- exit script
end
if (n ~= 0 and num > (n*10)-1) then -- accounting for last bracket at infinity focus
print("Warning")
temp2 = num + 1
print("Focus Steps = "..temp2)
return -- exit script
end
sleep(c*1000)
bookend()
-- else look after u == 0 or 1 cases
refocus(x) -- explicitly refocus to start
dof = get_dofinfo()
x = dof.focus
last_x = x
if k == 1 then log[#log + 1] = "\n"..os.date() end
X_bracket()
temp = get_exp_count().." @ "..x.."mm"
if v == 1 then print(temp) end
if k == 1 then log[#log + 1] = temp end
repeat -- to capture focus brackets up to just past h/3
x = (x*(h*10 - 2*fl))/(h*10 - 2*x*10) -- position of next focus bracket
if x <= last_x or x <= 0 then
print("Unknown Error")
refocus(x_start)
return
end
refocus(x) -- request move to x
dof = get_dofinfo()
x = dof.focus -- register actual x moved by cam
last_x = x
X_bracket()
temp = get_exp_count().." @ "..x.."mm"
if v == 1 then print(temp) end
if k == 1 then log[#log + 1] = temp end
until (x > h/3)
temp1 = h
temp2 = base_h*(q+2)
refocus(temp1) -- take shot at h
X_bracket()
temp = get_exp_count().." @ "..temp1.."mm"
if v == 1 then print(temp) end
if k == 1 then log[#log + 1] = temp end
if temp2 > temp1 then -- take additional infinity focus shot
refocus(temp2)
X_bracket()
temp = get_exp_count().." @ "..temp2.."mm"
if v == 1 then print(temp) end
if k == 1 then log[#log + 1] = temp end
end
bookend()
temp = count.." focus brackets"
print(temp)
if k == 1 then log[#log + 1] = temp end
temp1 = ((10*dof.coc*base_h)/temp2 + 5)/10
temp = "Infinity blur "..temp1.."um"
if k == 1 then log[#log + 1] = temp end
if p ~= 0 and k == 1 then log[#log + 1] = "Exposure offset = "..p.."Ev" end
refocus(x_start)
if k == 1 then
print_screen(-2306)
for i = 1, #log do
print(log[i].."\n")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment