Last active
June 13, 2023 19:26
-
-
Save pigeonhill/34c48d571a05e4abfc351030c893d002 to your computer and use it in GitHub Desktop.
Depth Of Field Info (Split lens version)
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
--[[ | |
DOFIS | |
Depth of Field Info Script | |
NOTE: This script assumes you are running the Lua fix from the experimental area or have the Lua fix module in your build, ie Latest Lua fix Build (2020-12-28) | |
In LV this script dynamically displays (in the ML top bar) the enhanced focus information: in non-LV mode, the Canon 'Shooting Settings' screen provides focus bracketing feedback. | |
In LV, if the display option is set to DoFs, then if you are focused less than H, DOFI will show the relative (R), either side of the point of focus, | |
or absolute (A) DoFs, relative to the sensor, plus show the blurs when focus is greater than H. | |
The script is macro aware and will switch DoF models if the magnification is greater than the one you set in the DOFIS menu. Macro DoF reporting only works in relative DoF mode. | |
DOFIS provides visual feedback when a user-set diffraction criterion is met, ie a diffraction limited point. One way to set this is to assume it is at. say, 3 sensor pixcels. | |
Green means below the limit, red above the limit. | |
The script visually shows the overlap status to aid focus bracketing: green means a positive overlap and red a focus gap between the current focus and the last image taken and... | |
yellow means the current focus is the same as the last image captured. The criterion used is the ML CoC value, with or without diffraction awareness. | |
If required, eg in bright sunshine when it is difficult to see the LV, you can switch on a Traffic Light mode. In TL mode the overlap feedback (on the left) and the infinity defocus blur (on the right)... | |
are shown as two large circles. The overlap colours are as above. The infinity blur colours are as follows: | |
- Red = infinity blur > than the ML set (overlap) defocus blur, ie the CoC used as the overlap criterion = focused at less than H | |
- Yellow = infinity defocus blur between the overlap and 1/3 of the overlap defocus blur, ie focused between H and 3H | |
- Green = infinity defocus blur < CoC/3, ie focused beyond 3H but not yet at infinity | |
- Black = focused at infinity | |
TL mode is initiated after you take an image and reset by changing the aperture value. | |
If full auto focus bracketing is switched on and a registered (non EFM) AF lens is found, and focus is less than H, and diffraction is not too high, DOFIS will automatically focus bracket to 4x hyperfocal... | |
Note Canon focus feedback becomes coarser as you focus towards infinity, so focus control becomes harder. | |
If you are focus bracketing in full mode, you have an option to take an exposure bracket at 4xH. | |
To use the infinity exposure bracketing, ETTR for the scene, eg the sky in a landscape, as your base exposure, and set the Ev lift you wish to use for the land. | |
ML AB will be switched off, if on, in full mode. | |
If semi auto focus bracketing is switched on (dx or H), then pressing the trigger key will move the lens to the next focus position requested. | |
In semi mode you can use ML AB. | |
Note in semi H mode, DOFIS will move the lens close to H, ie just before or just after, following which you can manually fine tune. | |
You can switch off auto focus bracketing and only use DOFIS exposure bracketing. | |
DOFIS will also show an estimate of the number of brackets from where you are focused to the (overlap) hyperfocal. | |
Changing aperature or focal length will reset DOFI bracketing, as will exposing the ML menu, eg to access additional info. | |
You can choose betwen a (registered) zoom, asymmetric, split thin lens model or a simple thin lens model. DOFIS shows this as S or T. | |
DOFIS alerts you to diffraction aware being on by displaying a + rather than a - to the right of the S ot T alert. | |
The normal DOFIS feedback has the following format: {S or T}{- or +}{#n or =H or >H or INF}{A or R}{[near DoF][far DoF] or [near DoF][blurs] or [blurs]} | |
You need to set the ML CoC, as this will be the the defocus overlap criterion. If diffraction aware is on, overlap will be adjusted so the ML Coc is the total blur... | |
comprised of the defocus blur and the diffraction blur in quadrature. If the diffraction blur is greater than the ML CoC, DOFIS will alert you. | |
If registered in the script, and found, a lens will be automatically used in Auto mode. Also, in Auto mode, if the lens is not found, DOFIS defaults to a thin lens model, thus | |
I recommend the Auto setting always be on. | |
You can access other infomation in the DOFIS menu, eg the AoVs and magnification at your point of focus etc. Note, this info will change according to whether you are... | |
using a registered lens or a thin lens; for example, to fully account for focus breathing in the AoV, DOFIS needs to know the pupil magnification. | |
DOFIS was mainly developed for a 5D3, but also tested om an EOSM. On the EOSM auto focusing modes should not be used. | |
Release 1.99 | |
March 2021 | |
Garry George | |
photography.grayheron.net | |
--]] | |
require("config") | |
mylens = {} | |
--[[ | |
Add your Lens Info here | |
DOFIS relies on Canon/ML distance reporting is 'acceptable' ;-) | |
Best to measure the lens Max Mag yourself or seek our actual manufactuer's data, ie rather than using advertising data | |
Also, measure pupil mag by taking focused images of the exit and entrance pupils, with a focused ruler in the plane of the pupil... | |
(for example see http://photography.grayheron.net/2020/09/dofis-start-of-major-update.html) | |
I recommend setting move to 0 on the EOSM or any camera where the lens movement is too slow, eg a macro lens. Use ML focus bracketing or just use manual DOFIS feedback when focus bracketing. | |
--]] | |
-- Lens #1 | |
mylens[1] = {} | |
mylens[1][1] = "12-24mm" -- lens name | |
mylens[1][2] = 0.154 -- Max Mag at longest FL | |
mylens[1][3] = 280 -- Minimum Focus at longest FL | |
mylens[1][4] = 24 -- Longest FL | |
mylens[1][5] = -1 -- move direction (towards infinity) | |
mylens[1][6] = 6.4 -- Pupil mag at widest FL | |
mylens[1][7] = 4.2 -- Pupil mag at longest FL | |
mylens[1][8] = 12 -- Widest FL | |
mylens[1][9] = 0.085 -- Max Mag at widest FL | |
mylens[1][10] = 280 -- Minimum Focus at widest FL | |
--Lens #2 | |
mylens[2] = {} | |
mylens[2][1] = "EF24-105mm f/4L IS USM" | |
mylens[2][2] = 0.227 | |
mylens[2][3] = 450 | |
mylens[2][4] = 105 | |
mylens[2][5] = -1 | |
mylens[2][6] = 4.08 | |
mylens[2][7] = 1 | |
mylens[2][8] = 24 | |
mylens[2][9] = 0.071 -- Max Mag at widest FL | |
mylens[2][10] = 480 -- Minimum Focus at widest FL | |
--Lens #3 | |
mylens[3] = {} | |
mylens[3][1] = "EF100mm f/2.8L Macro IS USM" | |
mylens[3][2] = 1.0 | |
mylens[3][3] = 300 | |
mylens[3][4] = 100 | |
mylens[3][5] = 0 | |
mylens[3][6] = 0.846 | |
mylens[3][7] = 0.846 | |
mylens[3][8] = 100 | |
mylens[3][9] = 1.0 -- Max Mag at widest FL | |
mylens[3][10] = 300 -- Minimum Focus at widest FL | |
--Lens #4 | |
mylens[4] = {} | |
mylens[4][1] = "EF-M11-22mm f/4-5.6 IS STM" | |
mylens[4][2] = 0.3 | |
mylens[4][3] = 150 | |
mylens[4][4] = 22 | |
mylens[4][5] = 0 | |
mylens[4][6] = 3.2 | |
mylens[4][7] = 2.26 | |
mylens[4][8] = 11 | |
mylens[4][9] = 0.13 -- Max Mag at widest FL | |
mylens[4][10] = 150 -- Minimum Focus at widest FL | |
--Lens #5 | |
mylens[5] = {} | |
mylens[5][1] = "TS-E24mm f/3.5L II" | |
mylens[5][2] = 0.34 -- Max Mag at longest FL | |
mylens[5][3] = 230 -- Minimum Focus at longest FL | |
mylens[5][4] = 24 -- Longest FL | |
mylens[5][5] = 0 -- move direction (towards infinity) | |
mylens[5][6] = 2.64 -- Pupil mag at widest FL | |
mylens[5][7] = 2.64 -- Pupil mag at longest FL | |
mylens[5][8] = 24 -- Widest FL | |
mylens[5][9] = 0.34 -- Max Mag at widest FL | |
mylens[5][10] = 230 -- Minimum Focus at widest FL | |
-- add additional lenses here and remove comment dashes. Make sure lens[n] number is contiguous with previous lenses | |
--Lens #n | |
--mylens[n] = {} | |
--mylens[n][1] = | |
--mylens[n][2] = | |
--mylens[n][3] = | |
--mylens[n][4] = | |
--mylens[n][5] = | |
--mylens[n][6] = | |
--mylens[n][7] = | |
--mylens[n][8] = | |
--mylens[n][9] = | |
--mylens[n][10] = | |
--********Change the following as required********** | |
button = KEY.RATE -- change as required | |
button_t = "RATE" -- add a 4 letter reminder here | |
--button = KEY.PLAY -- change as required | |
--button_t = "PLAY" -- add a 4 letter reminder here | |
-- | |
-- Explicity confirm your sensor data here | |
sensor_h = 36 | |
sensor_v = 24 | |
sensor_p = 6.3 -- sensor photosite (um) | |
--sensor_h = 22.3 | |
--sensor_v = 14.9 | |
--sensor_p = 4.29 -- sensor photosite (um) | |
p_factor = 3 -- 3 to 4, with 3 a mimimum for | |
-- accounting for anti aliasing | |
--************************************************** | |
menu.set("DOF Settings","DOF info in LiveView",0) | |
wave = 0.550 | |
infinity = 655000 -- trap ML reported infinity | |
f = lens.focal_length | |
x = lens.focus_distance | |
a = camera.aperture.value | |
ML_blur = menu.get("DOF Settings","Circle of Confusion",0) -- this is the overlap blur you need to set in ML | |
defocus_blur = ML_blur | |
H = 0 | |
ndof = 0 | |
fdof = 0 | |
infinity_blur = 0 | |
diff_blur = 0 | |
diff_blur_inf = 0 | |
total_blur = 0 | |
blurs = "" | |
base_blurs = "" | |
num = 0 | |
u = 0 | |
last_u = u | |
last_f = f | |
last_I_f = f | |
last_x = 0 | |
last_image_x = x | |
last_a = a | |
last_ndof = ndof | |
last_fdof = fdof | |
lens_0 = 0 | |
lens_e = 0 | |
CON = "ON" | |
COFF = "OFF" | |
image_taken = false | |
max_mag = 0 | |
min_mag = 0 | |
max_fl = 0 | |
min_fl = 0 | |
mfd = 0 | |
mfd_l = 0 | |
mfd_w = 0 | |
temp = "" | |
more = {"LT","LE","FP","M@x","Focus","HF","Defocus","Diff","LN","#B","H-AoV","V-AoV","D-AoV","P_mag","Pano","Ratio","lp"} | |
choices1 = {"Blurs","R-DoFs","A-DoFs"} | |
choices2 = {"Auto","Thin"} | |
choices3 = {"OFF","Full","Semi(dx)","Semi(H)"} | |
choices4 = {"OFF","Mode 1","Mode 2"} | |
lens_t = 0 | |
mag_u = 0 | |
lens_model_ok = nil | |
diff = false | |
no_good = false | |
auto_bracket = false | |
direction = 0 | |
new_u = 0 | |
refresh = true | |
help_txt = "" | |
p_mag = 1 -- pupil mag at f | |
p = 0 | |
exit_pupil = 0 | |
ratio = 0 | |
t_l = 0 | |
t_w = 0 | |
h = 0 | |
current_fdof = 0 | |
current_ndof = 0 | |
mag_t = 0.5 | |
lp_data = 0 | |
lp = 0 | |
a_posf = 0 | |
J = 0 | |
update_now = true | |
no_good = false | |
cleaned = true | |
function my_display(text,time,x_pos,y_pos) | |
text = string.rep("\n",y_pos)..string.rep(" ",x_pos)..text | |
display.notify_box(text,time*1000) | |
end | |
if (x==0 or a==0 or f==0) then | |
no_good = true | |
my_display("Can't use DOFIS",2,0,0) | |
return | |
end | |
function property.APERTURE:handler(value) | |
image_taken = false | |
update_now = true | |
cleaned = false | |
end | |
function my_shoot() | |
camera.shoot() | |
end | |
function myround(num, dp) -- written this way to eliminate rounding errors with other approaches and because ML Lua doesn't have a string.format | |
if dp and dp>0 then | |
local adjusted = false | |
if num < 1 and num >= 0 then -- number positive and less than 1 | |
num = num + 1 -- needed to protect 0s extraction | |
adjusted = true | |
elseif num < 0 and num > -1 then -- number negative and less than 1 | |
num = num - 1 -- needed to protect 0s extraction | |
adjusted = true | |
end | |
local temp = math.floor(num) -- integer part | |
local temp2 = tostring(math.floor(num*10^dp)) -- shift dp and round | |
temp2 = temp2:sub(-dp) -- decimal part | |
if adjusted and num >= 0 then | |
temp = "0" | |
elseif adjusted and num < 0 then | |
temp ="-0" | |
end | |
return temp.."."..temp2 | |
end | |
return tostring(math.floor(num)) | |
end | |
function x2u(xin) -- convert from sensor to front principal focus distance and update a few lens distances | |
if xin >= infinity then | |
mag_u = 0 | |
else | |
local q = xin - lens_t | |
mag_u = (q-2*f-math.sqrt(q*(q-4*f)))/(2*f) -- magnification | |
end -- magnification | |
lens_e = f*mag_u -- 'lens extension' in the DOFIS model | |
lens_0 = f + lens_e + lens_t -- position of 'front principal' from the sensor plane | |
return xin-lens_0 | |
end | |
function overlap_blur() | |
local w = last_u | |
local uu = u | |
if uu < w then | |
uu,w = w,uu | |
end | |
if uu==w then | |
w=0 | |
else | |
w=(f*(uu+w-2*p)+p*(uu+w)-2*uu*w)/(w-uu) | |
w=math.abs(1000*(f*f)/(a*w)) | |
end | |
if image_taken then return w else return -1 end | |
end | |
function Bookends() | |
if DOFIS_Menu.submenu["Bookends?"].value == "ON" then | |
local temp = camera.shutter.ms | |
camera.shutter.ms = 1 | |
my_shoot() | |
camera.shutter.ms = temp | |
end | |
end | |
function update() | |
f = lens.focal_length | |
a = camera.aperture.value | |
x = lens.focus_distance | |
last_x = x | |
last_a = a | |
if DOFIS_Menu.submenu["IR Freq"].value == CON then wave = 0.85 else wave=0.55 end | |
ML_blur = menu.get("DOF Settings","Circle of Confusion",0) | |
if f ~= last_I_f or a ~= last_a or menu.visible then -- reset bracketing | |
image_taken = false | |
cleaned = false | |
last_I_f = f | |
last_a = a | |
end | |
if DOFIS_Menu.submenu["Diffraction Aware"].value == CON then diff = true else diff = false end | |
if DOFIS_Menu.submenu["Lens Model"].value == "Auto" then -- check for a registered lens | |
lens_model_ok = false | |
lens_t = 0 | |
p = 0 | |
p_mag = 1 | |
for i=1,#mylens do | |
local mag_f = 0 | |
local X_f = 0 | |
if lens.name == mylens[i][1] then | |
max_mag = mylens[i][2] | |
min_mag = mylens[i][9] | |
mfd_l = mylens[i][3] | |
mfd_w = mylens[i][10] | |
max_fl = mylens[i][4] | |
min_fl = mylens[i][8] | |
if max_fl ~= min_fl then -- this is a zoom lens, so estimate MFD, Max Mag and p_mag at f, ie assume linear change over zoom range | |
mag_f = min_mag + ((f-min_fl)*(max_mag-min_mag))/(max_fl-min_fl) | |
X_f = mfd_w + ((f-min_fl)*(mfd_l-mfd_w))/(max_fl-min_fl) | |
p_mag = mylens[i][6] + ((f-min_fl)*(mylens[i][7]-mylens[i][6]))/(max_fl-min_fl) | |
else -- it's a prime lens | |
mag_f = max_mag | |
X_f = mfd_l | |
p_mag = mylens[i][6] | |
end | |
lens_t = X_f - (f*(1+mag_f)*(1+mag_f))/mag_f | |
direction = mylens[i][5] | |
p = f*(1-1/p_mag) | |
lens_model_ok = true | |
break | |
end | |
end | |
elseif DOFIS_Menu.submenu["Lens Model"].value == "Thin" then | |
lens_model_ok = false | |
lens_t = 0 | |
p = 0 | |
p_mag = 1 | |
else | |
lens_model_ok = nil -- shouldn't ever get here | |
end | |
diff_blur = 2.44*wave*a*(1+mag_u/p_mag) -- at focus x | |
diff_blur_inf = 2.44*wave*a -- at infinity | |
defocus_blur = ML_blur -- zero diffraction case | |
if diff then -- calculate defocus blur | |
if diff_blur < ML_blur then | |
defocus_blur = math.sqrt(ML_blur*ML_blur - diff_blur*diff_blur) | |
no_good = false | |
else | |
--no_good = true -- diffraction too high | |
defocus_blur = 1 | |
no_good = true | |
end | |
end | |
h = (1000*f*f)/(a*defocus_blur) | |
H = h + f -- as measured from the front principal, ie insensitive to pupil mag | |
do -- esitmate of diffraction impacted resolution FoM | |
local aa = 380/(wave*a*(1+mag_u/p_mag)) -- (lp/mm) MTF50 diffraction based resolution at aperture a | |
local bb = 1000/(p_factor*sensor_p) -- (lp/mm) sensor max resolution | |
local cc = 380/((wave*camera.aperture.min.value)) -- (lp/mm) MTF50 diffraction based resolution, wide open and at infinity | |
local dd = (1/aa)*(1/aa) + (1/bb)*(1/bb) | |
lp = math.sqrt(1/dd) -- lp/mm estimate | |
dd = math.sqrt(((1/cc)*(1/cc) + (1/bb)*(1/bb))/dd) | |
lp_data = 100*dd -- % lp/mm resolution reduction from infinity and wide open | |
end | |
u = x2u(x) -- focus distance from 'front principal'. Note: H, AoV and all relative DoF calculations are also sensitive to entrance pupil's location | |
infinity_blur = defocus_blur*(H-f)/(u-f) -- defocus infinity blur | |
exit_pupil = myround((lens_0+p),0) -- exit pupil position or pano pivot point | |
if DOFIS_Menu.submenu["On/Off"].value == CON and DOFIS_Menu.submenu["Show TS Info"].value == CON and DOFIS_Menu.submenu["Hinge Calculator"].value ~= 0 then | |
a_posf = math.tan(0.01745329251*DOFIS_Menu.submenu["Hinge Calculator"].value/10) | |
a_posf = math.atan((a_posf*(u-f))/f)//0.01745329251 | |
a_posf = a_posf + DOFIS_Menu.submenu["Hinge Calculator"].value/10 | |
if a_posf < 0 then a_posf = 180 + a_posf end | |
J = f/math.sin(0.01745329251*DOFIS_Menu.submenu["Hinge Calculator"].value/10) | |
end | |
-- estimate of (non-macro) absolute depths of field | |
if x > infinity then | |
ndof = H | |
else | |
ndof = u-((u-f)*(u-p))/(h+(u-f)) -- as measured from the front principal, but factoring in the pupil mag | |
end | |
if u < H then | |
fdof = u+((u-p)*(u-f))/(h-(u-f)) -- from the front principal | |
ratio = (u-ndof)/(fdof-u) -- relative near/far DoF ratio | |
else | |
fdof = infinity | |
ratio = 0 | |
end | |
mag_t = DOFIS_Menu.submenu["Mag Model"].value/10 | |
if mag_u > mag_t then -- use macro DoF estimates | |
ndof = (0.002*wave*((1+mag_u/p_mag)*a)*((1+mag_u/p_mag)*a))/(mag_u*mag_u) | |
fdof = u+ndof | |
ndof = u-ndof | |
end | |
-- estimate [:-)] of number of focus brackets to get to H | |
do | |
local u_stop = H/3 | |
local uu = u | |
if uu < u_stop then | |
num = 2 | |
while uu < u_stop | |
do | |
uu=(uu*(H-2*f))/(H-2*uu) | |
num = num + 1 | |
end | |
elseif u > H then | |
num = 1 | |
else | |
num = 2 | |
end | |
end | |
total_blur = math.sqrt(infinity_blur*infinity_blur + diff_blur*diff_blur) | |
base_blurs = "["..myround(infinity_blur,0).."/"..myround(diff_blur,0).."/"..myround(total_blur,0).."]" | |
if DOFIS_Menu.submenu["Display Options"].value == "Blurs" then -- only show infinity blurs | |
blurs = base_blurs | |
else | |
local tempn = 0 | |
local tempf = 0 | |
if x > infinity then -- no info here | |
blurs = "" | |
elseif u >= H then -- only show infinity blurs | |
tempn = ndof+lens_0 | |
if tempn > 1000 then | |
tempn = myround(tempn/1000,2).."m" | |
else | |
tempn = myround(tempn/10,0).."cm" | |
end | |
blurs = ">H:"..tempn..":A["..myround(infinity_blur,0).."/"..myround(diff_blur,0).."/"..myround(total_blur,0).."]" | |
else | |
if DOFIS_Menu.submenu["Display Options"].value == "R-DoFs" then | |
tempn = u-ndof | |
tempf = fdof-u | |
if mag_u > mag_t then | |
blurs = "["..myround(tempn,1).."mm]M["..myround(tempf,1).."mm]" | |
elseif tempf > 1000 then | |
blurs = "["..myround(tempn/1000,2).."m]R["..myround(tempf/1000,2).."m]" | |
elseif tempn < 100 then | |
blurs = "["..myround(tempn).."mm]R["..myround(tempf).."mm]" | |
else | |
blurs = "["..myround(tempn/10,0).."cm]R["..myround(tempf/10,0).."cm]" | |
end | |
else | |
tempn = ndof+lens_0 | |
tempf = fdof+lens_0 | |
if tempf > 1000 then | |
blurs = "["..myround(tempn/1000,2).."m]A["..myround(tempf/1000,2).."m]" | |
else | |
blurs = "["..myround(tempn/10,0).."cm]A["..myround(tempf/10,0).."cm]" | |
end | |
end | |
end | |
if no_good and (mag_u < mag_t) then blurs = "N 2 high" end | |
end | |
if DOFIS_Menu.submenu["Traffic Lights"].value ~= COFF and lv.running and lv.overlays == 2 and not menu.visible then | |
local c = 0 | |
if image_taken and not no_good then | |
if (x == last_image_x) then | |
c = COLOR.YELLOW | |
display.circle(250,240,70,c,c) | |
c=overlap_blur() | |
if c ~= -1 then | |
display.print(myround(c,0),250-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.YELLOW) | |
end | |
elseif (ndof > last_fdof) or (fdof < last_ndof) then | |
c = COLOR.RED | |
display.circle(250,240,70,c,c) | |
c=overlap_blur() | |
if c ~= -1 then | |
display.print(myround(c,0),250-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.WHITE,COLOR.RED) | |
end | |
else | |
c = COLOR.GREEN1 | |
display.circle(250,240,70,c,c) | |
c=overlap_blur() | |
if c ~= -1 then | |
display.print(myround(c,0),250-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.GREEN1) | |
end | |
end | |
if u < H then | |
c = COLOR.RED | |
display.circle(470,240,70,c,c) | |
c = myround(infinity_blur,0) | |
display.print(myround(c,0),470-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.WHITE,COLOR.RED) | |
elseif u < 3*H then | |
c = COLOR.YELLOW | |
display.circle(470,240,70,c,c) | |
c = myround(infinity_blur,0) | |
display.print(myround(c,0),470-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.YELLOW) | |
elseif u < infinity then | |
c = COLOR.GREEN1 | |
display.circle(470,240,70,c,c) | |
c = myround(infinity_blur,0) | |
display.print(myround(c,0),470-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.GREEN1) | |
else | |
c = COLOR.BLACK | |
display.circle(470,240,70,c,c) | |
end | |
elseif DOFIS_Menu.submenu["Traffic Lights"].value ~= COFF and lv.running and lv.overlays == 2 and not menu.visible then | |
if DOFIS_Menu.submenu["Traffic Lights"].value ~= "Mode 1" then | |
if not cleaned then | |
display.circle(250,240,70,COLOR.TRANSPARENT,COLOR.TRANSPARENT) | |
display.circle(470,240,70,COLOR.TRANSPARENT,COLOR.TRANSPARENT) | |
cleaned = true | |
end | |
else | |
if u < H then | |
c = COLOR.RED | |
display.circle(470,240,70,c,c) | |
c = myround(infinity_blur,0) | |
display.print(myround(c,0),470-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.WHITE,COLOR.RED) | |
elseif u < 3*H then | |
c = COLOR.YELLOW | |
display.circle(470,240,70,c,c) | |
c = myround(infinity_blur,0) | |
display.print(myround(c,0),470-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.YELLOW) | |
elseif u < infinity then | |
c = COLOR.GREEN1 | |
display.circle(470,240,70,c,c) | |
c = myround(infinity_blur,0) | |
display.print(myround(c,0),470-FONT.LARGE:width(myround(c,0))/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.GREEN1) | |
else | |
c = COLOR.BLACK | |
display.circle(470,240,70,c,c) | |
end | |
c = myround(lp_data,0).."%" | |
display.circle(250,240,70,COLOR.gray(lp_data),COLOR.gray(lp_data)) | |
display.print(c,250-FONT.LARGE:width(c)/2,240-FONT.LARGE.height/2,FONT.LARGE,COLOR.BLACK,COLOR.gray(lp_data)) | |
end | |
end | |
end | |
end | |
function check_auto_bracket() | |
event.shoot_task = nil -- switch off shot_task event handler while auto bracketing | |
auto_bracket = false | |
local xx = lens.focus_distance | |
local uu = x2u(xx) | |
local start_xx = xx | |
local focus_error = false | |
local exit_now = false | |
local diff_ok = true | |
if diff then -- calculate defocus blur | |
if diff_blur < ML_blur then | |
local defocus_blur = math.sqrt(ML_blur*ML_blur - diff_blur_inf*diff_blur_inf) -- use diffraction value at infinity, ie mag = 0 | |
no_good = false | |
else | |
no_good = true -- diffraction too high | |
diff_ok = false | |
end | |
end | |
if lens_model_ok and lens.af and direction ~= 0 and diff_ok then -- carry out focus bracketing | |
local h = (1000*f*f)/(a*defocus_blur) | |
local H = h + f -- H as measured from the front principal | |
if DOFIS_Menu.submenu["Auto Bracketing"].value == "Full" and uu < H then | |
menu.set("Shoot","Advanced Bracket",0) -- Can't use this mode with advanced ML backeting | |
current_fdof = uu+((uu-p)*(uu-f))/(h-(uu-f)) -- as impacted by the pupil mag | |
local tv = camera.shutter.apex | |
if DOFIS_Menu.submenu["Infinity bracket?"].value ~= 0 then -- adjust shutter to account for the Infinity bracket request | |
camera.shutter.apex = tv - DOFIS_Menu.submenu["Infinity bracket?"].value | |
end | |
sleep(DOFIS_Menu.submenu["Auto delay"].value) | |
Bookends() | |
my_shoot() | |
repeat | |
while not exit_now | |
do | |
repeat msleep(10) until lv.running | |
lens.focus(direction,2) -- move with medium steps towards the next focus position | |
repeat msleep(10) until lv.running | |
xx = lens.focus_distance | |
uu = x2u(xx) | |
current_ndof = uu-((uu-f)*(uu-p))/(h+(uu-f)) -- as impacted by the pupil mag extension, p | |
if current_ndof > current_fdof or xx > infinity then exit_now = true end | |
end | |
exit_now = false | |
while not exit_now | |
do | |
repeat msleep(10) until lv.running | |
lens.focus(-direction,1) -- move back in small steps to achieve a positive overlap | |
repeat msleep(10) until lv.running | |
xx = lens.focus_distance | |
uu = x2u(xx) | |
if xx <= start_xx then -- error | |
focus_error = true | |
exit_now = true | |
beep() | |
end | |
current_ndof = uu-((uu-f)*(uu-p))/(h+(uu-f)) -- as impacted by the pupil mag extension, p | |
if current_ndof <= current_fdof then exit_now = true end | |
end | |
exit_now = false | |
my_shoot() | |
current_fdof = uu+((uu-p)*(uu-f))/(h-(uu-f)) -- as impacted by the pupil mag | |
start_xx = xx | |
until (uu >= H/3) or focus_error | |
repeat msleep(10) until lv.running | |
uu = x2u(lens.focus_distance) | |
while uu < H do | |
lens.focus(direction,1) -- note using the smallest steps now as running out of Canon steps | |
uu = x2u(lens.focus_distance) | |
end | |
lens.focus(-direction,1) | |
my_shoot() -- take a shot at H | |
repeat msleep(10) until lv.running | |
while uu < 4*H do | |
lens.focus(direction,1) -- note using the smallest steps now as running out of Canon steps | |
uu = x2u(lens.focus_distance) | |
end | |
lens.focus(-direction,1) | |
my_shoot() -- take an infinity shot at 4*H, ie a defocus blur of overlap CoC/4 | |
repeat msleep(10) until lv.running | |
if DOFIS_Menu.submenu["Infinity bracket?"].value ~= 0 then -- do a Infinity bracket shot at 4*H | |
local current_shutter = camera.shutter.apex | |
camera.shutter.apex = current_shutter + DOFIS_Menu.submenu["Infinity bracket?"].value | |
my_shoot() | |
camera.shutter.apex = current_shutter | |
end | |
Bookends() | |
camera.shutter.apex = tv -- reset shutter | |
repeat msleep(10) until lv.running | |
elseif DOFIS_Menu.submenu["Auto Bracketing"].value == "Semi(H)" then -- go to H | |
while x2u(lens.focus_distance) < H do lens.focus(direction,2) end | |
while x2u(lens.focus_distance) > H do lens.focus(-direction,1) end | |
while x2u(lens.focus_distance) < H do lens.focus(direction,1) end | |
elseif DOFIS_Menu.submenu["Auto Bracketing"].value == "Semi(dx)" then -- use semi auto bracketing | |
uu = x2u(xx) | |
if uu >= H then | |
current_fdof = infinity | |
else | |
current_fdof = uu+((uu-p)*(uu-f))/(h-(uu-f)) -- as impacted by the pupil mag | |
end | |
exit_now = false | |
if uu < H and current_fdof < infinity then | |
while not exit_now | |
do | |
repeat msleep(10) until lv.running | |
lens.focus(direction,2) -- move with medium steps towards the next focus position | |
repeat msleep(10) until lv.running | |
xx = lens.focus_distance | |
uu = x2u(xx) | |
current_ndof = uu-((uu-f)*(uu-p))/(h+(uu-f)) -- as impacted by the pupil mag | |
if current_ndof > current_fdof or xx >= infinity then exit_now = true end | |
end | |
exit_now = false | |
while not exit_now | |
do | |
repeat msleep(10) until lv.running | |
lens.focus(-direction,1) -- move back in small steps to achieve a positive overlap | |
repeat msleep(10) until lv.running | |
xx = lens.focus_distance | |
uu = x2u(xx) | |
current_ndof = uu-((uu-f)*(uu-p))/(h+(uu-f)) -- as impacted by the pupil mag | |
if xx <= start_xx then | |
exit_now = true | |
end | |
if current_ndof <= current_fdof then exit_now = true end | |
end | |
end | |
end | |
end | |
refresh = true | |
event.shoot_task = check_stuff | |
end | |
function update_nonLV() | |
local c = COLOR.BLACK | |
local font_s = FONT.LARGE | |
local focus = x | |
local text = "" | |
local xp = 22 | |
local yp = 0 | |
local w = 720 - 2*xp | |
local d = FONT.LARGE.height + 4 | |
local defocus_b = myround(defocus_blur,0) | |
local diff_check = "" | |
if lens_model_ok then | |
if diff then diff_check = "S+" else diff_check = "S-" end | |
else | |
if diff then diff_check = "T+" else diff_check = "T-" end | |
end | |
if camera.mode ~= MODE.M then | |
display.print("SWITCH TO M MODE",xp+w/2-font_s:width("SWITCH TO M MODE")/2,yp+2,font_s,COLOR.WHITE,COLOR.BLACK) | |
return | |
end | |
if focus > infinity then | |
text = "oo/["..diff_check..defocus_b.."]"..base_blurs.."um" | |
elseif focus > 1000 then | |
text = myround(focus/1000,2).."m/["..diff_check..defocus_b.."]"..base_blurs.."um" | |
else | |
text = myround(focus/10,0).."cm/["..diff_check..defocus_b.."]"..base_blurs.."um" | |
end | |
if focus >= infinity then | |
-- | |
elseif (defocus_blur-infinity_blur) <= defocus_blur/10 and u > H then | |
text = text.."/=H" | |
elseif u > H then | |
text = text.."/>H" | |
else | |
text = text.."/#"..myround(num,0) | |
end | |
local pos = font_s:width(text)/2 | |
local cb = COLOR.GRAY | |
if image_taken and not no_good then | |
if (focus == last_image_x) then | |
c = COLOR.YELLOW | |
display.rect(xp,yp,w,d,cb,c) | |
display.print(text,xp+w/2-pos,yp+2,font_s,COLOR.BLACK,c) | |
elseif (ndof > last_fdof) or (fdof < last_ndof) then | |
c = COLOR.RED | |
display.rect(xp,yp,w,d,cb,c) | |
display.print(text,xp+w/2-pos,yp+2,font_s,COLOR.WHITE,c) | |
else | |
c = COLOR.GREEN1 | |
display.rect(xp,yp,w,d,cb,c) | |
display.print(text,xp+w/2-pos,yp+2,font_s,COLOR.BLACK,c) | |
end | |
elseif not no_good then | |
c = COLOR.BLACK | |
display.rect(xp,yp,w,d,cb,c) | |
display.print(text,xp+w/2-font_s:width(text)/2,yp+2,font_s,COLOR.WHITE,c) | |
else | |
display.print("Can't use DOFIS: Check Lens",xp+w/2-font_s:width("Can't use DOFIS: Check Lens")/2,yp+2,font_s,COLOR.WHITE,COLOR.BLACK) | |
end | |
if menu.get("Expo","Dual ISO",0) == 1 then display.print("DI",495,105,FONT.MED,COLOR.YELLOW,COLOR.BLACK) end | |
if menu.get("Shoot","Silent Picture",0) == 1 then display.print("SP",155,105,FONT.MED,COLOR.YELLOW,COLOR.BLACK) end | |
display.print(lens.focal_length.."mm",335,105,FONT.MED,COLOR.YELLOW,COLOR.BLACK) | |
end | |
function check_stuff() | |
if (lens.focus_distance==0 or camera.aperture.value==0 or lens.focal_length==0) and lens.focus_distance ~= last_x then | |
no_good = true | |
if (camera.gui.mode == 0 and not lv.running and DOFIS_Menu.submenu["Focus Bracketing"].value == CON) then | |
display.draw(update_nonLV) | |
end | |
my_display("Can't use DOFIS",2,0,0) | |
return | |
else | |
no_good = false | |
end | |
if DOFIS_Menu.submenu["On/Off"].value == COFF then return true end | |
if auto_bracket then check_auto_bracket() end | |
if (last_x ~= lens.focus_distance or menu.visible or camera.gui.mode == 0 or update_now) then | |
update() | |
if (camera.gui.mode == 0 and not lv.running and DOFIS_Menu.submenu["Focus Bracketing"].value == CON) then | |
display.draw(update_nonLV) | |
end | |
update_now = false | |
end | |
return true | |
end | |
function check_keys(kk) | |
if kk == KEY.UNPRESS_FULLSHUTTER then | |
update_now = true | |
last_image_x = x | |
last_ndof = ndof | |
last_fdof = fdof | |
image_taken = true | |
last_I_f = f | |
last_u = u | |
return true | |
end | |
if kk == button and DOFIS_Menu.submenu["Auto Bracketing"].value ~= COFF then | |
auto_bracket = true | |
return false | |
else | |
auto_bracket = false | |
return true | |
end | |
end | |
DOFIS_Menu = menu.new | |
{ | |
parent = "Focus", | |
name = "DOFIS", | |
help = "Make sure camera, eg FF or APS-C, is set correctly in the script", | |
help2 = "Shows DoFs (abs or rel) + defocus, diffraction & total inf blurs. Plus focus bracketing", | |
submenu = | |
{ | |
{name = "On/Off", | |
choices = {CON,COFF}, | |
}, | |
{name = "Display Options", | |
choices = choices1, | |
help = "Relative DoFs or Blurs in DOFIS window", | |
}, | |
{name = "Focus Bracketing", | |
choices = {CON,COFF}, | |
help = "Switches the focus bracketing feedback on or off", | |
}, | |
{name = "Auto Bracketing", | |
choices = choices3, | |
help = "Full = move (n(x to dx) to 4H) + shoot, Semi = move (x to dx or x to H)", | |
help2 = "ML AB will be switched off in full mode", | |
rinfo = function(this) | |
if this.value == "OFF" then | |
return "" | |
else | |
if this.value == "Full" and num <= 20 then | |
this.help2 = "Number of focus brackets" | |
return "#"..myround(num) | |
elseif this.value == "Full" and num > 20 then | |
this.help2 = "Number of focus brackets" | |
return ">20" | |
else | |
this.help2 = "Full = x to H, Semi = x to ?" | |
return button_t | |
end | |
end | |
end, | |
}, | |
{name = "Diffraction Aware", | |
choices = {CON,COFF}, | |
update = function(this) | |
if this.value == "ON" then | |
diff = true | |
else | |
diff = false | |
end | |
end, | |
help = "Switches diffraction aware on/off for DoFs", | |
}, | |
{name = "lp/mm Feedback", | |
choices = {CON,COFF}, | |
help = "Switches diffraction impacted IQ feedback on/off", | |
help2 = "Feedback is shown as a % of that at infinity and a wide open aperature", | |
}, | |
{name = "Traffic Lights", | |
choices = choices4, | |
help = "Switches traffic light feedback on/off", | |
help2 = "Shows overlap and infinity blur status", | |
}, | |
{name = "IR Freq", | |
choices = {CON,COFF}, | |
help = "Switches diffraction blur to IR frequency", | |
help2 = "Off covers visible and full spectrum capture", | |
}, | |
{name = "Infinity bracket?", | |
min = 0, | |
max = 6, | |
unit = UNIT.DEC, | |
rinfo = function(this) | |
if this.value == 0 then | |
return "OFF" | |
else | |
return "Ev" | |
end | |
end, | |
help = "Take an exposure bracket (2-6Ev) at 4xH: ETTR as the base exposure", | |
help2 = "Can only be used when auto focus bracketing", | |
}, | |
{name = "Auto delay", | |
min = 0, | |
max = 2, | |
unit = UNIT.DEC, | |
help = "Only used when auto focus bracketing, at the start of the bracketing sequence", | |
rinfo = function(this) return "Sec" end, | |
}, | |
{ | |
name = "Bookends?", | |
help = "Places an underexposed frame at start and end of the auto bracket set", | |
choices = {CON,COFF}, | |
}, | |
{name = "Lens Model", | |
choices = choices2, | |
help = "Switch between lens models", | |
help2 = "OK means registered lens found. Not Ok meand will use thin lens model", | |
rinfo = function(this) | |
if DOFIS_Menu.submenu["Lens Model"].value == "Auto" then | |
if lens_model_ok then | |
return "OK" | |
else | |
return "Not OK" | |
end | |
end | |
return "" | |
end, | |
}, | |
{name = "Mag Model", | |
min = 5, | |
max = 10, | |
unit = UNIT.DEC, | |
value = 5, | |
rinfo = function(this) | |
mag_t = this.value/10 | |
return myround(mag_t,1) | |
end, | |
help = "Mag to transition to macro model DoF", | |
help2 = "Mag shown on right", | |
}, | |
{name = "Hinge Calculator", | |
min = 0, | |
max = 85, | |
unit = UNIT.DEC, | |
value = 1, | |
rinfo = function(this) | |
if this.value ~= 0 then | |
return "J="..myround(f/math.sin(0.01745329251*this.value/10)/10,0).."cm" | |
else | |
return "J=Inf" | |
end | |
end, | |
help = "Tilt angle in 1/10 degrees", | |
help2 = "Converts to Hinge distance from lens FP", | |
}, | |
{name = "Show TS Info", | |
choices = {CON,COFF}, | |
update = function(this) | |
if this.value == "ON" then | |
diff = true | |
else | |
diff = false | |
end | |
end, | |
help = "Show J & PoSF angle from vertical in degrees", | |
help2 = "Make sure lens tilt is set correctly in DOFIS menu", | |
}, | |
{ | |
name = "Additional Info", | |
choices = more, | |
rinfo = function(this) | |
help_txt = "" | |
if this.value == "LT" then | |
temp = myround(lens_t,0).."mm" | |
help_txt = "Lens thickness. Note: can be + or -" | |
elseif this.value == "LE" then | |
temp = myround(lens_e,2).."mm" | |
help_txt = "Focus lens extension. Note: zero at infinity" | |
elseif this.value == "FP" then | |
temp = myround(lens_0,0).."mm" | |
help_txt = "Front principal position relative to sensor (J zero for TS-E)" | |
elseif this.value == "M@x" then | |
temp = myround(mag_u,3) | |
help_txt = "Magnification at the current focus" | |
elseif this.value == "LN" then | |
temp = "LN: "..lens.name | |
my_display(temp,1,5,10) | |
temp = "" | |
help_txt = "Lens name for registering lens in DOFIS" | |
elseif this.value == "Focus" then | |
if x > infinity then | |
temp = "oo" | |
elseif x < 1000 then | |
temp = myround(x/10,0).."cm" | |
else | |
temp = myround(x/1000,2).."m" | |
end | |
help_txt = "From Canon: let's hope it's good enough ;-)" | |
elseif this.value == "Defocus" then | |
temp = myround(defocus_blur,0).."um" | |
help_txt = "ML set (overlap) defocus blur, in microns" | |
elseif this.value == "Diff" then | |
temp = myround(diff_blur,0).."um" | |
help_txt = "Focus sensitive diffraction, in microns" | |
elseif this.value == "HF" then | |
if (h+f+lens_0) > 1000 then | |
temp = myround((h+f+lens_0)/1000,2).."m" | |
else | |
temp = myround((h+f+lens_0)/10,0).."cm" | |
end | |
help_txt = "Hyperfocal from the sensor plane" | |
elseif this.value == "#B" then | |
temp = "#"..myround(num) | |
help_txt = "Number of focus bracket to reach the hyperfocal" | |
elseif this.value == "H-AoV" then | |
temp = myround(114.591*math.atan(sensor_h/(2*f*(1+mag_u/p_mag))),1) | |
help_txt = "Horizontal/landscape AoV in degrees" | |
elseif this.value == "V-AoV" then | |
temp = myround(114.591*math.atan(sensor_v/(2*f*(1+mag_u/p_mag))),1) | |
help_txt = "Vertical/portrait AoV in degrees" | |
elseif this.value == "D-AoV" then | |
temp = math.sqrt(sensor_h*sensor_h + sensor_v*sensor_v) | |
temp = myround(114.591*math.atan(temp/(2*f*(1+mag_u/p_mag))),1) | |
help_txt = "Diagonal AoV in degrees" | |
elseif this.value == "P_mag" then | |
temp = myround(p_mag,1) | |
help_txt = "Pupillary magnification" | |
elseif this.value == "Pano" then | |
temp = exit_pupil.."mm" | |
help_txt = "Pano nodal postion from sensor (exit pupil)" | |
elseif this.value == "Ratio" then | |
temp = myround(ratio,2) | |
help_txt = "Estimate of DoF ratio (near/far)" | |
elseif this.value == "lp" then | |
temp = myround(lp,0) | |
help_txt = "Diffraction impacted resolution in lp/mm" | |
end | |
return temp | |
end, | |
update = function(this) | |
this.help2 = help_txt | |
end, | |
help = "Toggle through additional info", | |
help2 = "" | |
} | |
} | |
} | |
lv.info | |
{ | |
name = "DoF Info", | |
value = "", | |
priority = 100, | |
update = function(this) | |
this.background = COLOR.TRANSPARENT_BLACK | |
this.foreground = COLOR.WHITE | |
if DOFIS_Menu.submenu["On/Off"].value == COFF then | |
this.value = "" | |
else | |
this.value = blurs | |
end | |
end | |
} | |
lv.info | |
{ | |
name = "more info", | |
priority = 100, | |
value = "", | |
update = function(this) | |
if DOFIS_Menu.submenu["On/Off"].value == CON then | |
this.background = COLOR.TRANSPARENT_BLACK | |
this.foreground = COLOR.WHITE | |
if DOFIS_Menu.submenu["Focus Bracketing"].value == CON then | |
if image_taken then | |
if (lens.focus_distance == last_image_x) then | |
this.background = COLOR.YELLOW | |
this.foreground = COLOR.BLACK | |
elseif (ndof > last_fdof) or (fdof < last_ndof) then | |
this.background = COLOR.RED | |
this.foreground = COLOR.WHITE | |
else | |
this.background = COLOR.GREEN1 | |
this.foreground = COLOR.BLACK | |
end | |
end | |
end | |
if lens_model_ok == nil then | |
this.value = "??" | |
elseif lens_model_ok then | |
if diff then this.value = "S+" else this.value = "S-" end | |
else | |
if diff then this.value = "T+" else this.value = "T-" end | |
end | |
if x > infinity then | |
this.value = this.value.."oo" | |
elseif mag_u > mag_t then | |
this.value = this.value.."m"..myround(mag_u,2) | |
elseif (defocus_blur-infinity_blur) <= defocus_blur/10 and u > H then | |
this.value = this.value.."=H" | |
elseif u > H then | |
this.value = this.value..">H" | |
else | |
this.value = this.value.."#"..myround(num,0) | |
end | |
else | |
this.value = "" | |
end | |
end | |
} | |
lv.info | |
{ | |
name = "Diff info", | |
priority = 100, | |
value = "", | |
update = function(this) | |
if DOFIS_Menu.submenu["On/Off"].value == CON and DOFIS_Menu.submenu["lp/mm Feedback"].value == CON then | |
this.background = COLOR.GREEN1 | |
this.foreground = COLOR.BLACK | |
if (wave*a*(1+mag_u/p_mag))/0.38 > p_factor*sensor_p then | |
this.background = COLOR.RED | |
this.foreground = COLOR.YELLOW | |
end | |
this.value = myround(lp_data,0).."%" | |
else | |
this.value = "" | |
end | |
end | |
} | |
lv.info | |
{ | |
name = "PoSF info", | |
priority = 100, | |
value = "", | |
update = function(this) | |
if DOFIS_Menu.submenu["On/Off"].value == CON and DOFIS_Menu.submenu["Show TS Info"].value == CON and DOFIS_Menu.submenu["Hinge Calculator"].value ~= 0 then | |
this.background = COLOR.TRANSPARENT_BLACK | |
this.foreground = COLOR.WHITE | |
this.value = myround(J/10,0).."cm:"..myround(a_posf,0) | |
else | |
this.value = "" | |
end | |
end | |
} | |
event.shoot_task = check_stuff | |
event.keypress = check_keys | |
config.create_from_menu(DOFIS_Menu) -- keep a track of the script's menu state at camera close | |
console.hide() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment