wie ich hier schon beschrieben habe, haben die Funktionen get_dof und get_hyp (Bestimmung von Tiefenschärfe und Hyperfokal-Distanz) so ihre Tücken. Vor allem im Makrobereich stimmt die Ausgabe von get_dof einfach nicht, außerdem liefern die Funktionen je nach Status der Kamera unterschiedliche Werte zurück.
Jedenfalls habe ich nun ein paar Lua-Funktionen geschrieben, mit denen das Ganze besser funktioniert.
Insgesamt werden 3 Funktionen benötigt:
Die Funktion get_av1000(_apex96) wandelt den von get_av96() gelieferten sogenannten Apex-Blendenwert in normale Blendenwerte um. Da CHDK nur Ganzzahlberechnungen unterstützt, wird der Wert*1000 zurückgeliefert, also z.B. für Blende 2,8 sind es dann 2800. Die Werte weichen durch die verwendete Approximation ein wenig (ca. 1 %) von den richtigen Werten ab, eine zusätzliche Diskrepanz ergibt sich daraus, dass die bekannten Werte 2,8, 4,0, 5,6 etc. auch nur Näherungen sind, z.B. 2,8 ist in Wirklichkeit 2,828.
Syntax: [ Download ] [ Verstecken ]
Benutze Lua Syntax Highlighting
function get_av1000(_apex96) -- convert Apex96 aperture to 1000x Av value
-- approximate by quadratic equation av1000 = (k2 * apex96 ^ 2 + k1 * apex96 + k0) / 1000
-- with k2 = 32 k1 = -9648 k0 = 2998100
return (_apex96 * _apex96 * 32 - _apex96 * 9648 + 2998100) / 1000
end
-- approximate by quadratic equation av1000 = (k2 * apex96 ^ 2 + k1 * apex96 + k0) / 1000
-- with k2 = 32 k1 = -9648 k0 = 2998100
return (_apex96 * _apex96 * 32 - _apex96 * 9648 + 2998100) / 1000
end
Erstellt in 0.006 Sekunden, mit GeSHi 1.0.8.9
Die Funktion get_hyp_dst1(_av1000, _foc_length) liefert in Abhängigkeit von der Blendenzahl und der Brennweite die Hyperfokus-Entfernung in mm. Hierfür muss in der Variablen conf_circle die Größe des Zerstreuungskreises (bei meiner A710 sind es 5 µm definiert sein:
Syntax: [ Download ] [ Verstecken ]
Benutze Lua Syntax Highlighting
conf_circle = 5 -- circle of confusion = 5 µm
...
function get_hyp_dst1(_av1000, _foc_length) -- hyperfocal distance calculation from focal length and aperture
-- av1000 = 1000 * Av, foc_length in mm, global conf_circle in µm
return _foc_length * _foc_length / _av1000 / conf_circle + (_foc_length + 500) / 1000 -- round additive foc_length
end -- return value is in mm
...
function get_hyp_dst1(_av1000, _foc_length) -- hyperfocal distance calculation from focal length and aperture
-- av1000 = 1000 * Av, foc_length in mm, global conf_circle in µm
return _foc_length * _foc_length / _av1000 / conf_circle + (_foc_length + 500) / 1000 -- round additive foc_length
end -- return value is in mm
Erstellt in 0.005 Sekunden, mit GeSHi 1.0.8.9
Die Funktion get_dof1(_dst, _av1000, _f_len) berechnet mit Hilfe von get_hyp_dst1 aus dem Fokus in mm Achtung, ab Linse!!!, der Blende und der Brennweite die Tiefenschärfe in mm. Dass die Rechnung etwas kompliziert aussieht, liegt daran, dass die Zahlen richtig skaliert werden müssen, um Fehler durch Wertüberläufe oder abgeschnittene Nachkommastellen zu vermeiden:
Syntax: [ Download ] [ Verstecken ]
Benutze Lua Syntax Highlighting
function get_dof1(_dst, _av1000, _f_len) -- get depth of field
-- dst = focal distance in mm, av1000 = 1000 * Av value, f_len = focal length in µm
-- dof = _dst * (_hyp - _f_len) * (1 / (_hyp - _dst) - 1 / (_hyp + _dst - 2 * _f_len), rounded to mm
_hyp = get_hyp_dst1(_av1000, _f_len)
_f_len = (_f_len + 500) / 1000 -- round to mm (accuracy is sufficient here)
if _dst > _hyp then
return -1, _hyp -- inf
else
if _dst < 1000 then div = 1 elseif _dst < 10000 then div = 10 else div = 100 end
numerator = _dst * 10 / div * (_hyp - _f_len) -- calculate in mm, result * 10
denom1 = (_hyp - _dst) / div -- div keeps numerator < max integer
denom2 = (_hyp + _dst - 2 * _f_len) / div
return ((numerator / denom1 - numerator / denom2) + 5) / 10, _hyp -- round to mm
end -- return dof, hyp in mm
end
-- dst = focal distance in mm, av1000 = 1000 * Av value, f_len = focal length in µm
-- dof = _dst * (_hyp - _f_len) * (1 / (_hyp - _dst) - 1 / (_hyp + _dst - 2 * _f_len), rounded to mm
_hyp = get_hyp_dst1(_av1000, _f_len)
_f_len = (_f_len + 500) / 1000 -- round to mm (accuracy is sufficient here)
if _dst > _hyp then
return -1, _hyp -- inf
else
if _dst < 1000 then div = 1 elseif _dst < 10000 then div = 10 else div = 100 end
numerator = _dst * 10 / div * (_hyp - _f_len) -- calculate in mm, result * 10
denom1 = (_hyp - _dst) / div -- div keeps numerator < max integer
denom2 = (_hyp + _dst - 2 * _f_len) / div
return ((numerator / denom1 - numerator / denom2) + 5) / 10, _hyp -- round to mm
end -- return dof, hyp in mm
end
Erstellt in 0.006 Sekunden, mit GeSHi 1.0.8.9
Diese Funktion liefert außer der Tiefenschärfe auch gleich die Hyperfokus-Distanz zurück.
Bei der Anwendung im Skript muss vor dem Auslesen der Blende shoot_half() ausgeführt werden, da sonst falsche Blendenwerte zurückgeliefert werden:
Syntax: [ Download ] [ Verstecken ]
Benutze Lua Syntax Highlighting
press "shoot_half" -- required for correct get_av96
repeat until get_shooting() == true -- wait until finished
av1000 = get_av1000(get_av96()) -- get Apex96 aperture and convert to 1000x Av value
dof, hyp = get_dof1(current_focus, av1000, focal_length) -- calculate DOF and HYP for this photo
release("shoot_half")
repeat until get_shooting() == true -- wait until finished
av1000 = get_av1000(get_av96()) -- get Apex96 aperture and convert to 1000x Av value
dof, hyp = get_dof1(current_focus, av1000, focal_length) -- calculate DOF and HYP for this photo
release("shoot_half")
Erstellt in 0.004 Sekunden, mit GeSHi 1.0.8.9
current_focus ist die Objektentfernung in mm ab Linse, für die die Berechnung erfolgen soll. Bei Verwendung von get_focus() muss der Abstand zwischen CCD und Frontlinse abgezogen werden.
focal_length ist die eingestellte Brennweite in µm (nicht mm!)
Im Makrobereich kann es durchaus vorkommen, dass der zurückgelieferte DOF-Wert Null ist. Dies ist der Fall, wenn die Tiefenschärfe unter 0,5 mm liegt. Wenn der Fokus größer als die Hyperfokal-Distanz ist, wird der Wert -1 zurückgeliefert, da DOF dann unendlich ist.
Ich habe das so weit bei unterschiedlichsten Brennweiten, Blenden und Fokusentfernungen getestet, und es scheint immer zu funktionieren.
Falls jemand Fehler feststellt, bin ich für Rückmeldung dankbar.
Gruß
elektronikfreak