Magic Lantern Forum

Developing Magic Lantern => Scripting Corner => Scripting Q&A => Topic started by: garry23 on April 19, 2019, 10:28:40 AM

Title: Press question
Post by: garry23 on April 19, 2019, 10:28:40 AM
@a1ex

If I want to trigger advanced bracketing in a script, I need to simulate a shutter press. The question is, what is the best way.

Do I need to do a full sequence, ie press(half), press(full), press(unpressfull), press(unpresshalf)?

Or some other sequence.

How do I pause the script to wait for advanced bracketing to finish, eg before I refocus etc.

Hope you can educate me.

Cheers

Garry
Title: Re: Press question
Post by: a1ex on April 19, 2019, 02:09:37 PM
Theory:
Code: [Select]
camera.shoot()
camera.wait()

Practice: to be tested...
Title: Re: Press question
Post by: garry23 on April 19, 2019, 02:42:43 PM
@a1ex

I tried that earlier but it didn't seem to go well.

I've now decided on a compromise. Script will only be allowed to run in M or Av mode.

The user can elect to rune the script with the normal focus stacking and assuming three Canon-set brackets at each focus stop.

Thus I have:

Code: [Select]
if stop_count == 3 then -- assume 3 brackets requested
        local count = dryos.shooting_card.file_number
        key.press(KEY.HALFSHUTTER)
        key.press(KEY.FULLSHUTTER)
        repeat sleep(0.1) until dryos.shooting_card.file_number - count == stop_count
        key.press(KEY.UNPRESS_FULLSHUTTER)
        key.press(KEY.UNPRESS_HALFSHUTTER)
    else
        camera.shoot()
    end

If the user doesn't have the brackets set on the Canon side, the worst that can happen is you will get three exposures the same.
Title: Re: Press question
Post by: a1ex on April 19, 2019, 02:52:04 PM
I've just tested the shoot/wait sequence on 5D2 and it worked...

BTW, your full-shutter press sequence is reinventing camera.burst(3), and has an edge case when image number wraps around at 9999.
Title: Re: Press question
Post by: garry23 on April 19, 2019, 03:31:37 PM
@a1ex

Quote
I've just tested the shoot/wait sequence on 5D2 and it worked...

I just tried it on a 5D3 and it didn't  ::)

I'm in M mode and have a two brackets set via Canon.

I'm using this:

Code: [Select]
function my_shoot()
    camera.shoot()
    camera.wait()
end

All I get is a single image.
Title: Re: Press question
Post by: a1ex on April 19, 2019, 03:43:26 PM
If I want to trigger advanced bracketing in a script [...]

I'm in M mode and have a two brackets set via Canon.

These are not the same.

The shoot/wait sequence will cover the first case; that's what I've tested.

The burst() function should work with the second case, but I didn't test it.
Title: Re: Press question
Post by: garry23 on April 19, 2019, 04:00:52 PM
@a1ex

 :-[

But it still doesn'y work on my (sic) 5D3. That is M mode, ML bracketing on, Canon off and this code:

Code: [Select]
--[[

Script to capture 'perfect' focus brackets from the current focus position to a defocus (CoC) blur defined infinity.
Needs to run in LV and M Mode.
If the current position is greater than the ML hyperfocal/3, then three brackets will be taken at H/3, H and 3*H, giving a depth of focus of H/4 to infinity, using the ML CoC. Thus, if using the script, you don't need to worry
about focusing too much, as you will get three focus brackets to look at in post.
Reduce the ML CoC to achieve greater bracket to bracket focus overlap, ie focus insurance, but, sensibly, don't go below, say, 15/Crop.
Reducing the ML CoC below the 'normally recognised' CoC, eg 30/Crop , will result in more brackets, but higher focus quality through the scene.
The closer you are to the macro end, the more brackets will be taken, obviously.
Note an estimate (sic) of the number of brackets is shown in the top ML bar (RHS). B=0 means can't run script. B=n means estimate of number of brackets that will be taken. B=666 means too
much diffraction, so back off the aperture.
Script assumes you will not change lens without switching the camera off ;-)
The algorithm used is OK for non-macro use, ie landscape focus bracketing; and works best with WA lenses. So be warned and shoot wide!
The script allows the user to select a trigger key (that is hijacked if the script can run). Change this as required.
Two (different exposure) bookend images are taken at the beginning and end of bracketing, to help differentiate the bracket set in post.
The script is placed the ML Focus menu.
Finally, the script has one menu item, so it can be switched on and off, eg if you wish to access the trigger key in its normal mode.

Release 0.57
April 2019
Garry George

--]]

require("config")
direction = 1
trigger_key = KEY.RATE -- works for me on a 5D3 :-)
get_brackets = false
good_2_go = false
switched_off = false
bookends = true
options = {"ON+Bookends","ON","ONx2+Book","ONx3+Book","OFF"}
calibrated = false

function property.AF_MODE:handler(value)
    if not lens.af then good_2_go = false else good_2_go = true end
end

function test_OK()
    if lens.name == "" then return false end
    if not lens.af then return false end
    return true
end

function my_shoot()
    camera.shoot()
    camera.wait()
end

function calibrate()
    local normal = false
    local current_x = lens.focus_distance
    lens.focus(1,2,true) -- test lens chirality
    sleep(0.5)
    if lens.focus_distance > current_x then normal = true end
    lens.focus(-1,2,true)
    if not normal then direction = -direction end
end

function bookend()
   
    if camera.mode == MODE.M then
        local s = camera.shutter.apex
        camera.shutter.apex = 9
        camera.shoot()
        camera.shutter.apex = s
    else
        local t = camera.kelvin
        camera.kelvin = 0
        camera.shoot()
        camera.kelvin = t
    end
end

function set_focus(x)
    repeat sleep(0.1) until lv.running
    local current_x = lens.focus_distance
    if x == current_x then return x end
    local lens_ok = true
    if x > current_x then
        while lens.focus_distance < x and lens_ok do lens_ok = lens.focus(direction,2,true) end
        while lens.focus_distance > x and lens_ok do lens_ok = lens.focus(-direction,1,true) end
    else
        while lens.focus_distance > x and lens_ok do lens_ok = lens.focus(-direction,2,true) end
        while lens.focus_distance < x and lens_ok do lens_ok = lens.focus(direction,1,true) end
    end
    return lens.focus_distance -- final focus distance, ie may not be extactly x ;-)
end

function look_4_bracketing(pressed)
    if switched_off then
        get_brackets = false
        return true
    end
    if pressed == trigger_key then
        if not good_2_go then
            get_brackets = false
            return true -- as can't use script
        else
            get_brackets = true
            return false -- steal trigger key
        end
    else
        return true
    end
end

function capture_brackets()

    if switched_off or not lv.running  then
        get_brackets = false
        good_2_go = false
        return true
    end

    if not (camera.mode == MODE.M) then
        get_brackets = false
        good_2_go = false
        return true
    end

    if not calibrated and lv.running then
        calibrate()
        calibrated = true
    end

    if not test_OK() then
        good_2_go = false
        return true
    else
        good_2_go = true
    end

    if not get_brackets or not good_2_go then return true end

    get_brackets = false
    if bookends then bookend() end
    local x = lens.focus_distance
    local start_x = x
    while x < lens.hyperfocal/3 do
        x = set_focus(x)
        my_shoot()
        x = (x*(lens.hyperfocal - 2*lens.focal_length))/(lens.hyperfocal - 2*x) -- estimate of next bracket position
    end

    set_focus(lens.hyperfocal/3)
    my_shoot()

    set_focus(lens.hyperfocal)
    my_shoot()

    set_focus(3*lens.hyperfocal)
    my_shoot()

    if bookends then bookend() end
    set_focus(start_x)
    return true
end

get_brackets_menu = menu.new
{
    parent = "Focus",
    name = "Get Focus Brackets",
    help = "Press your trigger key to start",
    help2 = "Switch Bookends on/off here",
    depends_on = DEPENDS_ON.LIVEVIEW,
    choices = options,
    update = function(this,delta)
        if this.value == "ON+Bookends" then
            switched_off = false
            bookends = true
        elseif this.value == "ON" then
            switched_off = false
            bookends = false
        elseif this.value == "ONx2+Book" then
            switched_off = false
            bookends = true
        elseif this.value == "ONx3+Book" then
            switched_off = false
            bookends = true
        elseif this.value == "OFF" then
            switched_off = true
            bookends = false
        end
    end
}

lv.info
{
    name = "GFB",
    value = "",
    priority = 100,
    update = function(this)
        this.value = ""
        if not switched_off then
            local num = 0
            if lens.hyperfocal < 65000 then
                num = 1 + math.ceil((1 + lens.hyperfocal/lens.focus_distance)/2)
            else
                num = 666
            end
            if num < 3 then num = 3 end
            if not good_2_go then num = 0 end
            this.value = "#B="..num
        end
    end
}

event.keypress = look_4_bracketing
event.shoot_task = capture_brackets

config.create_from_menu(get_brackets_menu) -- keep a track of the script's menu state at camera close

I get a single image out of the my_shoot function.
Title: Re: Press question
Post by: garry23 on April 19, 2019, 04:22:39 PM
Further testing.

What seems to be happening is camera.wait() doesn't wait.

Thus the script moves on to the next op, ie refocus and take another bracket set, which once again fails.

What does appear to work is the last bookend image, which takes the required bookend and another image (I had two brackets set in ML).

It's giving me a headache :-( :-)
Title: Re: Press question
Post by: a1ex on April 19, 2019, 04:26:54 PM
Got it - the issue appears because ML bracketing happens in shoot_task. That means, as long as your shoot_task hook is running, ML cannot trigger its advanced bracketing sequence.

I've tested with a "simple" script (without custom menu); that one runs in a new task.
Title: Re: Press question
Post by: garry23 on April 19, 2019, 04:35:58 PM
@a1ex

Great: I was beginning to think you would never talk to me again, as I was stupid  ;)

Simple question: is there a fix I can do, or will I need to wait for a Lua Fix uplift?

As usual, thanks for your support and guidance.

Cheers

Garry
Title: Re: Press question
Post by: a1ex on April 19, 2019, 05:04:19 PM
Well, is there any reason to run this script as a "complex" one, with custom menu?

I mean, you could use a "simple" script, for example:
Code: [Select]
-- Bracketing test
menu.close()
sleep(2)
camera.shoot()
camera.wait()
display.notify_box("Finished.")

User would trigger the bracketing sequence from the "Run script" menu - no need to assign a shortcut key for it. The scripting backend will create a DryOS task for this script, with no extra effort on your part.

You would still have to define the options for bookends, but... is this something you would change often?

Yes, this suggestion is because of the multitasking limitations of our Lua integration with DryOS (read: it's a hack). It's not trivial to fix this, I've asked for help (https://www.magiclantern.fm/forum/index.php?topic=14828.msg179227#msg179227) a very long time ago, but...

So, your best bet is to keep things simple (within a single task).
Title: Re: Press question
Post by: garry23 on April 19, 2019, 05:10:44 PM
@a1ex

Thanks for the sound advice: I'll try going simple  ;)
Title: Re: Press question
Post by: garry23 on April 20, 2019, 09:09:51 AM
...@a1ex

Damn! I was really happy with the simple version of my script: but when testing to the extreme I get the attached error.

It seems to only happen if the Advanced Bracketing goes to Bulb mode.

BTW here is the latest draft of the script:

Code: [Select]
--[[

Get Brackets

This is a Lua 'simple script' to capture 'perfect' focus brackets from the current focus position to a defocus blur defined infinity, related to the ML CoC.
There is no menu and no feedback.
Needs to run in LV, AF mode and M Mode.
If the current position is greater than the ML hyperfocal/3, then three brackets will be taken at H/3, H and 3*H, giving a depth of focus of H/4 to infinity, using the ML CoC.
Thus, if using the script, you don't need to worry about focusing too much, as you will get three focus brackets to look at in post.
Set the ML CoC to achieve the required bracket to bracket defocus blur overlap, ie focus insurance, but, sensibly, don't go below, say, 15/Crop.
Reducing the ML CoC below the 'normally recognised' CoC, eg 30/Crop , will result in more brackets, but higher focus quality through the scene.
The script will pause to ask if you are content with the number of focus brackets (note exposure brackets are on top of this number).
The closer you are to the macro end, the more brackets will be taken, obviously.
The set the exposure brackets simply turn on ML's Advanced Bracketing.
The algorithm used is OK for non-macro use, ie landscape focus bracketing; and works best with WA lenses. So be warned and shoot wide!
Two (different exposure) bookend images are taken, one at the beginning and one at end of bracketing, to help differentiate the bracket set in post.
The script is run from the ML Scripts menu.

***WARNING*** Some lenses may not work with this script: sorry.

Please let me know if you have any issues or feedback.

Release 0.7
April 2019
Garry George
photography.grayheron.net

--]]

direction = 1
bookends = true
good_2_go = true

function my_shoot()
    camera.shoot()
    camera.wait()
end

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

function calibrate()
    repeat sleep(0.1) until lv.running
    local normal = false
    local current_x = lens.focus_distance
    lens.focus(1,2,true) -- test lens chirality
    sleep(0.5)
    if lens.focus_distance > current_x then normal = true end
    lens.focus(-1,2,true)
    if not normal then direction = -direction end
end

function bookend()
    local test = menu.get("Shoot","Advanced Bracket",0)
    if test == 1 then menu.set("Shoot","Advanced Bracket",0) end
    local t = camera.shutter.apex
    camera.shutter.apex = 10
    my_shoot()
    camera.shutter.apex = t
    if test == 1 then menu.set("Shoot","Advanced Bracket",1) end
end

function set_focus(x)
    repeat sleep(0.1) until lv.running
    sleep(1)
    local current_x = lens.focus_distance
    if x == current_x then return x end
    local lens_ok = true
    if x > current_x then
        while lens.focus_distance < x and lens_ok do lens_ok = lens.focus(direction,2,true) end
        while lens.focus_distance > x and lens_ok do lens_ok = lens.focus(-direction,1,true) end
    else
        while lens.focus_distance > x and lens_ok do lens_ok = lens.focus(-direction,2,true) end
        while lens.focus_distance < x and lens_ok do lens_ok = lens.focus(direction,1,true) end
    end
    current_x = lens.focus_distance
    return lens.focus_distance -- final focus distance, ie may not be extactly x ;-)
end

function capture_brackets()

    if menu.get("Get Brackets","Autorun",0) == 1 then 
        menu.set("Get Brackets","Autorun",0)
        return
    end

    menu.close()
   
    if not lv.running then lv.start() end

    repeat sleep(0.1) until lv.running

    if not (camera.mode == MODE.M) then my_display("Must be in M Mode",2,0,5) return end

    if lens.name == "" then my_display("Lens no good",2,0,5) return end
   
    if not lens.af then
        my_display("Switch AF on",2,0,5)
        repeat sleep(1) until lens.af
    end

    local num = 1 + math.ceil((1 + lens.hyperfocal/lens.focus_distance)/2)
    if num < 3 then num = 3 end
   
    my_display(tostring(num).." brackets: Press half shutter if OK?",5,0,5)
   
    if key.wait() ~= KEY.HALFSHUTTER then return end
   
    calibrate()

    if bookends then bookend() end
    local x = lens.focus_distance
    local start_x = x
    while x < lens.hyperfocal/3 do
        x = set_focus(x)
        my_shoot()
        x = (x*(lens.hyperfocal - 2*lens.focal_length))/(lens.hyperfocal - 2*x) -- estimate of next bracket position
    end

    set_focus(lens.hyperfocal/3)
    my_shoot()

    set_focus(lens.hyperfocal)
    my_shoot()

    set_focus(3*lens.hyperfocal)
    my_shoot()

    if bookends then bookend() end
    set_focus(start_x)
end

capture_brackets()


(https://i.ibb.co/SXj65Km/image1.jpg) (https://ibb.co/SXj65Km)


***UPDATE***

More testing and confirmed error only occurs if Advanced Bracketing uses BULB mode  :'(
Title: Re: Press question
Post by: a1ex on April 20, 2019, 12:06:44 PM
Understood, will prepare a fix.
Title: Re: Press question
Post by: garry23 on April 20, 2019, 12:38:04 PM
@a1ex

Many thanks, I won’t publish the script until I confirm all is ok.

Cheers

Garry
Title: Re: Press question
Post by: garry23 on April 20, 2019, 01:04:32 PM
...BTW

As long as I manage Advanced Bracketing settings, I can use the script OK.

For example I just took the test image below with my Sigma 12-24 at 12mm, f/5.6, a base exposure of 0.5s, and with a ZN strategy in Advanced Bracketing, ie +4Ev from an ML ETTR shutter.

I moved focus to focus min and ran the script, which said I would take four images, ie from min focus (some 200mm) out to 3*hyperfocal.

Plus, the script works well beside my DoF Bar. Fun to watch the DoF Bar change in front of you  ;)


(https://i.ibb.co/bPTjKfh/Test-image-5-D3.jpg) (https://ibb.co/bPTjKfh)