Skip to content

Instantly share code, notes, and snippets.

@pigeonhill pigeonhill/DOFI.lua
Last active Mar 8, 2020

Embed
What would you like to do?
Depth of Field Info
--[[
DOFI
Depth of Feild Info script
This script dynamically displays (in the ML top bar) the current infinity defocus blur, diffraction blur and the total blur at infinity.
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.
Yellow means the current focus is the same as the last image captured.
Changing aperature or focal length will reset DOFI.
Also exposing the ML menu will reset DOFI.
Augmented reality option shows the hyperfocal position as well as the focus. Set tripod height.
The ML CoC (total blur) is used as the focus overlap criterion.
A thin lens model is assumed, with the lens principal plane positioned at f(1+m) from the sensor, ie magnification is estimated from the TL model: so don't use the script for macro.
In AR mode select the correct format and the tripod/camera height above the ground plane. The ground plane is assumed to be parallel to the lens axis.
AR mode shows 3*H, H (with a yellow dot), H/3, H/5 and H/7, as well as the focus which will be red if focus is less than H, green if greater than H, or am orange dot if > 3*H
Release 0.75
March 2020
Garry George
photography.grayheron.net
--]]
require("config")
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
H = 0
m = 0
r = 0
last_H = H
ndof = 0
fdof = 0
infinity_blur = 0
diff_blur = 0
total_blur = 0
blurs = ""
num = 0
u = 0
last_f = f
last_x = x
last_a = a
last_ndof = ndof
last_fdof = fdof
last_lens_0 = 0
lens_0 = 0
card_count = dryos.shooting_card.file_number
CON = "ON"
COFF = "OFF"
image_taken = false -- that is at least one has been taken
show = true
freq = 0.550 -- 0.550 for visible band photography or 0.850 for IR (or another frequency to suit your sensor conversion)
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
my_display("Can't use DOFI",2,0,0)
return
end
function myround(nu) return tostring(math.floor(nu+0.5)) end
function update()
if f ~= last_f or a ~= last_a or menu.visible then -- reset
image_taken = false
card_count = dryos.shooting_card.file_number
last_f = lens.focal_length
last_a = camera.aperture.value
end
if card_count ~= dryos.shooting_card.file_number then
last_f = f
last_x = x
last_lens_0 = lens_0
last_a = a
last_H = H
last_ndof = ndof
last_fdof = fdof
card_count = dryos.shooting_card.file_number
image_taken = true
end
f = lens.focal_length
ML_blur = menu.get("DOF Settings","Circle of Confusion",0)
x = lens.focus_distance -- supplied by Canon from sensor
if x < infinity then
r = math.sqrt((x*x)/4 - f*x)
m = (x - 2*r)/(x + 2*r)
else
m = 0
end
lens_0 = f * (1.0 + m)
u = x - lens_0
a = camera.aperture.value
H = f + (1000*f*f)/(a*ML_blur)
ndof = (H*u-f*f)/(H+u-2*f)
if u < H then
fdof = (H*u-2*f*u+f*f)/(H-u)
else
fdof = infinity
end
num = math.ceil((1 + (H/u))/2) -- estimate of number of focus brackets
if u > H then num = 1 end
infinity_blur = ML_blur*(H-f)/(x-lens_0-f)
diff_blur = 2.44 * a * freq
total_blur = math.sqrt(infinity_blur*infinity_blur + diff_blur*diff_blur)
blurs = myround(infinity_blur).."/"..myround(diff_blur).."/"..myround(total_blur)
if x > infinity then
blurs = "INF: "..blurs
else
blurs = "#"..num..": "..blurs
end
end
function show_ar()
local scale = 60
local radmax = 10
local radmin = 2
display.rect(360-scale/2, 240-radmax, scale, 480,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
if x < 7*H then
local tri_h = 10*DOFI_Menu.submenu["Tripod Height"].value -- in mm
local sensor = 24 -- for full frame cam
if DOFI_Menu.submenu["Format?"].value == "APS-C" then sensor = sensor/1.6 end
local x0 = 2*f*tri_h/sensor
display.circle (360,240,4,COLOR.BLACK,COLOR.BLACK)
display.line(360-scale/2,240,360+scale/2,240,COLOR.BLACK)
display.line(360,480,360,240,COLOR.YELLOW)
local hy = 240 + (480*tri_h*(1+f/(3*H))*f)/(sensor*3*H)
local hw0= scale/2
local hw = hw0*x0/(3*H)
if hy >= 240 and hy >= 0 then
display.line(360-1,480,360-1,hy,COLOR.YELLOW)
display.line(360+1,480,360+1,hy,COLOR.YELLOW)
display.line(360-hw, hy, 360+hw, hy,COLOR.YELLOW)
display.line(360-hw, hy-1, 360+hw, hy-1,COLOR.YELLOW)
display.line(360-hw, hy+1, 360+hw, hy+1,COLOR.YELLOW)
end
hy = 240 + (480*tri_h*(1+f/(H))*f)/(sensor*H)
hw = hw0*x0/(H)
local radh = radmax - ((radmax-radmin)*(H-x0))/(5*H-x0)
display.circle (360,hy,radh,COLOR.YELLOW,COLOR.YELLOW)
if hy >= 240 and hy >= 0 then
display.line(360-2,480,360-2,hy,COLOR.YELLOW)
display.line(360+2,480,360+2,hy,COLOR.YELLOW)
display.line(360-hw, hy, 360+hw, hy,COLOR.GREEN1)
display.line(360-hw, hy-1, 360+hw, hy-1,COLOR.YELLOW)
display.line(360-hw, hy+1, 360+hw, hy+1,COLOR.YELLOW)
end
hy = 240 + (480*tri_h*(1+f/(H/3))*f)/(sensor*H/3)
hw = hw0*3*x0/(H)
if hy >= 240 and hy >= 0 then
display.line(360-3,480,360-3,hy,COLOR.YELLOW)
display.line(360+3,480,360+3,hy,COLOR.YELLOW)
display.line(360-hw, hy, 360+hw, hy,COLOR.YELLOW)
display.line(360-hw, hy-1, 360+hw, hy-1,COLOR.YELLOW)
display.line(360-hw, hy+1, 360+hw, hy+1,COLOR.YELLOW)
end
hy = 240 + (480*tri_h*(1+f/(H/5))*f)/(sensor*H/5)
hw = hw0*5*x0/(H)
if hy >= 240 and hy >= 0 then
display.line(360-4,480,360-4,hy,COLOR.YELLOW)
display.line(360+4,480,360+4,hy,COLOR.YELLOW)
display.line(360-hw, hy, 360+hw, hy,COLOR.YELLOW)
display.line(360-hw, hy-1, 360+hw, hy-1,COLOR.YELLOW)
display.line(360-hw, hy+1, 360+hw, hy+1,COLOR.YELLOW)
end
hy = 240 + (480*tri_h*(1+f/(H/7))*f)/(sensor*H/7)
hw = hw0*7*x0/(H)
if hy >= 240 and hy >= 0 then
display.line(360-5,480,360-5,hy,COLOR.YELLOW)
display.line(360+5,480,360+5,hy,COLOR.YELLOW)
display.line(360-hw, hy, 360+hw, hy,COLOR.YELLOW)
display.line(360-hw, hy-1, 360+hw, hy-1,COLOR.YELLOW)
display.line(360-hw, hy+1, 360+hw, hy+1,COLOR.YELLOW)
end
display.circle (360,240,5,COLOR.BLACK,COLOR.BLACK)
radh = radmax - ((radmax-radmin)*(x-x0))/(5*H-x0)
local y = 240 + (480*tri_h*(1+f/x)*f)/(sensor*x)
if (x > 3*H) then
display.circle (360,y,radh,COLOR.ORANGE,COLOR.ORANGE)
elseif (x >=H) then
display.circle (360,y,radh,COLOR.GREEN1,COLOR.GREEN1)
else
display.circle (360,y,radh,COLOR.RED,COLOR.RED)
end
end
end
function check_stuff()
update()
if not menu.visible and lv.overlays == 2 and DOFI_Menu.submenu["AR"].value == CON then display.draw(show_ar) end
return true
end
DOFI_Menu = menu.new
{
parent = "Focus",
name = "DOF Info",
help = "Helps with infinity focusing & focus bracketing",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{name = "On/Off",
choices = {CON,COFF},
update = function(this)
if this.value == "ON" then
show = true
else
show = false
end
end,
},
{
name = "AR",
help = "Switches the AR display on & off",
choices = {CON,COFF},
},
{
name = "Tripod Height",
help = "In cm",
min = 10,
max = 300,
value = 65,
},
{
name = "Format?",
help = "Just select ;-)",
choices = {"Full Frame","APS-C"},
},
}
}
lv.info
{
name = "DOFI",
value = "",
priority = 100,
update = function(this)
if (not show) then
this.value = ""
else
this.value = blurs
this.background = COLOR.WHITE
this.foreground = COLOR.BLACK
if image_taken then
if (x == last_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
elseif (ndof < last_ndof) and (fdof > last_ndof) then
this.background = COLOR.GREEN1
this.foreground = COLOR.BLACK
elseif (ndof > last_ndof) and (ndof <= last_fdof) then
this.background = COLOR.GREEN1
this.foreground = COLOR.BLACK
end
if x > infinity then
this.background = COLOR.BLACK
this.foreground = COLOR.WHITE
end
else
if x > infinity then
this.value = blurs
this.background = COLOR.BLACK
this.foreground = COLOR.WHITE
end
end
end
end
}
event.shoot_task = check_stuff
config.create_from_menu(DOFI_Menu) -- keep a track of the script's menu state at camera close
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.