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
--[[ | |
@title QDFS | |
@chdk_version 1.6 | |
#coc = 15 "CoC (um)" [5 30] | |
#help = 1 "Console" {Off On} | |
Notes: | |
* This Quasi Depth of Field Scale script only runs on the M3, M10 or M100 with the XIMR version of CHDK. But note, not tested on the M100. | |
* Go to https://drive.google.com/drive/folders/1drk1xi6kMMIeF5xSqXgnpjGCffF8CVkd?usp=sharing for XIMR builds | |
* | |
* The script provides visual feedback for manual focus bracketing | |
* It was mainly written for wide angle lenses and specifically the EF-M 11-22mm ;-) | |
* The lens extension and pupil mag are ignored | |
* Only registered lenses can be used | |
* Changing focal length will reset the DoF scale | |
* Switch out and back into ALT mode will remove the DoF of the last captured image | |
* Switching the console on in the script's menu will provide feedback, eg the lens stepper count and the Canon lower and upper focus bounds | |
* If you are focused beyond the hypefocal, the DoF Scale will display the infinity blur in microms (on the left of the scale) | |
* The infinity blur info will disappear if you focus beyond the Canon 'data infinity', when additional info will be shown | |
* The number of brackets to the hyperfocal is shown on the right, as you focus | |
* If you focus at infinity you will see additional info | |
* Pressing the INFO button in ALT mode will toggle the bar on and off, eg as an aid to composing | |
* If things don't look right either change focal length to reset things or switch the camera on and off | |
Release 1.13 | |
photography.grayheron.net | |
August 2022 | |
--]] | |
bi = get_buildinfo() | |
require "drawings" | |
props=require'propcase' | |
capmode = require("capmode") | |
set_exit_key("down") -- change as required | |
tg = 242 | |
bar = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
ndof = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
fdof = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
lastdof = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
line = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
hpos = draw.add("line", 0, 0, 0, 0, tg) | |
h3pos = draw.add("line", 0, 0, 0, 0, tg) | |
h5pos = draw.add("line", 0, 0, 0, 0, tg) | |
h7pos = draw.add("line", 0, 0, 0, 0, tg) | |
h9pos = draw.add("line", 0, 0, 0, 0, tg) | |
h10pos = draw.add("line", 0, 0, 0, 0, tg) | |
blur = draw.add("string",0,0,"",tg,tg) | |
nb = draw.add("string",0,0,"",tg,tg) | |
fp = draw.add("elpsf", 1, 1, 1, 1, tg, tg) | |
cal = draw.add("string",0,0,"",tg,tg) | |
show = true | |
set_console_autoredraw(1) | |
set_console_layout(0,0,45,3) | |
reset_lens = false | |
-- Check a couple of things first | |
if not ((bi.platform == "m3") or (bi.platform == "m10") or (bi.platform == "m100")) then | |
print("Doesn't run on this Cam") | |
sleep(3000) | |
return | |
end | |
if get_focus_mode() ~= 1 then | |
print("Need manual focus mode") | |
sleep(3000) | |
return | |
end | |
if get_gui_screen_width() == 360 then | |
hdmi = 0 | |
else | |
hdmi = 60 | |
end | |
-- Functions -- | |
function get_focus_distance_lower() -- returns lower focus distance in mm, but note 'accuracy' is 1cm from Canon | |
local x=-1 | |
if (bi.platform=="m3") and (bi.platsub=="101a") then | |
x=peek(0x00244918, 2) | |
elseif (bi.platform=="m3") and (bi.platsub=="120f") then | |
x=peek(0x0024495C, 2) | |
elseif (bi.platform=="m3") and (bi.platsub=="121a") then | |
x=peek(0x0024495C, 2) | |
elseif (bi.platform=="m10") then -- same address in 110d, 110f, 110g | |
x=peek(0x00272018, 2) | |
elseif (bi.platform=="m100") and (bi.platsub=="100a") then | |
x=peek(0x001FC7FC, 2) | |
else | |
print('Wrong platform') | |
end | |
if x == -1 then return -1 else return x*10 end -- in mm | |
end | |
function get_focus_distance_upper() -- returns upper focus distance in mm, but note 'accuracy' is 1cm from Canon | |
local x=-1 | |
if (bi.platform=="m3") and (bi.platsub=="101a") then | |
x=peek(0x00244916, 2) | |
elseif (bi.platform=="m3") and (bi.platsub=="120f") then | |
x=peek(0x0024495A, 2) | |
elseif (bi.platform=="m3") and (bi.platsub=="121a") then | |
x=peek(0x0024495A, 2) | |
elseif (bi.platform=="m10") then -- same address in 110d, 110f, 110g | |
x=peek(0x00272016, 2) | |
elseif (bi.platform=="m100") and (bi.platsub=="100a") then | |
x=peek(0x001FC7FA, 2) | |
else | |
print('Wrong platform') | |
end | |
if x == -1 then return -1 else return x*10 end | |
end | |
function lens_name() -- does what it says | |
local pname = 0 | |
if (bi.platform=="m3") then | |
if (bi.platsub == "101a") then | |
pname = 0x00244969 | |
else | |
pname = 0x002449ad | |
end | |
elseif (bi.platform=="m10") then | |
pname = 0x272065 | |
elseif (bi.platform=="m100") and (bi.platsub == "100a") then | |
pname = 0x1FC84E | |
end | |
local len = peek(pname-1,1) | |
local i = 0 | |
local t = {} | |
while i < len do | |
local c = peek(pname + i, 1) | |
if c == 0 then break end | |
table.insert(t, string.char(c)) | |
i = i + 1 | |
end | |
local name = table.concat(t) | |
return name | |
end | |
function lens_cal() -- called at the start and when focal length changes: sets lens to MFD | |
reset_lens = false | |
call_event_proc('FA.Create') | |
draw.clear() | |
draw.replace(bar,"rectf",hdmi,0,hdmi+360,20,"white","white") | |
draw.replace(cal,"string",hdmi+180-50,2,"Calibrating","black","white") | |
draw.overdraw() | |
call_event_proc('InitializeAdjustmentSystem') | |
sleep(100) | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
repeat | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
sleep(50) | |
call_event_proc("EFLensCom.FocusSearchFar") | |
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') -- make sure we are at 'infinity' | |
max_count = temp | |
repeat -- to find some useful data | |
call_event_proc("EFLensCom.MoveFocus", -1, 1) | |
sleep(50) | |
until get_focus_distance_lower() < 81910 -- lower data infinity | |
far_count = call_event_proc('GetEFLensFocusPositionWithLensCom')+1 | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
repeat | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
sleep(50) | |
call_event_proc("EFLensCom.FocusSearchNear") | |
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') -- make sure we are at MFD | |
near_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
MFD = get_focus_distance_lower() | |
draw.clear() | |
end | |
function set_up() | |
dof = get_dofinfo() | |
F = fmath.new(dof.focal_length,1000) -- focal length in mm (real) | |
base_av = get_prop(props.USER_AV) | |
n = fmath.new(av96_to_aperture(base_av),1000) -- aperture number as a real | |
H = (1000*(F*F))/(n*coc) + F -- Relative to front principal | |
if f1 == f2 then | |
mag = m1 | |
else | |
mag = ((F-f1)*(m2-m1))/(f2-f1) + m1 | |
end | |
end | |
function lens_info() | |
if lens_name() == "EF-M11-22mm f/4-5.6 IS STM" then -- calculate lens thickness from manufacturer's data | |
f1 = 11 | |
f2 = 22 | |
m1 = fmath.new(13,100) | |
m2 = fmath.new(3,10) | |
return true | |
elseif lens_name() == "EF-M28mm f/3.5 MACRO IS STM" then | |
f1 = 28 | |
f2 = 28 | |
m1 = fmath.new(1,1) | |
m2 = fmath.new(1,1) | |
return true | |
elseif lens_name() == "EF-M55-200mm f/4.5-6.3 IS STM" then | |
return false | |
elseif lens_name() == "EF-M18-55mm f/3.5-5.6 IS STM" then | |
return false | |
elseif lens_name() == "EF-M15-45mm f/3.5-6.3 IS STM" then | |
return false | |
else -- lens not recognised | |
return false | |
end | |
end | |
function check_focus() | |
dof = get_dofinfo() | |
dirty = false | |
local test_count = call_event_proc('GetEFLensFocusPositionWithLensCom') - near_count | |
local test_F = fmath.new(dof.focal_length,1000) | |
local test_n = fmath.new(av96_to_aperture(get_user_av96()),1000) | |
if test_F ~= F then | |
repeat | |
dof = get_dofinfo() | |
F = fmath.new(dof.focal_length,1000) | |
sleep(500) | |
dof = get_dofinfo() | |
test_F = fmath.new(dof.focal_length,1000) | |
until test_F == F | |
grabp = false | |
dirty = true | |
reset_lens = true | |
image = false | |
F = test_F | |
n = test_n | |
H = 1000*(F*F)/(n*coc) + F | |
if f1 == f2 then | |
mag = m1 | |
else | |
mag = ((F-f1)*(m2-m1))/(f2-f1) + m1 | |
end | |
draw.remove(lastdof) | |
elseif test_n ~= n then | |
grabp = false | |
dirty = true | |
image = false | |
F = test_F | |
n = test_n | |
H = 1000*(F*F)/(n*coc) + F | |
draw.remove(lastdof) | |
elseif test_count ~= focus_count then -- update things | |
dirty = true | |
focus_count = test_count | |
end | |
end | |
function update() -- update focus position estimate in the console | |
if (focus_count + near_count) <= far_count then | |
if image then | |
print("Max:"..(max_count)..",Near:"..(near_count)..",Far:"..(far_count)..",Last:"..(last_count)) | |
else | |
print("Max:"..(max_count)..",Near:"..(near_count)..",Far:"..(far_count)..",H:"..H:int().."mm") | |
end | |
print("#:"..(focus_count)..",Lower:"..get_focus_distance_lower().."mm,Upper:"..get_focus_distance_upper().."mm") | |
else | |
if image then | |
print("Max:"..(max_count)..",Near:"..(near_count)..",Far:"..(far_count)..",Last:"..(last_count)) | |
else | |
print("Max:"..(max_count)..",Near:"..(near_count)..",Far:"..(far_count)..",H:"..H:int().."mm") | |
end | |
print("#:"..(focus_count)..", >INF") | |
end | |
pos = 0 | |
k = 360-2*pos | |
draw.replace(bar,"rectf",hdmi+pos,0,hdmi+k,20,"white","white") | |
local J1 = far_count - near_count | |
u = (F*(J1 + J1*mag - mag*focus_count))/(mag*(J1-focus_count)) | |
mfd = (F*(J1 + J1*mag - mag*0))/(mag*(J1-0)) -- MFD relative to the front principal | |
halfdof = (mfd*k)/H | |
p = k - (mfd*k)/u | |
p = p:int() | |
halfdof = halfdof:int() | |
pj = p | |
fill = "grey_light" | |
if image then | |
if p == pdof then | |
fill = "yellow" | |
elseif p >= (pdof-2*halfdof) and p <= (pdof+2*halfdof) then | |
fill = "green" | |
else | |
fill = "red" | |
end | |
end | |
draw.replace(ndof,"rectf",hdmi+pos+p-halfdof,14,hdmi+pos+p,20,"black",fill) | |
draw.replace(fdof,"rectf",hdmi+pos+p,14,hdmi+pos+p+halfdof,20,"black",fill) | |
draw.replace(line,"rectf", hdmi+pos,9,hdmi+k,11,"black","black") | |
draw.replace(fp,"elpsf", hdmi+pos+p,17,2,2,"black","black") | |
local h1 = H:int() | |
p = (k - (mfd*k)/(H)):int() | |
draw.replace(hpos,"line",hdmi+pos+p,0,hdmi+pos+p,20,"red") | |
p = (k - (mfd*k)/((H/2))):int() | |
draw.replace(h3pos,"line",hdmi+pos+p,3,hdmi+pos+p,17,"black") | |
p = (k - (mfd*k)/((H/4))):int() | |
draw.replace(h5pos,"line",hdmi+pos+p,3,hdmi+pos+p,17,"black") | |
p = (k - (mfd*k)/((H/8))):int() | |
draw.replace(h7pos,"line",hdmi+pos+p,3,hdmi+pos+p,17,"black") | |
p = (k - (mfd*k)/((H/16))):int() | |
draw.replace(h9pos,"line",hdmi+pos+p,3,hdmi+pos+p,17,"black") | |
p = (k - (mfd*k)/((H/32))):int() | |
draw.replace(h10pos,"line",hdmi+pos+p,3,hdmi+pos+p,17,"black") | |
local qq = 0 | |
if u:int() >= H:int() then | |
qq = ((coc*H)/u):int() | |
if qq >= 0 then | |
qq = " "..tostring(qq).."um " | |
draw.replace(blur,"string",hdmi+pos+5,2,qq,"black","white") | |
else | |
draw.remove(blur) | |
end | |
else | |
draw.remove(blur) | |
end | |
if u:int() <= (H/3):int() and u:int() > 0 then | |
qq = (H-u)/(2*u) + 1 | |
qq = " #"..tostring(qq:int()).." " | |
draw.replace(blur,"string",hdmi+k-6*(string.len(qq))-15,2,qq,"black","white") | |
else | |
draw.remove(nb) | |
end | |
if get_focus_distance_lower() >= 81910 and not image then | |
qq1 = (H-mfd)/(2*mfd) + 1 | |
qq1 = tostring(qq1:int()) | |
qq = " CoC:"..coc..", MFD:"..mfd:int()..", H:"..H:int()..", #:"..qq1 | |
draw.replace(cal,"string",hdmi+pos+5,2,qq,"black","white") | |
else | |
draw.remove(cal) | |
end | |
end | |
function check_overlaps() | |
local temp = focus_count | |
if get_gui_screen_width() == 360 then | |
hdmi = 0 | |
else | |
hdmi = 60 | |
end | |
if grabp and image then | |
draw.replace(lastdof,"rectf",hdmi+pos+pdof-halfdof,0,hdmi+pos+pdof+halfdof,6,"black","blue") | |
grabp = false | |
end | |
dirty = false | |
draw.overdraw() | |
end | |
function check_buttons_etc() | |
wait_click(50) -- check for a button press | |
if (is_key("print") and get_alt_mode()) then | |
shoot() | |
last_count = focus_count | |
image = true | |
dirty = true | |
grabp = true | |
pdof = pj | |
elseif (is_key("display") and get_alt_mode()) then | |
if show then | |
draw_clear() | |
show = false | |
elseif not show then | |
draw.overdraw() | |
show = true | |
end | |
end | |
end | |
-- Main Section -- | |
if lens_info() == false then -- then don't use | |
print("Lens not registered") | |
sleep(3000) | |
return | |
end | |
show = true | |
grabp = false | |
set_up() | |
lens_cal() | |
last_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
focus_count = last_count | |
if (last_count - near_count) ~= 0 then | |
print("Calibration failed") | |
sleep(3000) | |
return | |
end | |
if help == 0 then -- then switch off console display | |
set_console_layout(0,0,1,0) | |
print("") | |
set_console_autoredraw(-1) | |
else | |
set_console_layout(0,0,45,2) | |
end | |
finish = false | |
image = false | |
repeat -- stay here | |
if get_alt_mode() then | |
check_focus() | |
check_buttons_etc() | |
if reset_lens then lens_cal() end -- focal length changed so recalibrate lens | |
if screen_needs_refresh() then dirty = true end | |
if dirty and show then | |
update() | |
check_overlaps() | |
end | |
end | |
if not get_alt_mode() and show then -- reset | |
image = false | |
draw.remove(lastdof) | |
dirty = true | |
end | |
sleep(100) -- adjust as required | |
until finish -- exit via pressing ALT exit button |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment