Saturday, January 30, 2016

Magical auto landscape bracketing

***** Note, as of this update (20th Feb 2016) this post has been superseded by the following posts, as some of the 'backend' ML code needed for an auto script still needs to be fixed. So the script should not be used for now *****

In previous posts I have spoken about the power of Magic Lantern to take a Canon EOS system to 'another level'. For example, using the diffraction corrected Depth of Field feedback, one can manually construct a set of focus brackets when taking landscapes, eg not doing simple (linear) macro bracketing.

Without ML, you will need to calculate the appropriate focus points, eg using http://goo.gl/J6F4Z5, and then trying to estimate the required focus points on your lens: not an easy task.

Now there is a third way: a Magic Lantern script that I have written (and will develop further).

The script is written in Lua and runs from the Magic Lantern menu: I have positioned it in the Audio Menu in ML, as this is uncluttered by other menu items. But a simple change in the script will allow you to position it elsewhere in ML.

To use the script make sure you have the latest ML nightly, as you must have the Lua interpreter running. This version of the script has been written to automatically gather brackets down, from the furthest focus point, towards the macro end of the lens. So you need to ensure you are focused at this position. For example, at infinity or anywhere between infinity and the hyperfocal distance.

The script will only work if your lens has autofocus enabled and reports focus distance. A good check is to enable Depth of Field reporting in ML, and see if it reports in LV. If you see the focus distance being reported, as well as the near and far depths of field, the script should run as programmed. This version has some crude error checking.

The Landscape Focus Stacker (LFS) menu has several user inputs/choices. First, you can choose the delay time, so the camera settles down. The default is 5 seconds. 

You also need to tell the script what the Minimum Focus Distance of your lens is. This is easy to ascertain, by looking at the focus distance LV reporting as you position the focus to the macro end. The MFD is in cm. The MFD can vary significantly from lens to lens, so be wary of using a single MFD.

Finally, you can ask the script to bookend your bracket sequence, by inserting a dark frame at the beginning and end of the sequence. This is a help when you are ingesting lots of different focus brackets in to, say, Lightroom.

I have appended the script at the end of this post: note this is an early version and I will be updating it with other functionality, eg bracketing from the macro end to infinity. Simply copy the script into a flat/text document and ensure the file extension is .lua. Place the file in the ML script folder on your camera's card.

To use the script simply follow this suggested workflow:
  • Select composition and exposure as normal;
  • Select the correct DoF settings in the ML menu, eg diffraction on and the Circle of Confusion criterion for your needs;
  • Ensure AF is on and switch to LV;
  • Set the required user choices in the LFS menu, eg delay, MFD and whether to bookend or not;
  • Set focus for the farthest bracket;
  • Select Run in the LFS menu and press SET;
  • Sit back and watch the script capture the perfect set of landscape brackets.
Once you have ingested the brackets into your PC for post processing, I use Lightroom, use your preferred stacking tool to blend the captured images. I personally use Helicon Focus for blending, but Photoshop sometimes does an equally good job.

The following is a test image I ran for this post. I shot this at F/8, with a MFD of 50cm. Once I had focused at the furthest point, the script ran and decided I required four brackets. The resultant (boring, indoor) image is in focus throughout; whereas each image, at F/8, only exhibited focus in part of the image.


The addition of Lua scripting in ML is one of the most significant recent additions to Magic Lantern; and I wish to publicly thank David Milligan and other ML heros who have made the Lua scripting environment a reality.

Finally, here is the LFS script...enjoy!

--    Simple landscape bracketing script
--    Version 0.2
--    Assumes lens is positioned at farthest point
--    in bracket set.

a1 = 0
b1 = 0
a2 = 0
b2 = 0
i = 0
current_tv = 0
current_av = 0

function main()
--    Close ML menu
    menu.close()
   
if lens.dof_near ~= 0 and lens.af == true
    then
--    Delay for requested seconds
    for i = keymenu.submenu["Delay"].value,0,-1
        do
        msleep(1000)
        end
--    Check if bookends requested
    if keymenu.submenu["Bookends"].value == "yes"
    then
        current_tv = camera.shutter.apex
        current_av = camera.aperture.apex
        camera.shutter.apex = 100
        camera.aperture.apex = 90
        task.yield(100)
        camera.shoot(64, 0)
        camera.shutter.apex = current_tv
        camera.aperture.apex = current_av
    end
--    Capture first image
    a2 = lens.dof_near
    b2 = lens.dof_far
    task.yield(100)
    camera.shoot(64, 0)
-- take remaining brackets to macro end
    repeat
    a1=a2
    b1=b2
        repeat
        lens.focus(1,1)
        b2 = lens.dof_far
        a2 = lens.dof_near
        until b2 < a1 or lens.focal_distance <= keymenu.submenu["MFD"].value
    camera.shoot(64,0)
    until lens.focal_distance <= keymenu.submenu["MFD"].value
--    User macro stop reached
    beep(4, 100, 330)
--    Check if bookends requested   
    if keymenu.submenu["Bookends"].value == "yes"
    then
        current_tv = camera.shutter.apex
        current_av = camera.aperture.apex
        camera.shutter.apex = 100
        camera.aperture.apex = 90
        task.yield(100)
        camera.shoot(64, 0)
        beep(4, 100, 630)
        camera.shutter.apex = current_tv
        camera.aperture.apex = current_av
    end
end
end

keymenu = menu.new
{
    parent = "Audio",
    name = "Landscape Stacker",
    help = "Focus at farthest point",
    help2 = "AF must be on",
    depends_on = DEPENDS_ON.LIVEVIEW,
    submenu =
    {
        {
            name = "Run",
            help = "Starts the script",
            depends_on = DEPENDS_ON.LIVEVIEW,
            select = function(this) task.create(main) end,
        },
        {
            name = "Delay",
            help = "Seconds to delay start (default 5)",
            value = 5,
            min = 0,
            max = 10
        },
        {
            name = "MFD",
            help = "Min Focus Distance (default 50cm)",
            help2 = "Set for your lens",
            value = 50,
            min = 10,
            max = 500
        },
        {
            name = "Bookends",
            help = "Adds a dark frame before/after brackets",
            choices = {"no","yes"},
            value = {"no"}
        }
    }
}