Last active
July 16, 2022 20:48
-
-
Save pigeonhill/f2b5e1b16e2707d5382966cc9140af3b to your computer and use it in GitHub Desktop.
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 FBTL | |
@chdk_version 1.6 | |
#overlap = 15 "Overlap Blur (um)" [5 30] | |
#help = 0 "Console" {Off On} | |
Notes: | |
* This test 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 feedback for manual focus bracketing. | |
* Set the overlap blur in the script's menu | |
* 'Trafic Lights' will show on the left or the right, once an image is taken | |
* Black shows the script is running | |
* Yellow means you are positioned at the same location as the last captured image | |
* Green means that DoF (left = near and right = far) have a positive overlap | |
* Red means you have a negative overlap | |
* White means you are at infinity | |
* Changing focal length will reset the traffic lights | |
* Switch the console on in the script's menu will provide feedback on the focus, DoFs and the lens stepper count | |
* If things don't look right either change focal length to reset things or switch the script off and on, ie via the exit button | |
Release 1.02 | |
photography.grayheron.net | |
July 2022 | |
--]] | |
bi = get_buildinfo() | |
require "drawings" | |
props=require'propcase' | |
set_exit_key("down") -- change as required | |
set_console_autoredraw(1) | |
set_console_layout(0,0,45,3) | |
focus_count = -999 | |
reset_lens = false | |
INF = 999000 -- infinity trap | |
count = 0 | |
U = 0 | |
tg = 242 | |
-- 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_gui_screen_width() ~= 360 then | |
print("Need an XIMR build") | |
sleep(3000) | |
return | |
end | |
-- Functions -- | |
function units(xx) -- pretty print of focus distance | |
local xr ="" | |
if xx:int() > 5000 then | |
xr=(xx/1000):tostr(1).."m" | |
elseif xx:int() > 1000 then | |
xr=(xx/10):tostr(0).."cm" | |
else | |
xr=(xx):tostr(0).."mm" | |
end | |
return xr | |
end | |
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 move_focus_by(n) -- steps | |
local end_count = call_event_proc('GetEFLensFocusPositionWithLensCom') + n | |
call_event_proc("EFLensCom.MoveFocus",n, 1) | |
repeat -- wait until move complete | |
sleep(20) | |
until call_event_proc('GetEFLensFocusPositionWithLensCom') == end_count | |
return end_count | |
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 | |
print("Calibrating") | |
call_event_proc('InitializeAdjustmentSystem') | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
repeat | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
call_event_proc("EFLensCom.FocusSearchFar") | |
sleep(50) | |
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') -- make sure we are at 'infinity' | |
repeat -- to find some useful data | |
call_event_proc("EFLensCom.MoveFocus", -1, 1) | |
sleep(50) | |
until get_focus_distance_lower() < 81000 | |
xc = get_focus_distance_lower() -- Canon lower focus distance 'infinity' start | |
sleep(20) | |
far_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
repeat | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
call_event_proc("EFLensCom.FocusSearchNear") | |
sleep(10) | |
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') -- make sure we are at MFD | |
near_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
MFD = fmath.new(get_focus_distance_lower(),1) | |
k = (MFD*(MFD-4*F)):sqrt() | |
total_count = far_count - near_count -- lens max number of steps at the current focal length | |
reset_lens = false | |
end | |
function TL_focus_pos(nn) -- functionalised estimate of focus from the stepper motor position | |
local a = fmath.new(get_focus_distance_lower(),1) | |
local b = fmath.new(get_focus_distance_upper(),1) | |
local c = ((2*a*b)/(a+b)):int() | |
local d = MFD | |
-- use a, b or c to 'scale'' the basic functional form | |
-- change this function as required | |
-- With the 11-22mm lens, a seems to work well | |
local temp = (total_count*MFD - 2*F*nn)/(total_count-nn) - (a*nn)/(total_count) | |
if temp:int() < 0 then | |
return fmath.new(INF + 1,1) | |
else | |
return temp | |
end | |
end | |
function update_DoFs(xx) -- update DoF related stuff | |
h = (1000*F*F)/(N*overlap) -- short hyperfocal (mm) | |
H = h + F -- 'full' hyperfocal (mm), as measured from the thin lens principal, ie NOT the sensor | |
u = (((xx*(xx-4*F)):sqrt() + xx)/2):int() -- focus distance in mm from front principal | |
pmag = 1 -- ignore pupil magnification | |
t = 0 -- as using a thin lens, the hiatus is zero | |
if xx:int() < INF then | |
ndof = (F*F)/(u-F) | |
ndof = ndof+(h*(F-h*pmag))/(pmag*(u+h-F)) | |
ndof = (ndof+(pmag*(2*F+h+t)-F)/pmag) | |
else | |
ndof = H | |
end | |
if 2*u < H:int() then | |
fdof = (F*F)/(u-F) | |
fdof = fdof-(h*(F+h*pmag))/(pmag*(u-h-F)) | |
fdof = (fdof+(pmag*(2*F-h+t)-F)/pmag) | |
elseif u < H:int() then | |
fdof = (F*F)/(u-F) | |
fdof = fdof-(h*(F+h*pmag))/(pmag*(u-h-F)) | |
fdof = (fdof+(pmag*(2*F-h+t)-F)/pmag) | |
else | |
fdof = fmath.new(INF+1) | |
end | |
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 | |
end | |
function lens_info() | |
if lens_name() == "EF-M11-22mm f/4-5.6 IS STM" then -- calculate lens thickness from manufacturer's data | |
return true | |
elseif lens_name() == "EF-M28mm f/3.5 MACRO IS STM" then | |
return true | |
elseif lens_name() == "EF-M55-200mm f/4.5-6.3 IS STM" then | |
return true | |
elseif lens_name() == "EF-M18-55mm f/3.5-5.6 IS STM" then | |
return true | |
elseif lens_name() == "EF-M15-45mm f/3.5-6.3 IS STM" then | |
return true | |
else -- lens not recognised | |
return false | |
end | |
end | |
function check_focus() | |
dof = get_dofinfo() | |
dirty = false | |
local test_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
local test_n = fmath.new(av96_to_aperture(get_user_av96()),1000) | |
local test_F = fmath.new(dof.focal_length,1000) | |
if test_F ~= F then -- recalibrate lens and update focus position | |
dirty = true | |
reset_lens = true | |
image = false | |
clr = tg | |
draw.replace(left,"rectf",hdmi+0,0,hdmi+10,15,clr,clr) -- update left traffic light | |
draw.replace(right,"rectf",hdmi+350,0,hdmi+360,15,clr,clr) -- update right traffic light | |
elseif test_count ~= focus_count then -- update focus position | |
dirty = true | |
end | |
F = test_F | |
focus_count = test_count | |
end | |
function update() -- update focus position estimate in the console | |
count = call_event_proc('GetEFLensFocusPositionWithLensCom') - near_count | |
x = TL_focus_pos(count) | |
update_DoFs(x) | |
if x:int() < INF and count <= total_count then | |
if fdof:int() > INF then | |
print(units(x)..", NDoF:"..ndof:int()..", FDoF:oo, #:"..count) | |
else | |
print(units(x)..", NDoF:"..ndof:int()..", FDoF:"..fdof:int()..", #:"..count) | |
end | |
else | |
print("oo"..",NDoF = "..ndof:int()) | |
end | |
end | |
function check_overlaps() | |
if get_gui_screen_width() == 360 then | |
hdmi = 0 | |
else | |
hdmi = 60 | |
end | |
if get_exp_count() == ecnt then | |
if not image then | |
draw.replace(left,"rectf",hdmi+0,0,hdmi+10,15,"black","black") | |
draw.replace(right,"rectf",hdmi+350,0,hdmi+360,15,"black","black") | |
draw.overdraw() | |
end | |
else | |
if image then -- display traffic lights | |
local clr = tg | |
if x == last_image_x then | |
clr = "yellow" | |
elseif x:int() > INF then | |
clr = "white" | |
elseif (ndof >= last_image_ndof) and (ndof <= last_image_fdof) then | |
clr = "green" | |
elseif (ndof > last_image_fdof) or (ndof < last_image_ndof) then | |
clr = "red" | |
end | |
draw.replace(left,"rectf",hdmi+0,0,hdmi+10,15,clr,clr) -- update left traffic light | |
if x == last_image_x then | |
clr = "yellow" | |
elseif x:int() > INF then | |
clr = "white" | |
elseif (fdof <= last_image_fdof) and (fdof >= last_image_ndof) then | |
clr = "green" | |
elseif (fdof > last_image_fdof) or (fdof < last_image_ndof) then | |
clr = "red" | |
end | |
draw.replace(right,"rectf",hdmi+350,0,hdmi+360,15,clr,clr) -- update right traffic light | |
else | |
draw.replace(left,"rectf",hdmi+0,0,hdmi+10,15,"black","black") | |
draw.replace(right,"rectf",hdmi+350,0,hdmi+360,15,"black","black") | |
end | |
draw.overdraw() | |
dirty = false | |
end | |
end | |
function check_buttons_etc() | |
wait_click(50) -- check for a button press | |
if (is_key("print") and get_alt_mode()) then | |
shoot() | |
snapped = true | |
last_image_ndof = ndof | |
last_image_fdof = fdof | |
last_image_x = x | |
last_image_u = u | |
finish = false | |
image = true | |
dirty = true | |
end | |
end | |
-- Main Section -- | |
if lens_info() == false then -- then don't use | |
print("Can't use for now") | |
sleep(3000) | |
return | |
end | |
call_event_proc('FA.Create') | |
sleep(100) | |
set_up() | |
lens_cal() | |
x = TL_focus_pos(count) | |
update_DoFs(x) | |
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,1) | |
end | |
finish = false | |
image = false | |
last_image_ndof = fmath.new(0) | |
last_image_fdof = fmath.new(0) | |
last_image_x = fmath.new(0) | |
ecnt = get_exp_count() | |
left = draw.add("rectf", 0, 0, 0, 0,"black","black") | |
right = draw.add("rectf", 0, 0, 0, 0, "black","black") | |
repeat -- stay here | |
check_focus() | |
if reset_lens then lens_cal() end -- focal length changed so recalibrate lens | |
if screen_needs_refresh() then dirty = true end | |
if dirty then update() end | |
check_buttons_etc() | |
check_overlaps() | |
sleep(100) -- adjust a 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