Optomised HFD Script

Started by garry23, November 15, 2016, 11:34:27 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

garry23

For those that do landscape stills photography, the hyperfocal distance is always useful.

There are tables and apps, but of course ML provides HFD info: but the challenge is setting the lens to the HFD.

The following script does this automatically: https://gist.github.com/pigeonhill/92df2d0ae7b69b4223cd802eedee3db1

You don't need to be in LV, but the lens must report focus distance and be in AF mode.

This version also sets the optimized aperture for maximum HFD depth of field, irrespective of the current aperture.

The camera should be in manual and once the script has run, you will need to tweak the shutter for final exposure. I simply ETTR after the script has run or use auto (ML) bracketing.

The script runs from modified keys. The base script uses MENU and INFO. Change these keys to your liking.

Press MENU twice to use MENU as normal. Press MENU followed by INFO to set the optimised HFD.

For those that wish to scan scripts, here is the code:

--[[
Script uses modified keys
Version 0.7 (should work on all ML enabled cameras with the Lua module)
Shows the use of a modified key approach using an AF lens auto positioned to the HFD
Garry George Nov 2016
http://photography.grayheron.net/
For the HFD functionality must be in AF mode and lens must report distance
Script handles LV, ie LV doesn't need to be on
Also make sure ML DoF set up as you require it, eg diffraction on
Also for the fastest move position lens at infinity end, ie macro end moves are slower
Script optimises aperture: but you still need to finalise shutter for exposure
This version of the script does some (sic) error checking ;-)
--]]

-- Declare some globals

mod_button_1 = KEY.MENU -- key to modify
mod_button_2 = KEY.INFO -- key to indicate mod mode requested, ie move to the optimised HFD position
last_key_pressed = 999 -- used to reset mod_button pairing
hfd_move_requested = false
lv_already_on = false

-- Choose buttons of your choice, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants

function check_lens_ready() -- just in case
if hfd_move_menu.submenu["Turn On/Off"].value == "On" then-- check lens is ready to be moved
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
repeat
msleep(100)
until lens.focus(0,1,false)
end
end
end

function optimise() -- aperture for max hyperfocal depth of field
local current_aperture = camera.aperture.apex
local current_dof_near = lens.dof_near
local delta_aperatue = 0.5
camera.aperture.apex = camera.aperture.min.apex -- set aperture to widest
repeat
current_dof_near = lens.dof_near -- current dof_near
current_aperture = camera.aperture.apex -- store current aperture
camera.aperture.apex = camera.aperture.apex + delta_aperatue -- close down the aperture by a 1/2 stop
msleep(100) -- give the system a chance to do some stuff, just in case
until lens.dof_near >= current_dof_near -- that is until diffraction starts getting the better of you
camera.aperture.apex = current_aperture
end

function move()
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
if lens.dof_far ~= lens.dof_near then -- ok to move
if lens.focus_distance < lens.hyperfocal then
repeat
lens.focus(-1,2,false)
until lens.focus_distance >= lens.hyperfocal
repeat
lens.focus(1,1,false)
until lens.focus_distance <= lens.hyperfocal
repeat
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
else
repeat
lens.focus(1,2,false)
until lens.focus_distance <= lens.hyperfocal
repeat
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check aperture", 3000)
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check lens settings", 3000)
end
end

function test4mod(key)
if hfd_move_menu.submenu["Turn On/Off"].value == "Off" then
return true -- all keys work as normal
elseif key == mod_button_1 and last_key_pressed == mod_button_1 then -- use moded key as normal
last_key_pressed = 999 -- reset
return true
    elseif key == mod_button_2 and last_key_pressed == mod_button_1 then -- use moded key in modified way
-- ****************** Place modified flag requests here ************
last_key_pressed = 999 -- reset
hfd_move_requested = true -- flag HFD move requested
if lv.enabled then lv_already_on = true else lv_already_on = false end
-- ****************** Place modified flag requests here ************
return false -- steal key press
elseif key == mod_button_1 then -- first press of modified key in new sequence
last_key_pressed = mod_button_1
return false -- steal key press
else
return true -- use all non-moded buttons in an unmodified way
end
end

function check_requests(arg)
if hfd_move_requested == true then -- handle lv and lens move
hfd_move_requested = false -- reset flag
if not lv_already_on then lv.start() end
check_lens_ready() -- just in case it isn't
optimise() -- aperture
move() -- lens to maximised HFD position, but note shutter will need checking for optimised exposure
if not lv_already_on then lv.stop() end
return false
end
end

event.keypress = test4mod
event.shoot_task = check_requests

hfd_move_menu = menu.new
{
parent = "Shoot",
name = "HFD",
help = "Moves lens to HFD focus distance",
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
choices = {"On","Off"},
}
}
}


As usual, I welcome feedback  ;)

BBA

@Garry23
Thanks for sharing!
I am always interested in what you do.

Would you like to tell me a word about the optimise function ?
I think I understand. Quite interesting !

I see you have used the step-size 2 to go faster : very interesting too.
I wonder if you preferred not to use step-size 3 (or, maybe, for next time ?).

garry23

@BBA

I did look at step size 1, 2 and 3; and personally settled for 2, for the first move.

Bluntly, time-wise, I don't think it matters that much.

Because I have diffraction aware on, the 'blur circle' that ML uses is a function of diffraction which is a function of aperture. See here: http://photography.grayheron.net/2015/04/customising-magic-lantern.html

What I have scripted is not fully optimized, but pretty close, ie I optimize the aperture irrespective of where it is focused, then move the lens.

Bottom line: if you don't change CoC, ie as you should according to your display needs on the final print or digital image, then, for a FF camera F/16 will be about optimal for max DoF,: but not necessary for image quality across the lens radius. For this you need to look at MTF data. But ML can't access MTF data  ::) ;) :)

Cheers

Garry

knoodrake

Hello @garry23

One step from being the ultimate HFD for me: the ability (in menu) to disable the aperture optimise(), because sometimes you lack light and want to actually stay at widest aperture, and just have the widest DoF possible with it. But it's a detail, I may add it myself and repost the modified version here.

HFD script (and DoF infos in LV) and Dual ISO are my absolute favorite features enabled by ML and its community :D

Cheers
:)

garry23

@knoodrake

Great minds think alike  ;)

I came to the same conclusion and will be tweaking the script to enable the aperture feature be on or off.

Cheers

Garry

garry23

As I prepare for a trip, I'm updating all my 'go to' scripts: one of them being the Auto HFD script.

This script works in LV mode and automatically sets the lens (must be an AF lens) to the HFD, but gives the user various options:
   Exit: simply leaves the interactive mode and does nothing
   Set: moves to the HFD with the current aperture
   Opt: moves to the HFD after adjusting the aperture to achieve the maximum DoF (hint - use ML diffraction aware for optimum results)
   Wide: moves to the HFD after adjusting the aperture to achieve the lens's widest possible setting
   +2: moves to the HFD after adjusting the aperture to the lens's 'sweet spot', assumed 2 stops from the widest'

Here is the script:

--[[
Script moves lens to HFD giving user various aperture options
Version 0.9 (should work on all ML enabled cameras with the Lua module)
Allows user to select aperture options to auto position the lens to the HFD
Garry George Dec 2016
http://photography.grayheron.net/
For the HFD functionality must be in AF mode and lens must report distance
LV needs to be on
Also make sure ML DoF set up as you require it, eg diffraction on
As script may change aperture, you still need to finalise shutter for exposure, eg use ML-ETTR after the HFD is set
To use, simply go into LV and press the mod_button_1 followed by the mod_button_2 buttons...
then keep pressing the mod_button_2 button until the required aperture option is reached...
then press mod_button_1 to either exit script or move the lens with the selected aperture option
Pressing mod_button_1 twice simply functions the mod_button_1 in normal mode
Script has 'only' been tested on a 5D3
This version of the script does some (sic) error checking ;-)
--]]

-- Declare some globals
mod_button_1 = KEY.MENU -- key to modify
mod_button_2 = KEY.INFO -- interactive key
last_key_pressed = 999 -- used to reset mod_button pairing
hfd_move_requested = false
imode = false
imode_condition = 0
options = {"Exit"," Set"," Opt","Wide"," +2 "} -- for aperture

--[[
Exit: simply leaves the interactive mode and does nothing
Set: moves to the HFD with the current aperture
Opt: moves to the HFD after adjusting the aperture to achieve the maximum DoF (hint - use ML diffraction aware for optimum results)
Wide: moves to the HFD after adjusting the aperture to achieve the lens's widest possible setting
+2: moves to the HFD after adjusting the aperture to the lens's 'sweet spot', assumed 2 stops from the widest'

Choose buttons of your choice for mod_button_1 or _2, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants, but note not all cameras recognise all keys :-(
--]]

function check_lens_ready() -- just in case
if hfd_move_menu.submenu["Turn On/Off"].value == "On" then-- check lens is ready to be moved
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
repeat
msleep(100)
until lens.focus(0,1,false)
end
end
end

function optimise() -- change aperture if needed
if imode_condition == 3 then
local current_aperture = camera.aperture.min.apex
local current_dof_near = lens.dof_near
local delta_aperatue = 0.5 -- change aperture in half stops
repeat
current_dof_near = lens.dof_near -- current dof_near
current_aperture = camera.aperture.apex -- store current aperture
camera.aperture.apex = camera.aperture.apex + delta_aperatue -- close down the aperture by a 1/2 stop
msleep(100) -- give the system a chance to do some stuff, just in case
until lens.dof_near >= current_dof_near -- that is until diffraction starts getting the better of you
camera.aperture.apex = current_aperture -- set aperture to DoF optimised value
elseif imode_condition == 2 then
-- use current set value
elseif imode_condition == 4 then
camera.aperture.apex = camera.aperture.min.apex -- set aperture to widest
elseif imode_condition == 5 then
camera.aperture.apex = camera.aperture.min.apex + 2 -- set aperture to 'sweet spot', eg widest +2 stops
end
end

function move()
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
if lens.dof_far ~= lens.dof_near then -- ok to move
if lens.focus_distance < lens.hyperfocal then
repeat
lens.focus(-1,2,false)
until lens.focus_distance >= lens.hyperfocal
repeat
lens.focus(1,1,false)
until lens.focus_distance <= lens.hyperfocal
repeat
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
else
repeat
lens.focus(1,2,false)
until lens.focus_distance <= lens.hyperfocal
repeat
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check aperture", 3000)
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check lens settings", 3000)
end
end

function test4mod(key)
if lv.running then
if hfd_move_menu.submenu["Turn On/Off"].value == "On" and imode then -- stay in interactive mode
if key == mod_button_2 then  -- check if interactive toggled
imode_condition = imode_condition + 1
if imode_condition > 5 then imode_condition = 1 end
return false -- steal key press
elseif key == mod_button_1 then -- flag HFD move or exit requested
hfd_move_requested = true
imode = false
last_key_pressed = 999 -- reset
return false
else
hfd_move_requested = false
return false -- steal all other key presses
end
end
-- if not going into interactive mode then check other key sequences
if hfd_move_menu.submenu["Turn On/Off"].value == "Off" then
return true -- all keys work as normal
elseif key == mod_button_1 and last_key_pressed == mod_button_1 then -- use moded key as normal
last_key_pressed = 999 -- reset
return true
elseif key == mod_button_2 and last_key_pressed == mod_button_1 then -- go into interactive mode
imode = true -- go into interactive mode
imode_condition = 1
return false -- steal key press
elseif key == mod_button_1 then -- first press of modified key in new sequence
last_key_pressed = mod_button_1
return false -- steal key press
else
return true -- use all non-moded buttons in an unmodified way
end
else -- don't use script
return true
end
end

lv.info -- provide user feedback in interactive mode in the ML top menu bar
{
name = "HFD",
priority = 100,
value = "",
update = function(this)
this.background = COLOR.BLUE
this.foreground = COLOR.YELLOW
if hfd_move_menu.submenu["Turn On/Off"].value == "On" and imode then
this.value = options[imode_condition]
else
this.value = ""
end
end
}

function check_requests(arg)
if hfd_move_requested == true and not imode then -- move lens if requested
hfd_move_requested = false -- reset flag
if imode_condition == 1 then -- do nothing
return false
end
        -- else move the lens as reqested
check_lens_ready() -- just in case it isn't
if imode_condition ~= 1 then -- check aperture and change if needed
optimise()
end -- now
move() -- lens to HFD position, but note shutter may need checking for optimised exposure
hfd_move_requested = false
return false
end
end

event.keypress = test4mod
event.shoot_task = check_requests

hfd_move_menu = menu.new
{
parent = "Shoot",
name = "HFD",
help = "Moves lens to HFD focus distance",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
choices = {"On","Off"},
}
}
}