Last active
April 7, 2023 17:30
-
-
Save pigeonhill/cdf25239bae6a4343e6431fb4c10c849 to your computer and use it in GitHub Desktop.
M3 Focus & Exposure Bracketing
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 LBS-M | |
@chdk_version 1.7 | |
@subtitle Bracketing Options | |
#mode = 0 "Focus?" {Off X2INF Min2INF Manual Min2X SupRes} | |
#bracket = 0 "Exposure?" {Off 1(4Ev) 1(3Ev) 1(2Ev) 2(2Ev) 3(2Ev) ISO AutoX>H Wind3Ev Wind4Ev HandH AutoS>H} | |
#sky = 0 "Sky?" {Off 2Ev 3Ev 4Ev 5Ev 6Ev ETTR} | |
#ndf = 0 "ND?" [-5 30] | |
@subtitle Bracketing Settings | |
#infinity = 3 "Infinity Focus (xH)" [2 4] | |
#overlap = 15 "Overlap Blur (um)" [5 30] | |
#pmag = 1 "Assumed Pupil Mag" [1 6] | |
#hhmin = 30 "HH Min Tv (1/x s)" [10 100] | |
#isoval = 0 "X Bracketing Value" {+1/200 +2/400 +3/800 +4/1600 +5/3200} | |
#srpix = 0 "SupRes Pixel Shift?" {Off -+ ++} | |
@subtitle Other Settings | |
#dofs = 0 "DoF Display" {Blur DoFs Both} | |
#diff = 0 "Diffraction Aware?" {Off Vis IR} | |
#traf = 0 "Traffic Lights" {Off On} | |
#evmode = 0 "Exposure Help" {Off Survey ETTR} | |
#sleep_time = 0 "Delay (s)" [0 10] | |
#bookends = 1 "Bookends?" {Off On} | |
#histoon = 0 "CHDK Histogram" {Off On} | |
#screen_off = 0 "Screen?" {Off On} | |
#log = 0 "Log?" {Off On Reset} | |
#help = 0 "Console" {Off On} | |
#lens = 0 "Lens Name?" {Off On} | |
#usefd = 0 "Focus distance" {lower Upper Harmonic} | |
#hlw = 1 "Over X Warning Bins" [1 10] | |
#bp = 0 "Black Level Sensitivity" {Normal Medium High} | |
#limit = 0 "ETTR limit" [0 10] | |
#ettro = 0 "ETTR Offset (Ev)" [0 5] | |
#title = 1 "Title Line" {Off Full Exit} | |
Notes: | |
* This script only runs on the M3 or M10 with the XIMR version of CHDK (1.7) and the camera should be in M mode. | |
* Focus functionality and time based ND bracketing needs a registered EF-M lens. Non registered EF-M lenses can only be used with certain exposure bracketing logic. | |
* The focus bracketing works best with wide angle lenses, as tele lenses will usually mean too many focus brackets - be warned ;-) | |
* Set the CHDK ALT button to anything other than m-FN (M3) or VIDEO (M10), as these buttons are used as a second shutter button to start bracketing | |
* Register your lens below in the lens_info() function. Note only EF-M lenses will allow full focus functionality. Non EF-M lenses may 'play up' ;-) | |
* This script is not designed for macro focus stacking; it is intended for non-macro, deep focus photography only. | |
* If you reset/delete the log, you need to set the log menu after. | |
* Use the M-Fn button on the M3 to initiate bracketing, or the VIDEO button on the M10. Note there is a difference between Off and Manual in focus bracketing options | |
* For non-auto focus control I recommend using Manual with Traffic Lights on. Off will just take a single image without traffic lights | |
* In manual mode, if traffic light (TL) feedback is enabled, once an image is captured, the left hand TL shows the near DoF's focus overlap state, relative to the last image captured... | |
* ...and the right TL shows the far DoF's overlap state relative to the last image captured. Yellow = same focus; green = a positive overlap; red = a negative overlap (a gap). | |
* Changing focal length or aperture will reset the traffic lights. | |
* The CHDK histogram can be toggled on and off by pressing the MENU button. Postion the histogram in the CHDK OSD editor. | |
* A long half shutter press will allow you to toggle and set the focus and exposure bracketing, delay, bookends and sky bracketing by using the LEFT, RIGHT, DOWN, UP and SET buttons respectively... | |
* ...followed by a half shutter button press to return to the shooting mode | |
* Auto ETTR by pressing the wheel right button. | |
* If auto exposure bracketing is selected, first set the exposure for the shadows; the script will auto bracket by the requested Ev step until the ETTR exposure is reached | |
* Exposure survey/help provides two options. The first provides Ev feed back on the current exposure relative to the last captured image. The second provides... | |
* ...1/3 stop feedback in the top 1Ev highlight area, showing the % of the histogram in each 1/3 stop. If any of the histogram is in the top 3 bins of the histogram, then... | |
* ...the display switches to show the % of the histogram in those three bins | |
* Use the "Assumed Pupil Mag" menu item to refine focus overlap insurance. Use 1 for a telephoto lens... | |
* ...for a retrofocus lens simply guess the pupil mag if you don't know it (exit/entrance ratio), but round up, ie slightly over estimate for DoF insurance | |
* All UI presented distances, ie focus and DoFs, are relative to the sensor plane. | |
* Note: If the bar disappears, just do a half shutter press. | |
* Exit script via a full shutter press | |
Release 2.02 | |
photography.grayheron.net | |
April 2023 | |
--]] | |
require "drawings" | |
props=require'propcase' | |
capmode = require("capmode") | |
bi = get_buildinfo() | |
current_focus_mode = get_focus_mode() | |
current_mode = capmode.get_name() | |
if current_focus_mode ~= 1 then set_mf(1) end | |
if histoon == 0 then set_config_value(1060,0) else set_config_value(1060,1) end | |
inf = 81000 -- infinity trap | |
dirty = true | |
set_console_autoredraw(1) | |
set_console_layout(0,0,45,3) | |
tg = 242 | |
non_m = false | |
extension = 0 | |
total_count = 0 | |
near_count = 0 | |
f_near = 0 | |
tv_str = {"32", "25.4","20","16", "12.7", "10","8", "6.3","5","4","3.2", "2.5","2", | |
"1.6", "1.3", "1", "0.8", "0.6", "0.5", "0.4", "0.3", "1/4", "1/5", "1/6", "1/8", "1/10", "1/13", | |
"1/15", "1/20", "1/25", "1/30", "1/40", "1/50", "1/60", "1/80", "1/100", "1/125", "1/160", "1/200", | |
"1/250", "1/320", "1/400", "1/500", "1/640","1/800", "1/1000", "1/1250", "1/1600","1/2000","1/2500", | |
"1/3200","1/4000", "1/5000", "1/6400", "1/8000", "1/10000", "1/12500", "1/16000", "1/20000", "1/25000", | |
"1/32000", "1/40000"} | |
exp_state = {"Off","1(4Ev)","1(3Ev)","1(2Ev)","2(2Ev)","3(2Ev)","ISO","AutoX>H","Wind3Ev","Wind4Ev","HandH","AutoS>H"} | |
sky_state = {"Off","2Ev","3Ev","4Ev","5Ev","6Ev","ETTR"} | |
focus_state = {"Off","X2INF","Min2INF","Manual","Min2X","SupRes"} | |
toggle_info = false | |
-- Check if OK to use | |
if not ((bi.platform == "m3") or (bi.platform == "m10")) 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 | |
if capmode.get_name() ~= "M" then | |
print("Put camera in M mode") | |
sleep(3000) | |
return | |
end | |
if log == 2 then | |
print_screen(1) | |
print("Log reset") | |
print("Change log menu") | |
sleep(3000) | |
print_screen(0) | |
return | |
end | |
set_draw_title_line(title) -- switch off CHDK info according to the menu request | |
function units(xx) | |
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 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 lens front principal, ie NOT the sensor | |
local q = xx-t | |
u = (((q*(q-4*F)):sqrt() + q)/2):int() -- focus distance in mm from front principal | |
if xx < 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) | |
num = 0 | |
local uc = u | |
repeat | |
num = num + 1 | |
new_uc = 2*F*F*(pmag-1) + F*(uc-2*pmag*uc) + h*pmag*uc | |
new_uc = (new_uc/( F*(2*pmag-1) + pmag*(h-2*uc))) | |
uc = new_uc | |
until uc:int() >= (H/3):int() | |
num = num + 1 | |
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) | |
num = 2 | |
else | |
fdof = fmath.new(inf+1) | |
num = 1 | |
end | |
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 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 | |
end | |
function get_focus_distance() | |
local a = fmath.new(get_focus_distance_lower(),1) | |
local b = fmath.new(get_focus_distance_upper(),1) | |
if usefd == 0 then | |
return a:int() | |
elseif usefd == 1 then | |
return b:int() | |
else | |
if b:int() >= inf then | |
return b:int() | |
else | |
return ((2*a*b)/(a+b)):int() | |
end | |
end | |
end | |
function refocus_to(xx) -- Only moves towards infinity. Returns requested focus distance in mm | |
local current_x = x | |
local last_step_x = current_x | |
local steps_total = 0 | |
local steps = 1 | |
local last_step_count = steps_total | |
local steps_back = 0 | |
if xx < current_x then return -1 end -- don't use | |
if xx <= get_focus_distance_upper() then -- xx is within the current Canon focus step | |
current_x = get_focus_distance_upper() | |
repeat | |
call_event_proc("EFLensCom.MoveFocus", steps, 1) | |
sleep(25) | |
steps_total = steps_total + 1 | |
until get_focus_distance_lower() >= current_x | |
else -- find the Canon focus step that covers xx | |
while current_x < xx do | |
call_event_proc("EFLensCom.MoveFocus", steps, 1) -- move smallest step you can towards infinity | |
steps_total = steps_total + steps | |
sleep(25) -- for system to catch up | |
current_x = get_focus_distance_lower() -- Get Canon based focus position | |
if (current_x ~= last_step_x) and (current_x < xx) then -- just went through an intermediate step change, ie not yet reached the step that covers xx | |
last_step_x = current_x | |
last_step_count = steps_total -- close enough | |
end | |
end | |
end | |
-- now fine tune position backwards if required | |
steps_back = ((current_x - xx) * (steps_total - last_step_count)) / (current_x - last_step_x) | |
if steps_back > 0 then | |
for i = 1, steps_back do call_event_proc("EFLensCom.MoveFocus", -steps, 1) end | |
end | |
sleep(25) -- for system to catch up | |
return xx -- return request focus position, eg the 'best' estimate in mm as to focus position | |
end | |
function lens_name() | |
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() | |
call_event_proc('FA.Create') | |
call_event_proc('InitializeAdjustmentSystem') | |
sleep(100) | |
call_event_proc("EFLensCom.FocusSearchNear") | |
local temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
repeat | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
call_event_proc("EFLensCom.FocusSearchNear") | |
sleep(10) | |
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') | |
near_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
f_near = get_focus_distance_lower() | |
call_event_proc("EFLensCom.FocusSearchFar") | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
repeat | |
temp = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
call_event_proc("EFLensCom.FocusSearchFar") | |
sleep(10) | |
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') | |
local far_count = call_event_proc('GetEFLensFocusPositionWithLensCom') | |
local f_far = get_focus_distance_lower() | |
sleep(100) | |
print("near count = "..near_count) | |
print("far count = "..far_count) | |
print("near focus = "..f_near) | |
print("far focus = "..f_far) | |
extension = (F*F)/(f_near-F) -- lens extension at MFD using thin lens model | |
total_count = far_count - near_count | |
print("Total Count = "..total_count) | |
end | |
function TL_count(xx) | |
local xval = (total_count)*((F*F+F*extension-extension*xx)/(extension*(F-xx))) + near_count | |
return xval:int() | |
end | |
function restore() | |
clr = tg | |
draw.replace(obj5,"rectf",hdmi+0,0,hdmi+10,15,clr,clr) -- update left traffic light | |
draw.replace(obj6,"rectf",hdmi+350,0,hdmi+360,15,clr,clr) -- update right traffic light | |
set_prop(props.USER_TV,base_s) | |
set_prop(props.USER_AV,base_av) | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
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) | |
print_screen(0) | |
cls() | |
sleep(1000) | |
exit_alt() | |
end | |
function my_restore() -- currently the same as the CHDK restore function ;-) | |
clr = tg | |
draw.replace(obj5,"rectf",hdmi+0,0,hdmi+10,15,clr,clr) -- update left traffic light | |
draw.replace(obj6,"rectf",hdmi+350,0,hdmi+360,15,clr,clr) -- update right traffic light | |
set_prop(props.USER_TV,base_s) | |
set_prop(props.USER_AV,base_av) | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
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) | |
print_screen(0) | |
cls() | |
sleep(1000) | |
exit_alt() | |
end | |
function set_up() | |
if current_focus_mode ~= 1 then set_mf(1) end -- just in case | |
if (current_mode ~= "M") then capmode.set("M") end -- just in case | |
dof = get_dofinfo() | |
F = fmath.new(dof.focal_length,1000) -- focal length in mm (real) | |
s = get_prop(props.USER_TV) | |
base_s = s | |
base_av = get_prop(props.USER_AV) | |
base_iso = get_iso_mode() | |
n = fmath.new(av96_to_aperture(base_av),1000) -- aperture number as a real | |
s_ev = s | |
last_s = s | |
x = get_focus_distance() | |
end | |
function myshoot() | |
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 X_bracket() -- multi image capture options | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
s = get_prop(props.TV) | |
set_tv96_direct(s) -- just in case | |
set_iso_mode(base_iso) | |
if bracket == 0 then | |
snap() | |
elseif bracket == 1 then | |
snap() | |
set_tv96_direct(s - 96 * 4) | |
snap() | |
elseif bracket == 2 then | |
snap() | |
set_tv96_direct(s - 96 * 3) | |
snap() | |
elseif bracket == 3 then | |
snap() | |
set_tv96_direct(s - 96 * 2) | |
snap() | |
elseif bracket == 4 then | |
snap() | |
set_tv96_direct(s - 96 * 2) | |
snap() | |
set_tv96_direct(s - 96 * 4) | |
snap() | |
elseif bracket == 5 then | |
snap() | |
set_tv96_direct(s - 96 * 2) | |
snap() | |
set_tv96_direct(s - 96 * 4) | |
snap() | |
set_tv96_direct(s - 96 * 6) | |
snap() | |
elseif bracket == 6 then | |
local iso = get_iso_mode() | |
set_iso_mode(iso) | |
sleep(100) | |
snap() | |
local isov = iso | |
isov = isov + (isoval+1)*3 | |
if isov > 16 then isov = 16 end | |
set_iso_mode(isov) | |
snap() | |
set_iso_mode(iso) | |
elseif bracket == 7 or bracket == 11 then -- auto bracket | |
shot_histo_enable(1) | |
snap() | |
sleep(100) | |
local lower = 1024 - hlw | |
local test=get_histo_range(lower,1023) | |
local test2 = get_histo_range(128,128+bp) | |
local step = 1 | |
while test > 0 and (s + 96 * (isoval+1) * step) <= 1152 do | |
set_tv96_direct(s + 96 * (isoval+1) * step) | |
snap() | |
sleep(100) | |
test=get_histo_range(lower,1023) | |
step = step + 1 | |
end | |
step = 1 | |
if bracket == 11 then -- deal with the shadows | |
while test2 > 0 and (s - 96 * (isoval+1) * step) >= -480 do | |
set_tv96_direct(s - 96 * (isoval+1) * step) | |
snap() | |
sleep(100) | |
test2=get_histo_range(128,128+bp) | |
step = step + 1 | |
end | |
end | |
shot_histo_enable(0) | |
elseif bracket == 8 or bracket == 9 then | |
snap() | |
local iso = get_sv96() | |
set_sv96(iso+96*(bracket-5)) | |
set_tv96_direct(s + 96*(bracket-5)) | |
snap() | |
set_sv96(iso) | |
elseif bracket == 10 then | |
local tv_test = tv96_to_usec(s) -- shutter speed in us | |
if tv_test <= 1000000/hhmin then | |
print("HH Check OK") | |
snap() | |
set_tv96_direct(usec_to_tv96(1000000/hhmin)) | |
snap() | |
local iso = get_iso_mode() | |
if isoval == 1 then | |
isov = 800 | |
elseif isoval == 2 then | |
isov = 1600 | |
elseif isoval == 3 then | |
isov = 3200 | |
end | |
set_iso_mode(isov) | |
set_tv96_direct(usec_to_tv96(1000000/hhmin)) | |
snap() | |
set_iso_mode(iso) | |
else | |
print("Check Xposure") | |
end | |
end | |
set_tv96_direct(s) | |
end | |
function bookend() | |
local current_tv = get_prop(props.USER_TV) | |
set_tv96_direct(960) | |
if not non_m then set_av96_direct(get_max_av96()) end | |
shoot() | |
set_tv96_direct(current_tv) | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
if not non_m then set_av96_direct(base_av) end | |
end | |
function hiatus() | |
local M = fmath.new(Mmax,1000) | |
local Fr = fmath.new(Fmax,1000) | |
-- Note the following is an estimate of min zoomed mag, based on assuming MFD is fixed across the zoom range and a thin lens model | |
local M1 = (1+M) | |
local k = Fr/F | |
m=k*M1*M1 | |
m=m-(M1*(k:sqrt())*(k*M1*M1-4*M):sqrt()) | |
m=m-2*M | |
m=m/(2*M) | |
t = (F * (1 + m) * (1 + m)) | |
t = MFD - t/m -- this is an estimate of the spilt thin lens thickness (mm) | |
return t | |
end | |
function lens_info() | |
MFD = 0 | |
if lens_name() == "EF-M11-22mm f/4-5.6 IS STM" then -- calculate lens thickness from manufacturer's data | |
--if lens_name() == "E-M11-22mm f/4-5.6 IS STM" then -- calculate lens thickness from manufacturer's data | |
-- add other lenses as required, ie replace the following for your lens | |
-- For the above lens, 300 is the lens max magnification x 1000, ie from manufacturer's data or your measurement | |
-- 22000 is the lens maximun zoom, or the prime, focal length in microns | |
-- 150 is the lens minimum focus distance (mm), ie from manufacturer's data or your measurement | |
Fmax = 22000 -- Longest focal length (mm) * 1000 | |
Mmax = 300 -- Max magnification * 1000 | |
MFD = 150 -- Minimum Focus Distance in mm | |
t = hiatus() -- distance between front and rear principals | |
return true | |
elseif lens_name() == "EF-M28mm f/3.5 MACRO IS STM" then | |
Fmax = 28000 -- Longest focal length (mm) * 1000 | |
Mmax = 1000 -- Max magnification * 1000 | |
MFD = 97 -- Minimum Focus Distance in mm | |
t = hiatus() -- distance between front and rear principals | |
return true | |
elseif lens_name() == "EF-M55-200mm f/4.5-6.3 IS STM" then | |
Fmax = 200000 -- Longest focal length (mm) * 1000 | |
Mmax = 210 -- Max magnification * 1000 | |
MFD = 960 -- Minimum Focus Distance in mm | |
t = hiatus() -- distance between front and rear principals | |
return true | |
elseif lens_name() == "EF-M18-55mm f/3.5-5.6 IS STM" then | |
Fmax = 55000 -- Longest focal length (mm) * 1000 | |
Mmax = 240 -- Max magnification * 1000 | |
MFD = 150 -- Minimum Focus Distance in mm | |
t = hiatus() -- distance between front and rear principals | |
return true | |
elseif lens_name() == "EF-M15-45mm f/3.5-6.3 IS STM" then | |
Fmax = 45000 -- Longest focal length (mm) * 1000 | |
Mmax = 250 -- Max magnification * 1000 | |
MFD = 250 -- Minimum Focus Distance in mm | |
t = hiatus() -- distance between front and rear principals | |
return true | |
--[[ | |
elseif lens_name() == "10-20mm" then | |
Fmax = 20000 -- Longest focal length (mm) * 1000 | |
Mmax = 130 -- Max magnification * 1000 | |
MFD = 240 -- Minimum Focus Distance in mm | |
t = hiatus() -- distance between front and rear principals | |
return true | |
elseif lens_name() == "your lens" then | |
copy template above | |
]] | |
else -- lens not recognised | |
return false | |
end | |
end | |
function update() | |
local pos = 0 | |
if get_gui_screen_width() == 360 then | |
hdmi = 0 | |
else | |
hdmi = 60 | |
end | |
lens_info() | |
update_DoFs(x) -- update u and DoFs | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if x > inf then | |
temp = ">>H:INF" | |
elseif u >= H:int() then | |
temp = (10*(u/H)):int() | |
if temp >= 50 then | |
temp = ">>H:"..units(fmath.new(x,1)) | |
else | |
temp = (temp/10).."."..((temp-(temp/10)*10)).."xH:"..units(fmath.new(x,1)) | |
end | |
else | |
local xl = get_focus_distance_lower() | |
local xu = get_focus_distance_upper() | |
--temp = "#"..num..":"..units(fmath.new(x,1)) | |
temp = "#"..num..":"..units(fmath.new(xl,1)).."-"..units(fmath.new(xu,1)) | |
end | |
draw.replace(obj2,"string",hdmi+10,0,temp,"white",tg) -- draw focus position info | |
local inf_blur = ((overlap*(H-F))/(u-F)) | |
if x >= inf then inf_blur = fmath.new(0,1) end | |
if diff == 1 then -- show impact of diffraction on Vis infinity blur | |
inf_blur = (inf_blur*inf_blur + (1342*n/1000)*(1342*n/1000)):sqrt() | |
elseif diff == 2 then -- show impact of diffraction on IR infinity blur | |
inf_blur = (inf_blur*inf_blur + (2074*n/1000)*(2074*n/1000)):sqrt() | |
end | |
inf_blur = inf_blur:int() | |
local qqq = get_user_tv_id() | |
if get_alt_mode() and evmode == 1 and not image then -- change to Survey mode | |
local temp_s = get_user_tv96() | |
if (temp_s > 1152 or temp_s < -480) then temp = "BULB" else temp = tv_str[qqq+16].."s" end | |
temp_s = fmath.new(temp_s,96) | |
temp_s = fmath.new(s_ev,96)-temp_s | |
if (10*temp_s):int() == 0 then | |
temp_s = " "..temp_s:tostr(1) | |
elseif (10*temp_s):int() > 0 then | |
temp_s = "+"..temp_s:tostr(1) | |
else | |
temp_s = temp_s:tostr(1) | |
end | |
if (get_user_tv96() > 1152 or get_user_tv96() < -480) then | |
temp = "???Ev:BULB" | |
else | |
temp = temp_s.."Ev:"..temp | |
end | |
if (s_ev > 1152 or s_ev < -480) then temp = "???Ev:"..tv_str[qqq+16].."s" end | |
if (s_ev > 1152 or s_ev < -480) and (get_user_tv96() > 1152 or get_user_tv96() < -480) then temp = "???Ev:???" end | |
pos = 180-4*(string.len(temp)) | |
draw.replace(obj3,"string",hdmi+pos, 0,temp,"white",tg) | |
elseif get_alt_mode() and evmode == 2 then -- change to ETTR mode | |
local histo={} | |
local total = 0 | |
local stop3 = 0 | |
local stop2 = 0 | |
local stop1 = 0 | |
local hlwc = 0 | |
local clr_t = 0 | |
histo,total=get_live_histo() | |
for i = 230,255,1 do stop3 = stop3 + histo[i] end -- get the total count in the requested 1/3 stop | |
for i = 207,229,1 do stop2 = stop2 + histo[i] end -- get the total count in the requested 1/3 stop | |
for i = 186,206,1 do stop1 = stop1 + histo[i] end -- get the total count in the requested 1/3 stop | |
hlwc = histo[253] + histo[254] + histo[255] -- get the top end count | |
draw.replace(obj3,"string",hdmi+pos, 0,"",tg,tg) | |
if hlwc ~= 0 then | |
clr = "yellow_light" | |
clr_t = "red" | |
elseif stop1 == 0 then | |
clr = "grey_dark" | |
clr_t = "yellow_light" | |
else | |
clr = "yellow_light" | |
clr_t = "black" | |
end | |
draw.replace(obj7,"rectf",hdmi+145,0,hdmi+173,15,clr,clr) | |
if hlwc ~= 0 then | |
temp = "" | |
elseif stop1 == 0 then | |
temp = "0%" | |
elseif (100*stop1)/total == 0 then | |
temp = "<1%" | |
else | |
temp = tostring((100*stop1)/total).."%" | |
end | |
draw.replace(obj13,"string",hdmi+147, 0,temp,clr_t,clr) | |
if hlwc ~= 0 then | |
clr = "yellow_light" | |
clr_t = "red" | |
elseif stop2 == 0 then | |
clr = "grey_dark" | |
clr_t = "yellow_light" | |
else | |
clr = "yellow_light" | |
clr_t = "black" | |
end | |
draw.replace(obj8,"rectf",hdmi+175,0,hdmi+203,15,clr,clr) | |
if hlwc ~= 0 then | |
temp ="" | |
elseif stop2 == 0 then | |
temp = "0%" | |
elseif (100*stop2)/total == 0 then | |
temp = "<1%" | |
else | |
temp = tostring((100*stop2)/total).."%" | |
end | |
draw.replace(obj14,"string",hdmi+177, 0,temp,clr_t,clr) | |
if hlwc ~= 0 then | |
clr = "yellow_light" | |
clr_t = "red" | |
elseif stop3 == 0 then | |
clr = "grey_dark" | |
clr_t = "yellow_light" | |
else | |
clr = "yellow_light" | |
clr_t = "black" | |
end | |
draw.replace(obj9,"rectf",hdmi+205,0,hdmi+233,15,clr,clr) | |
if hlwc ~= 0 then | |
if ((100*hlwc)/total) == 0 then | |
temp = "0."..tostring((1000*hlwc)/total).."%" | |
else | |
temp = tostring((100*hlwc)/total).."%" | |
end | |
elseif stop3 == 0 then | |
temp = "0%" | |
elseif (100*stop3)/total == 0 then | |
temp = "<1%" | |
else | |
temp = tostring((100*stop3)/total).."%" | |
end | |
if hlwc ~= 0 then | |
draw.replace(obj15,"string",hdmi+207, 0,"",clr_t,clr) | |
draw.replace(obj9,"rectf",hdmi+145,0,hdmi+233,15,clr,clr) | |
draw.replace(obj14,"string",hdmi+190-847*string.len(temp)/200, 0,temp,clr_t,clr) | |
else | |
draw.replace(obj15,"string",hdmi+207, 0,temp,clr_t,clr) | |
end | |
elseif get_alt_mode() and evmode == 0 then | |
if (get_user_tv96() > 1152 or get_user_tv96() < -480) then temp = "BULB" else temp = tv_str[qqq+16].."s" end | |
temp = F:int().."mm:"..temp | |
pos = 180-4*(string.len(temp)) | |
draw.replace(obj3,"string",hdmi+pos, 0,temp,"white",tg) | |
end | |
if dofs == 0 then | |
temp = units(ndof)..":"..inf_blur.."um" | |
elseif dofs == 2 then | |
if u < H:int() then | |
temp = units(ndof)..":"..units(fdof) | |
else | |
temp = units(ndof)..":"..inf_blur.."um" | |
end | |
elseif dofs == 1 then | |
if u < H:int() then | |
temp = units(ndof)..":"..units(fdof) | |
else | |
temp = units(ndof)..":INF" | |
end | |
end | |
pos = 350-8*(string.len(temp)) | |
draw.replace(obj4,"string",hdmi+pos,0,temp,"white",tg) | |
if traf == 1 and image and mode == 3 then -- display traffic lights | |
local clr = tg | |
if x == last_image_x then | |
clr = "yellow" | |
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(obj5,"rectf",hdmi+0,0,hdmi+10,15,clr,clr) -- update left traffic light | |
if x == last_image_x then | |
clr = "yellow" | |
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(obj6,"rectf",hdmi+350,0,hdmi+360,15,clr,clr) -- update right traffic light | |
local ee = (F*(pmag-1))/(pmag) -- pupil extension in mm | |
local blur = ee*(u+last_image_u)-2*u*last_image_u | |
blur = blur + F*(u+last_image_u-2*ee) | |
blur = blur*n | |
blur = ((1000*F*F*(u-last_image_u))/blur):int() -- blur at overlap in microns | |
if blur < 0 then blur = -blur end | |
if x < inf then | |
temp = F:int().."mm:"..blur.."um" | |
else | |
temp = F:int().."mm:".."???" | |
end | |
pos = 180-4*(string.len(temp)) | |
draw.replace(obj3,"string",pos, 0,temp,"white",tg) | |
else | |
clr = tg | |
draw.replace(obj5,"rectf",hdmi+0,0,hdmi+10,15,clr,clr) -- update left traffic light | |
draw.replace(obj6,"rectf",hdmi+350,0,hdmi+360,15,clr,clr) -- update right traffic light | |
end | |
draw.overdraw() | |
dirty = false | |
end | |
function non_m_update() | |
local pos = 0 | |
if get_gui_screen_width() == 360 then | |
hdmi = 0 | |
else | |
hdmi = 60 | |
end | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
local qqq = get_user_tv_id() | |
if get_alt_mode() and evmode == 1 and not image then -- change to Ev or Exp feedback | |
local temp_s = get_user_tv96() | |
if (temp_s > 1152 or temp_s < -480) then temp = "BULB" else temp = tv_str[qqq+16].."s" end | |
temp_s = fmath.new(temp_s,96) | |
temp_s = fmath.new(s_ev,96)-temp_s | |
if (10*temp_s):int() == 0 then | |
temp_s = " "..temp_s:tostr(1) | |
elseif (10*temp_s):int() > 0 then | |
temp_s = "+"..temp_s:tostr(1) | |
else | |
temp_s = temp_s:tostr(1) | |
end | |
if (get_user_tv96() > 1152 or get_user_tv96() < -480) then | |
temp = "???Ev:BULB" | |
else | |
temp = temp_s.."Ev:"..temp | |
end | |
if (s_ev > 1152 or s_ev < -480) then temp = "???Ev:"..tv_str[qqq+16].."s" end | |
if (s_ev > 1152 or s_ev < -480) and (get_user_tv96() > 1152 or get_user_tv96() < -480) then temp = "???Ev:???" end | |
elseif get_alt_mode() and evmode == 2 then -- change to ETTR mode | |
local histo={} | |
local total = 0 | |
local stop3 = 0 | |
local stop2 = 0 | |
local stop1 = 0 | |
local hlwc = 0 | |
local clr_t = 0 | |
histo,total=get_live_histo() | |
for i = 230,255,1 do stop3 = stop3 + histo[i] end -- get the total count in the requested 1/3 stop | |
for i = 207,229,1 do stop2 = stop2 + histo[i] end -- get the total count in the requested 1/3 stop | |
for i = 186,206,1 do stop1 = stop1 + histo[i] end -- get the total count in the requested 1/3 stop | |
hlwc = histo[253] + histo[254] + histo[255] -- get the top end count | |
draw.replace(obj3,"string",hdmi+pos, 0,"",tg,tg) | |
if hlwc ~= 0 then | |
clr = "yellow_light" | |
clr_t = "red" | |
elseif stop1 == 0 then | |
clr = "grey_dark" | |
clr_t = "yellow_light" | |
else | |
clr = "yellow_light" | |
clr_t = "black" | |
end | |
draw.replace(obj7,"rectf",hdmi+145,0,hdmi+173,15,clr,clr) | |
if hlwc ~= 0 then | |
temp = "" | |
elseif stop1 == 0 then | |
temp = "0%" | |
elseif (100*stop1)/total == 0 then | |
temp = "<1%" | |
else | |
temp = tostring((100*stop1)/total).."%" | |
end | |
draw.replace(obj13,"string",hdmi+147, 0,temp,clr_t,clr) | |
if hlwc ~= 0 then | |
clr = "yellow_light" | |
clr_t = "red" | |
elseif stop2 == 0 then | |
clr = "grey_dark" | |
clr_t = "yellow_light" | |
else | |
clr = "yellow_light" | |
clr_t = "black" | |
end | |
draw.replace(obj8,"rectf",hdmi+175,0,hdmi+203,15,clr,clr) | |
if hlwc ~= 0 then | |
temp ="" | |
elseif stop2 == 0 then | |
temp = "0%" | |
elseif (100*stop2)/total == 0 then | |
temp = "<1%" | |
else | |
temp = tostring((100*stop2)/total).."%" | |
end | |
draw.replace(obj14,"string",hdmi+177, 0,temp,clr_t,clr) | |
if hlwc ~= 0 then | |
clr = "yellow_light" | |
clr_t = "red" | |
elseif stop3 == 0 then | |
clr = "grey_dark" | |
clr_t = "yellow_light" | |
else | |
clr = "yellow_light" | |
clr_t = "black" | |
end | |
draw.replace(obj9,"rectf",hdmi+205,0,hdmi+233,15,clr,clr) | |
if hlwc ~= 0 then | |
if ((100*hlwc)/total) == 0 then | |
temp = "0."..tostring((1000*hlwc)/total).."%" | |
else | |
temp = tostring((100*hlwc)/total).."%" | |
end | |
elseif stop3 == 0 then | |
temp = "0%" | |
elseif (100*stop3)/total == 0 then | |
temp = "<1%" | |
else | |
temp = tostring((100*stop3)/total).."%" | |
end | |
if hlwc ~= 0 then | |
draw.replace(obj15,"string",hdmi+207, 0,"",clr_t,clr) | |
draw.replace(obj9,"rectf",hdmi+145,0,hdmi+233,15,clr,clr) | |
draw.replace(obj14,"string",hdmi+190-847*string.len(temp)/200, 0,temp,clr_t,clr) | |
else | |
draw.replace(obj15,"string",hdmi+207, 0,temp,clr_t,clr) | |
end | |
else | |
if (get_user_tv96() > 1152 or get_user_tv96() < -480) then temp = "BULB" else temp = tv_str[qqq+16].."s" end | |
temp = "??mm:"..temp | |
end | |
pos = 180-4*(string.len(temp)) | |
draw.replace(obj3,"string",hdmi+pos, 0,temp,"white",tg) | |
draw.overdraw() | |
dirty = false | |
end | |
function snap() -- single image capture | |
press("shoot_half") | |
repeat sleep(10) until (get_shooting()) | |
myshoot() | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
end | |
function check_focus_etc() | |
dof = get_dofinfo() | |
local test_x = get_focus_distance() | |
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 or test_n ~= n then | |
dirty = true | |
image = false | |
elseif test_x ~= x then | |
dirty = true | |
end | |
F = test_F | |
n = test_n | |
x = test_x | |
end | |
function check_buttons_etc() | |
wait_click(50) -- check for a button press | |
do | |
local iso = get_iso_mode() | |
local tv = get_prop(props.USER_TV) | |
snapped = false | |
if is_key("right") and get_alt_mode() and not toggle_info then -- ETTR requested | |
set_ETTR() | |
if ettro > 0 then | |
local itest = 0 | |
repeat | |
wheel_left() | |
sleep(200) | |
itest = itest + 1 | |
until itest == 3*ettro | |
end | |
elseif is_key("set") and get_alt_mode() and not toggle_info then | |
click("set") | |
elseif is_key("left") and get_alt_mode() and not toggle_info then | |
set_config_value(2140,1-get_config_value(2140,0)) | |
draw_clear() | |
elseif is_key("shoot_half") and get_alt_mode() then | |
timer_start = get_tick_count() | |
while is_pressed("shoot_half") and get_tick_count()-timer_start < 2000 do | |
sleep(100) | |
end | |
release("shoot_half") | |
sleep(100) | |
if get_tick_count()-timer_start > 2000 then | |
draw.clear() | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if bookends == 0 then temp = "Off" else temp = "On" end | |
temp = "L/R/U/D/S:"..focus_state[mode+1].."/"..exp_state[bracket+1].."/"..temp.."/"..sleep_time.."s/"..sky_state[sky+1] | |
draw.replace(obj12,"string",hdmi+180-847*string.len(temp)/200,0,temp,"white",tg) | |
draw.overdraw() | |
toggle_info = true | |
return | |
else | |
draw.clear() | |
toggle_info = false | |
end | |
s_ev = get_user_tv96() | |
dirty = true | |
elseif ((is_key("print") and bi.platform=="m3") or (is_key("video") and (bi.platform=="m10"))) and get_alt_mode() and not toggle_info then | |
if mode == 0 then -- just take an image | |
snap() | |
elseif mode == 3 then -- take an exposure bracket set | |
set_up() | |
sleep(sleep_time*1000) | |
if bookends == 1 then bookend() end | |
X_bracket() | |
if sky == 6 then -- take an auto ETTR exposure bracket for the sky | |
set_ETTR() | |
snap() | |
print("Sky X") | |
elseif sky > 0 then -- take a single exposure shot for the sky | |
set_tv96_direct(s + 96*(sky+1)) | |
snap() | |
print("Sky X") | |
end | |
ND_test() | |
if bookends == 1 then bookend() end | |
snapped = true | |
last_image_ndof = ndof | |
last_image_fdof = fdof | |
last_image_x = x | |
last_image_u = u | |
finish = false | |
image = true | |
dirty = true | |
elseif mode == 5 then -- take a superres set (make sure you set the move logic in the menu) | |
set_up() | |
if bookends == 1 then bookend() end | |
sleep(sleep_time*1000) | |
set_tv96_direct(s) | |
if ndf > 0 then i = ndf end | |
if ndf == -1 or ndf == 0 then | |
i = 2 | |
elseif ndf == -2 then | |
i = 4 | |
elseif ndf == -3 then | |
i = 8 | |
elseif ndf == -4 then | |
i = 16 | |
elseif ndf == -5 then | |
i = 32 | |
end | |
if ndf ~= 0 then | |
if srpix == 1 then -- move focus to new start | |
for j = 1, i/2 do | |
call_event_proc("EFLensCom.MoveFocus", -1, 1) | |
sleep(50) | |
end | |
end | |
for j = 1, i do | |
snap() | |
sleep(1000) | |
if srpix ~= 0 and get_focus_distance() < inf then | |
call_event_proc("EFLensCom.MoveFocus",1,1) -- move smallest step you can towards infinity | |
sleep(50) | |
end | |
end | |
end | |
update() | |
last_image_ndof = ndof | |
last_image_fdof = fdof | |
last_image_x = x | |
last_image_u = u | |
finish = false | |
image = true | |
dirty = true | |
if sky == 6 then | |
set_ETTR() | |
snap() | |
print("Sky X") | |
elseif sky > 0 then -- take a single exposure shot for the sky | |
set_tv96_direct(s + 96*(sky+1)) | |
snap() | |
print("Sky X") | |
end | |
snapped = true | |
if bookends == 1 then bookend() end | |
elseif mode > 0 then -- do some auto focus bracketing | |
finish = true | |
end | |
elseif is_key("menu") and get_alt_mode() and not toggle_info then | |
if get_config_value(1060) == 0 then set_config_value(1060,1) else set_config_value(1060,0) end | |
dirty = true | |
elseif ((is_key("display") and bi.platform=="m3") or (is_key("down") and bi.platform=="m10")) and not toggle_info and get_alt_mode() then | |
draw.clear() | |
if bi.platform=="m10" then | |
click("down") | |
else | |
click("display") | |
end | |
dirty = true | |
end | |
if snapped then | |
set_iso_mode(base_iso) | |
set_prop(props.USER_TV,tv) | |
end | |
if get_alt_mode() ~= last_alt_state then -- ALT state changed | |
last_alt_state = get_alt_mode() | |
image = false | |
s_ev = get_user_tv96() -- reset ev feedback | |
dirty = true | |
end | |
if (last_s ~= get_user_tv96()) then | |
dirty = true | |
last_s = get_user_tv96() | |
end | |
if toggle_info == true then -- go into adjustment mode | |
if is_key("down") and get_alt_mode() then -- Change delay time | |
sleep_time = sleep_time + 1 | |
if sleep_time > 10 then sleep_time = 0 end | |
draw.clear() | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if bookends == 0 then temp = "Off" else temp = "On" end | |
temp = "L/R/U/D/S:"..focus_state[mode+1].."/"..exp_state[bracket+1].."/"..temp.."/"..sleep_time.."s/"..sky_state[sky+1] | |
draw.replace(obj12,"string",hdmi+180-847*string.len(temp)/200,0,temp,"white",tg) | |
draw.overdraw() | |
elseif is_key("right") and get_alt_mode() then | |
bracket = bracket + 1 | |
if bracket > 11 then bracket = 0 end | |
draw.clear() | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if bookends == 0 then temp = "Off" else temp = "On" end | |
temp = "L/R/U/D/S:"..focus_state[mode+1].."/"..exp_state[bracket+1].."/"..temp.."/"..sleep_time.."s/"..sky_state[sky+1] | |
draw.replace(obj12,"string",hdmi+180-847*string.len(temp)/200,0,temp,"white",tg) | |
draw.overdraw() | |
elseif is_key("left") and get_alt_mode() then | |
mode = mode + 1 | |
if mode > 5 then mode = 0 end | |
draw.clear() | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if bookends == 0 then temp = "Off" else temp = "On" end | |
temp = "L/R/U/D/S:"..focus_state[mode+1].."/"..exp_state[bracket+1].."/"..temp.."/"..sleep_time.."s/"..sky_state[sky+1] | |
draw.replace(obj12,"string",hdmi+180-847*string.len(temp)/200,0,temp,"white",tg) | |
draw.overdraw() | |
elseif is_key("up") and get_alt_mode() then | |
bookends = 1 - bookends | |
draw.clear() | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if bookends == 0 then temp = "Off" else temp = "On" end | |
temp = "L/R/U/D/S:"..focus_state[mode+1].."/"..exp_state[bracket+1].."/"..temp.."/"..sleep_time.."s/"..sky_state[sky+1] | |
draw.replace(obj12,"string",hdmi+180-847*string.len(temp)/200,0,temp,"white",tg) | |
draw.overdraw() | |
elseif is_key("set") and get_alt_mode() then | |
sky = sky + 1 | |
if sky > 6 then sky = 0 end | |
draw.clear() | |
draw.replace(obj1,"rectf",hdmi+0,0,hdmi+360,15,tg,tg) -- clear the info bar | |
if bookends == 0 then temp = "Off" else temp = "On" end | |
temp = "L/R/U/D/S:"..focus_state[mode+1].."/"..exp_state[bracket+1].."/"..temp.."/"..sleep_time.."s/"..sky_state[sky+1] | |
draw.replace(obj12,"string",hdmi+180-847*string.len(temp)/200,0,temp,"white",tg) | |
draw.overdraw() | |
elseif is_key("shoot_half") and get_alt_mode() then | |
draw.clear() | |
dirty = true | |
return | |
end | |
end | |
end | |
end | |
function set_ETTR() | |
set_iso_mode(100) -- always ETTR at ISO 100 | |
do | |
local histo={} | |
local total = 0 | |
histo,total=get_live_histo() | |
total = 0 | |
local max = #histo | |
local start = max-hlw | |
for i = start,(max-1),1 do total = total + histo[i] end -- get the total count in the requested quartiles | |
local sl = 50 | |
if total <= 0 then -- underexposed | |
repeat | |
wheel_left() | |
sleep(sl) | |
histo,total=get_live_histo() | |
total = 0 | |
for i = start,(max-1),1 do total = total + histo[i] end | |
until total > limit or get_prop(props.USER_TV) <= -480 | |
end | |
if total > limit then | |
repeat | |
wheel_right() | |
sleep(sl) | |
histo,total=get_live_histo() | |
total = 0 | |
for i = start,(max-1),1 do total = total + histo[i] end | |
until total <= limit or get_prop(props.USER_TV) >= 1056 | |
end | |
s = get_prop(props.USER_TV) | |
set_user_tv96(s) | |
press("shoot_half") | |
repeat sleep(10) until get_shooting() | |
release("shoot_half") | |
repeat sleep(10) until (not get_shooting()) | |
return | |
end | |
end | |
function ND_test() | |
if ndf > 0 and not non_m then -- capture an ND sim bracket subset based on time | |
local current_tv = get_prop(props.USER_TV) | |
local base_shutter_time = tv96_to_usec(current_tv) | |
local max_av = get_max_av96() | |
local current_av = get_av96() | |
if base_shutter_time < 1000000*ndf then | |
if bookends == 1 then bookend() end -- additional bookends for ND brackets | |
del_av = max_av - current_av -- max av shift available in ev | |
del_tv = current_tv - usec_to_tv96(ndf*1000000) -- required tv shift in ev | |
if del_tv < del_av then -- adjust things | |
temp_av = (current_av+del_tv) | |
temp = current_tv - del_tv -- adjust shutter time to match aperture | |
else | |
temp_av = max_av -- set to max | |
temp = current_tv - del_av -- adjust shutter time to match aperture | |
end | |
if temp < -480 then -- max shutter of 30s: just in case | |
temp = -480 | |
end | |
i = 1 + (ndf*1000000)/tv96_to_usec(temp) | |
print(i.." ND brackets") | |
for j = 1, i do | |
set_tv96_direct(temp) | |
set_av96(temp_av) | |
snap() | |
end | |
if bookends == 1 then bookend() end | |
set_av96(current_av) | |
set_tv96(current_tv) | |
end | |
elseif ndf > 0 and non_m then | |
print("Can't use time based ND") | |
elseif ndf <0 then -- capture an ND sim bracket subset based on ND filter | |
if bookends == 1 then bookend() end | |
if ndf == -1 then | |
i = 2 | |
elseif ndf == -2 then | |
i = 4 | |
elseif ndf == -3 then | |
i = 8 | |
elseif ndf == -4 then | |
i = 16 | |
elseif ndf == -5 then | |
i = 32 | |
end | |
print(i.." ND brackets") | |
for j = 1, i do | |
snap() | |
end | |
if bookends == 1 then bookend() end | |
end | |
end | |
-- Main Section | |
if lens == 1 then | |
print_screen(-1) | |
print(lens_name()) | |
sleep(3000) | |
return | |
end | |
set_up() | |
if lens_info() == false then -- adjust a few things as can't use focus mode | |
mode = 3 | |
non_m = true | |
if ndf > 0 then | |
print("Change ND option") | |
sleep(3000) | |
return | |
end | |
end | |
print_screen(0) -- switch off logging until bracketing | |
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 | |
-- Set up the bar drawing objects | |
obj1 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj2 = draw.add("string", 0, 0, "","white",tg) | |
obj3 = draw.add("string", 0,0,"","white",tg) | |
obj4 = draw.add("string",0,0,"","white",tg) | |
obj5 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj6 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj7 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj8 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj9 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj10 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj11 = draw.add("rectf", 0, 0, 0, 0, tg,tg) | |
obj12 = draw.add("string", 0,0,"","white",tg) | |
obj13 = draw.add("string", 0,0,"","white",tg) | |
obj14 = draw.add("string", 0,0,"","white",tg) | |
obj15 = draw.add("string", 0,0,"","white",tg) | |
last_alt_state = get_alt_mode() | |
image = false -- no image taken yet | |
last_image_ndof = fmath.new(0) | |
last_image_fdof = fmath.new(0) | |
last_image_x = fmath.new(0) | |
last_image_u = fmath.new(0) | |
ecnt = get_exp_count() | |
finish = false | |
histo={} | |
repeat -- stay here while in asssess/shooting mode. THIS IS THE PIVOT POINT OF THE SCRIPT | |
if not non_m then check_focus_etc() end | |
check_buttons_etc() | |
if screen_needs_refresh() then dirty = true end | |
if dirty and not non_m then update() end | |
if dirty and non_m then non_m_update() end | |
sleep(300) | |
until finish -- then take menu requested custom brackets | |
if mode == 2 or mode == 4 then -- move to focus minimum | |
if mode == 4 and x > H:int() then | |
x_end = 2*H:int() | |
else | |
x_end = get_focus_distance() | |
end | |
repeat | |
x = get_focus_distance() | |
call_event_proc("EFLensCom.FocusSearchNear") | |
sleep(50) | |
until x == get_focus_distance() | |
update_DoFs(x) | |
end | |
set_up() -- for focus bracketing | |
if log == 1 then | |
set_console_autoredraw(-1) | |
print_screen(-1) | |
print("...") | |
print(os.date()) | |
print("Focus distance: "..usefd) | |
print("Diffraction Aware: "..diff) | |
print("Overlap Blur: "..overlap.."um") | |
print("Assumed Pupil Mag: "..pmag) | |
set_console_autoredraw(1) | |
end | |
t1=os.time() -- start the clock | |
draw.clear() | |
print_screen(0) | |
print("Bracketing Started") | |
if log == 1 then print_screen(-1) end -- switch focus bracketing logging on | |
if bookends == 1 then bookend() end | |
t1=sleep_time-(os.time()-t1) | |
if t1 > 0 then sleep(t1*1000) end | |
if screen_off == 0 then set_lcd_display(0) end | |
print("FB #1 @ "..units(fmath.new(x))) | |
X_bracket() -- First exposure(s) | |
i = 1 | |
while (u < (H/3):int()) do -- capture the rest of the focus brackets up to H/3 | |
-- Note that focus bracketing is calculated/updated in u space, but actual refocusing is in x space | |
-- All console feedback is in x space, ie distance estimates measured from the sensor | |
new_u = 2*F*F*(pmag-1) + F*(u-2*pmag*u) + h*pmag*u | |
new_u = (new_u/( F*(2*pmag-1) + pmag*(h-2*u))):int() -- new u in mm, using DOFIS model | |
if new_u <= u then new_u = u + 5 end -- move at least 5mm, just in case. Remember: script is not designed for macro work! | |
u = new_u | |
xtemp = (u + F + (F*F)/(u-F) + t) -- next focus bracket estimate in x space: in mm from f(1+m)+t+u | |
if mode == 4 then | |
if xtemp:int() > x_end then break end | |
end | |
refocus_to(xtemp:int()) | |
i = i + 1 -- keep track of number of images taken | |
print("FB #"..i.." @ "..units(xtemp)) | |
X_bracket() | |
x = xtemp:int() | |
end | |
if mode == 4 then | |
if x < x_end then | |
x = refocus_to(x_end) | |
print("last image @ "..units(fmath.new(x))) | |
X_bracket() | |
end | |
if sky == 6 then -- take an auto ETTR exposure bracket for the sky | |
set_ETTR() | |
snap() | |
set_tv96_direct(base_s) | |
print("Sky X") | |
elseif sky > 0 then -- take a single exposure shot for the sky | |
set_tv96_direct(s + 96*(sky+1)) | |
snap() | |
set_tv96_direct(base_s) | |
print("Sky X") | |
end | |
if bookends == 1 then bookend() end | |
my_restore() | |
return | |
end | |
if u < H:int() then -- take image(s) at H | |
temp = ((F*F)/(H-F) + F + t + H) | |
refocus_to(temp:int()) | |
print("@H = "..units(temp)) | |
X_bracket() | |
end | |
if u < infinity*H:int() then -- take image(s) at infinity*H | |
temp = ((F*F)/(infinity*H-F) + F + t + infinity*H) | |
if temp:int() > inf then -- adjust as at/beyond lens infinity | |
repeat | |
infinity = infinity - 1 | |
temp = ((F*F)/(infinity*H-F) + F + t + infinity*H) | |
until temp:int() < inf or infinity == 2 | |
end | |
refocus_to(temp:int()) | |
print("@"..infinity.."xH = "..units(temp)) | |
X_bracket() | |
end | |
if sky == 6 then -- take an auto ETTR exposure bracket for the sky | |
set_ETTR() | |
snap() | |
print("Sky X") | |
local test_tv = get_prop(props.USER_TV) | |
if (test_tv-base_s) > 4*96 then -- ETTR more than 4Ev from the base shutter, so take an intermediate exposure for the sky | |
set_tv96_direct((test_tv+base_s)/2) | |
snap() | |
print("Intermediate Sky X") | |
end | |
elseif sky > 0 then -- take a single exposure shot for the sky | |
set_tv96_direct(s + 96*(sky+1)) | |
snap() | |
print("Sky X") | |
end | |
ND_test() | |
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