Written for/on: A620
Also works on: A610 / A630 / A640

The PowerShot A6xx series cams have great potential for shooting extreme closeups of very tiny subjects, or detail shots of larger subjects, because they can achieve focus with subjects as close as 1cm. That's a wonderful spec, but at such an extremely short focus distance the depth of field is prohibitively shallow. The resulting photo of any dimensional (non-flat) subject will be less than satisfactory; due to the DOF constraint (approx 1mm DOF), the photo can depict only a "slice" of the subject in clear focus.

We can setup the cam on a "macro focusing rail" ("Velbon", and other manufacturers) and shoot a series of "slices", then process these sets of frames using "stacking" software (the freeware CombineZM software, for instance) to achieve a single combined-slice photo in which the entire distance of the dimensional subject is in sharp focus. However, shooting those myriad frames is a tedious chore. So tedious, in fact, that success in avoiding misaligned subject framing across frames really demands cabled (aka 'remote pc') shooting. Although this removes the necessity for a physical shutter press for each shot, shooting the "slices" still requires you to adjust the macro rail for each frame.

The primary goal for this CHDK script is to facilitate macro (erm, "extreme closeup") shooting. The script steps through a user-specified range of focus distances, generating a series (or 'stack') of frames which, when fed to CombineZm, yield a "continuous DOF" image. Quickly. Effortlessly. Automagically.

At short subject distances, the A6xx series cams are able to step through (address) discreet subject distances in 1mm increments. As a practical matter, you cannot direct the camera "by hand" to do so via manual focus left/right keypresses. Even with a quick/light touch, the time required to perform a "single" (click/release) keypress causes the camera's focus distance to jump by a multiple "steps". Prior to experimenting with CHDK, on a good day (heh) I recall having been "quick enough" at my manual keypress to count 45 presses between the 10cm mark on the slider and the left end of the slider scale. In contrast, your degree of control from using the script "pushes the envelope" -- in your series of shots, you will observe the near focus boundry moving outward 1mm, predictably and consistently, across each frame.

Although this script will allow you to automate stepping the cam through any focus range... the tiny steps (as coded) are ridiculously inefficient (overkill) for capturing the few frames required beyond the hyperfocal distance in creating an "apparent unlimited DOF" series. Thankfully, DOF variances are minimal at the near end of the range (minimal, although NOT negligible)... but understand that the script is designed for, tested with, and intended for precision shooting at the "extreme closeup" near end of the scale. Creation of a truly efficient (minimum number of DOF-overlapping frames) script covering the full focal range for the the A6xx series cams would involve sifting through 68 "FocalLength x Aperture" permutations.

CombineZM -=-
A tutorial in the use of CombineZM is beyond the scope of this "DOFstacker script wiki page", so I hope the following quick "workflow overview" will suffice:

Install CombineZM. Have a beer.
Shoot your pics and copy the imagefiles to your PC.
Run CombineZM and choose New from the dropdown menu.
Browse, and click // Shift+Click to select the imagefiles for your intended "stack".
Have a beer (while CombineZM is processing the frames) then when it displays the result, choose SaveAs and type the desired filename and/or path.


tripod-mounted camera
ModeDial to Av (f5.6)
set REVIEW off
set flash OFF
The above are recommended (strongly recommended, for beginners) rather than 'required' because this script is designed to accomodate various scenarios. The cam can be setup on any firm, unyielding surface (tabletop, a rock, firm turf) -- just bear in mind that at extremely close subject distances, the SLIGHTEST camera shift or vibration will be detrimental to the consistency of the frames in your series. Similarly (recommended vs required), neither the review nor the flash state will prevent the script from running its course (unless REVIEW=hold) but setting them as recommended will enable the script to step through the shooting series more quickly. (Flash??? Sure! Hmmm, well, everyone except me has a slave flash ringlight, right? Anyhow...)

After you've grown familiar with using the script, you may want to shoot using an aperture other than f5.6 -- that's fine, *IF* you understand (or are prepared to experiment and discover) the constraints imposed in shooting extreme closeup. By opting away from f5.6, in your experimentation you should expect to encounter "softer apparent focus" images (diffraction-limited focus) or a stacked image result which displays focus "banding" (because the DOF of individual frames is *so* shallow that they do not overlap).


closeStart dist (mm)
closeStart dist (cm)
closeStart dist (m)
Multiple distance inputs are provided for convenience in data entry. You can enter either 10mm *or* 1cm, to the same effect. If you want the cam to begin shooting the series by assuming a near-focus starting distance of 11mm (the frontmost edge of your subject), you can enter 10mm *and* 1cm (or 11mm + 0cm)(your choice). Instead of measuring (I usually don't), you can just guess, or just choose "zero" as a starting point any time the subject is "about 1cm away".

Until/unless you change the default, the script starts at "zero distance" (zero == subject touching front of lens housing). (anecdotal reference: Shooting along the length of a ruler, with the ruler butted against the lens housing, the "dist=zero" frame from my A620 shows a near edge focus boundry of 7.5 millimeters. Woohoo! That's 25% closer than the can's 1cm spec!) Expect noticeable CA (fringing) from shots at this minimal (closer-than-spec) distance, and undertstand that each individual camera may differ from others (even cams of same model) in its ability to achieve focus at the closest (zero) step, or even the first several.

Number of focal steps
each step = 1mm change in subject focus distance (ON THE NEAR END; SUBJECT DISTANCES 0-10cm). If your subject is 15mm long, or is aligned in the scene such that it projects 15mm into the field, use a value of 15 here, in this parameter. If you don't have a ruler at hand, or don't care to measure, you can just use an inflated number as your guessed length... and later discard any unneeded tail-end frames.

Number focal steps (x10)
If your lens is pointing down the length of a subject that is "5cm long", instead of scrolling all the way to 50 ( x1mm, using the other param) you can just enter "5" here, in this "distance x10" param.

Snap HDR sets? (1=yes)
Enabling this option causes the script to also perform exposure bracketing, snapping a set of 3 bracketed shots at each stepped focus distance. This feature will enable you (and me) to experiment with using multiple frames to create HDR (high dynamic range) images. (See the "related reading" section, below.)

ExpComp limit (1 or 2)
When the "Snap HDR sets" option is enabled, changing this "limit" parameter toggles the range of exposure compensation bracketing performed: (sets of -2 / 0 /+2 or sets of -1 / 0 / 1 )

Show helptext? (1=yes)
The script is EXTREMELY verbose -- it provides plenty of onscreen help/tips, toward the goal of suitablilty for use (in classrooms and) by my ten-year-old nephew. After you have used the script a few times, you may opt to "turn off" this inline, runtime help.


MANUAL FOCUS MUST BE SELECTED prior to starting the script.

When utilizing the script option to perform HDR (exposure compsentaion) bracketing, prior to starting the script you should activate the onscreen ExposureCompensation slider by clicking the "erase" button. I said "you should"; actually, you MUST (and the script will prompt you with a text reminder regarding this requirement).


If you are interested in creating "an extreme closeup photographic record of a seed germinating" (for instance) you might want to add an intervalometer function, so that the script would repeatedly capture a stack of frames for the selected focus range. (The output from each 'stack', in turn, would serve as a frame in a time-lapse video, or... more feasibly, a slideshow frame.) Adapting this script to such use would only require wrapping an additional, timer loop around the "for y=a to a+d" section of code, along with inclusion of another param to accomodate input of the desired interval delay.

For shooting HDR (high dynamic range), the script probably needs to be modified to permit more granular exposure compensation than the current "1EV per step". I'm intrigued by what I've read & seen regarding HDR, but I haven't yet dabbled in creating HDR images. Opinions differ, but some HDR enthusiasts claim that it's necessary to capture a set of frames having more exposure latitude than -2 / 0 / +2. Getting that range via a CHDK A6xx script might be accomplished by instructing the user to first select Av mode and select the desired aperture (5.6), framing the subject then half-pressing the shutter, to read what the camera has metered as the ExpComp=0 shutter speed. Afterward, the user would switch the ModeDial to Manual, select the same aperture value (5.6) along with the metered shutter speed to serve as a starting point... then run a version of the script which accomplishes an additional degree of exposure bracketing by ALSO stepping the shutter speed, in conjunction with the ExpComp and/or focus bracketing functions.

Related Reading -- HDR:
discussion groups at flickr:

Recent HDR discussions in the DPReview "lighting talk" and "retouching" forums:

Various collected bookmarks re "tonemapping" or "tone mapping HDR"

July 04, 2007 ~Russ

Script Code (save as "DOFstacker.bas" to your /CHDK/SCRIPTS/ folder)

@title DOF stackmaker
rem written for A620+CHDK build 136 (should work with any A6xx model)

@param a closeStart dist (mm)
@default a 0
@param b closeStart dist (cm)
@default b 0
@param c closeStart dist (m)
@default c 0
let a=1000*c+10*b+a
if a<0 then let a=0
rem Zero offset for each model (or each invididual) cam may differ from 62
let a=a+62
@param d Show helptext? (1=yes)
@default d 1
@param e Snap HDR sets? (1=yes)
@default e 0
@param f ExpComp limit (1 or 2)
@default f 2
rem each IF statement may contain only a single relational operator
if e<0 then let e=0
if e>1 then let e=0
if f<1 then let f=1
if f>2 then let f=2
@param g Number of focal steps
@default g 0
@param h Number focal steps (x10)
@default h 2

get_zoom z
if z>0 then gosub "nozoom"
let x=10*h+g+a
if x>1199 then gosub "crazysteps"
if d=1 then gosub "instruct"
if e=1 then gosub "chkslider"
gosub "countdown"

rem if e=1 then click "erase"
rem NO! Make this a precondition/requirement! We cannot guess cursor position;
rem a single, or double click may be required (depends on ModeDial position)

for y=a to x
    set_focus y
    rem if e=1 then gosub "hdrset" else gosub "regshoot"
    rem workaround "ELSE" bug
    if e=1 then gosub "hdrset" 
    if e=0 then gosub "regshoot"
next y

print "ensure MANUAL FOCUS"
print "selected before using"
print "this script or CAM MAY"
print "CRASH (powerdown)"
print "paused --[ click SET ]--"
print "ModeDial to Av (f5.6)"
print "set REVIEW off"
print "set flash OFF"
print "paused --[ click SET ]--"
print "Move away from cam or"
print "sit ENTIRELY still "
print "during the session..."
print "paused --[ click SET ]--"
print "...because the TINIEST"
print "vibration will produce"
print "blur / misalignment"
print "in your series of shots"
print "paused --[ click SET ]--"

rem ExpBracketing option has been selected
print "ENSURE ExpComp slider"
print "is visible onscreen"
print "SCRIPT NOW and set it"
print "paused --[ click SET ]--"

for n=1 to 5
    print "starting in:", 6-n,"secs..."
    sleep 940
next n
for n=1 to 5
    print " "
next n

print "shooting..."
print "."

for n=1 to 3
    if n>1 then goto "noinit"
    for p=1 to 12
       click "left"
       sleep 100
    next p  
    rem each IF statement may contain only a single relational operator
    rem also need to workaround the uBasic "ELSE" bug
    rem if n=1 & f=1 then gosub "triple" 
    if n=1 then goto "checkstep"
    if n>1 then goto "nocheckstep"
    if f=1 then let q=1
    if f=2 then let q=0
    if q=1 then gosub "triple"
     if n>1 then gosub "triple"
next n

let v=f*3
for s=1 to v
    click "right"
    sleep 100
next s

rem Focus nearer than 5cm requires widest zoom (7.3mm focal length)
rem (I chose not to, but code could override using set_zoom 0)
print "***TO USE THIS SCRIPT***"
print "You MUST set camera"
print "to widest zoom"
print "then RESTART script."
goto "theend"

if x>11359 then gosub "infcrazy"
if x<11359 then gosub "hypcrazy"

rem 1199 is 1157+62 (1557mm is hyperfocal dist for f5.6 at 7.3mm focal length)
rem NOTE: user may have selected a different aperture
print "selected Start value is"
print "beyond hyperfocal dist!"
print "Most frames will have"
print "same (redundant) focus!"
print "paused --[ click SET ]--"

rem 11359 may not be a constant across various cameras; it is the
rem INF boundry get_focus value ***for 7.3mm focal length only*** on my A620
print "these Start+Step values"
print "will result in numerous"
print "identical / redundant"
print "INFINITY-focused frames"
print "paused --[ click SET ]--"