[Lua] Das bessere get_dof und get_hyp

CHDK-Skripte, CHDK-Entwicklung, PC-Zusatzprogramme, Informationen für Tüftler

Das bessere get_dof und get_hyp

Beitragvon elektronikfreak » 17.12.2009, 09:51

Hallo,
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
 
Erstellt in 0.003 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
 
Erstellt in 0.003 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
 
Erstellt in 0.004 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")
 
Erstellt in 0.003 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
Zuletzt geändert von elektronikfreak am 24.12.2009, 18:04, insgesamt 1-mal geändert.
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon msl » 17.12.2009, 18:24

Hallo elektronikfreak,

sehr schöner Beitrag. =D>

Könnte man diese Funktionen nicht in einer Art Funktionsbibliothek zusammenfassen und in ein Skript schreiben. Solche Skripte können per require(<Skriptname>) in andere Skripte eingebunden werden. Die darin enthaltenen Funktionen stehen dann im eigentlichen Skript zur Verfügung. Damit das dann auch für alle zur Verfügung steht, würde ich es an passender Stelle in unsere CHDK-DE-Version einfügen.

Gruß msl
■ "Hey you, don't tell me there's no hope at all. Together we stand, divided we fall."CHDK inside FAQCHDK-Neuigkeiten auf Twitter
Benutzeravatar
msl
Super-Mod
Super-Mod
 
Beiträge: 4501
Bilder: 271
Registriert: 22.02.2008, 12:47
Wohnort: Leipzig
Kamera(s): A720 1.00c
SX220 1.01a

Beitragvon elektronikfreak » 17.12.2009, 21:17

Hallo msl,
ja klar. Aber nachdem die Funktionen noch ziemlich "druckfrisch" sind, möchte ich erst noch etwas mehr testen, vielleicht probieren ja auch noch ein paar mehr Leute das mal aus. Soll ja schon vorgekommen sein, dass Skripte nicht unter allen Umständen so funktioniert haben, wie sie sollten.
Wenn ich das richtig verstanden habe, muss ich einfach nur die Funktionen in eine Lua-Datei sozusagen ohne Main-Programm packen, oder?
Außerdem würde ich dazu dann noch ein wenig Doku liefern.

Aber es gibt da sowieso noch ein paar offene Punkte:
Wo bekomme ich den Wert für conf_circle her? Der steht jetzt einfach mal so als globale Variable da, aber eigentlich brauche ich ja einen kameraspezifischen Wert. Gibt's da was?
Ähnlich ist es mit den Brennweiten. Ich habe zwar eine Funktion geschrieben, die den Zoomwert ausliest und das Ergebnis anhand einer Wertetabelle in Brennweite umrechnet, aber das passt natürlich nur für meinen Kameratyp. Natürlich könnte ich auch diese Funktion zur Verfügung stellen, aber die müsste man dann ggf. selber an die Kamera anpassen, was natürlich am Sinn einer Library etwas vorbeigeht.

Gruß

elektronikfreak
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon fe50 » 17.12.2009, 22:46

@elektronikfreak

Die Werte findest Du im CHDK Sourcecode...circle of confusion jeweils in shooting.c (unter \platform)
"The grass was greener, The light was brighter"►  ◄fe50 home►  ◄TRAIL-Magazin►  ◄RTFM !
Benutzeravatar
fe50
CHDK-Legende
CHDK-Legende
 
Beiträge: 1105
Registriert: 25.04.2008, 15:28
Wohnort: B'Württemberg
Kamera(s): Ixus50 101b, Ixus860 100c, SX10 101a

Beitragvon elektronikfreak » 17.12.2009, 23:22

fe50 hat geschrieben:Die Werte findest Du im CHDK Sourcecode...circle of confusion jeweils in shooting.c (unter \platform)

Hallo fe50,
ich meine nicht die Zahlenwerte für meine Kamera, die habe ich ja bereits. Aber wenn jemand meine Funktionen für eine andere Kamera nutzen will, muss er die Werte für diese Kamera herausfinden und manuell eintragen. Ich wollte wissen, ob es eine Möglichkeit gibt, das irgendwie zu automatisieren - so dass die Funktionen ohne manuelle Änderung für andere Kamera genutzt werden können. Also ohne dass ich eine Tabelle mit sämtlichen Brennweite-Werten sämtlicher Kameras anlegen muss :shock: .
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon msl » 17.12.2009, 23:30

Hallo elektronikfreak,

sicherlich muss das ganze Projekt noch etwas durchdacht und getestet werden. Es wäre aber eine gute Möglichkeit, einen einheitlichen Standard für weiterführende Berechnungen zu schaffen.

Wir haben jetzt 48 verschiedene Kamera-Modelle. Für diese müssten die Werte in eine Tabelle eingetragen werden. Über die Funktion get_buildinfo() kann die Plattform ermittelt werden. Aus der Tabelle werden dann die notwendigen Daten zugeordnet. Eine andere Möglichkeit sehe ich nicht - leider.

Die Werte für Brennweite und Circle of Confusion sind nicht sofort auffindbar, da diese leider nicht einheitlich in den Plattform-abhängigen Dateien eingefügt wurden. Wie fe50 schon schrieb, ist der coc-Wert zuerst in shooting.c zu suchen. Die Werte für die Brennweiten findet man meistens in main.c oder shooting.c in der Funktion static const int fl_tbl[].

Gruß msl
■ "Hey you, don't tell me there's no hope at all. Together we stand, divided we fall."CHDK inside FAQCHDK-Neuigkeiten auf Twitter
Benutzeravatar
msl
Super-Mod
Super-Mod
 
Beiträge: 4501
Bilder: 271
Registriert: 22.02.2008, 12:47
Wohnort: Leipzig
Kamera(s): A720 1.00c
SX220 1.01a

Beitragvon naddel » 18.12.2009, 17:43

Hallo,

Wenn jetzt ein Rechenweg gefunden wurde der auch funktioniert stellt sich mir die Frage warum man nicht gleich den DOF-Rechner dahingehen umstellen kann, daß er bessere Werte liefert. Deswegen gab es in den letzten Wochen doch einige Verwirrung. Im DOF-Rechner sollten die kameraspezifischen Daten doch leicht erreichbar sein.

Gruß naddel
S2 1.00f mit aktueller DE Version
Benutzeravatar
naddel
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 156
Registriert: 26.01.2009, 20:42
Kamera(s): G3 s2 ixusii

Beitragvon elektronikfreak » 18.12.2009, 20:47

naddel hat geschrieben:warum man nicht gleich den DOF-Rechner dahingehen umstellen kann, daß er bessere Werte liefert. Deswegen gab es in den letzten Wochen doch einige Verwirrung. Im DOF-Rechner sollten die kameraspezifischen Daten doch leicht erreichbar sein.

Die Frage ist berechtigt, das sollte so schwer nicht sein. Leider kenne ich mich aber mit der Implementierung in CHDK-Code nicht aus.
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon gehtnix » 18.12.2009, 22:55

elektronikfreak hat geschrieben:Die Frage ist berechtigt, das sollte so schwer nicht sein. Leider kenne ich mich aber mit der Implementierung in CHDK-Code nicht aus.
Guckt ihr hier. Der Status steht seit Juli auf "Neu".

gruß gehtnix
Bild
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 13:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS50 101b

Beitragvon elektronikfreak » 19.12.2009, 12:27

gehtnix hat geschrieben:Der Status steht seit Juli auf "Neu".

Da geht's aber speziell um get_hyp_dst. Die Funktion get_dof hat das gleiche Problem, und das hat wohl auch die gleiche Ursache, nämlich dass die gewählte Blende erst mit shoot_half tatsächlich eingestellt wird - was auch logisch ist. Außerdem liefert get_dof im Makrobereich generell viel zu große Werte, wahrscheinlich, weil hier die Entfernungen ab CCD gerechnet werden und nicht ab Linse, wie es richtig wäre.
Aus der Tatsache, dass ein Bug schon seit Monaten bekannt sind und nicht behoben wurde, würde ich auch nicht unbedingt schließen, dass sich da bald etwas tut. Genau aus dem Grund verlasse ich mich in solchen Fällen lieber nicht auf andere, sondern schreibe meine eigene Funktion, von der ich weiß, dass sie zumindest für meine Zwecke funktioniert.
Und wenn ich sie schon mal geschrieben habe, stelle ich sie auch zur Diskussion und zur freien Verfügung.

Gruß

elektronikfreak
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon gehtnix » 20.12.2009, 16:37

Hi,

elektronikfreak hat geschrieben:Da geht's aber speziell um get_hyp_dst.
Sollte ja nur aufzeigen dass der Fehler bekannt ist und nix passiert. Ist aber nicht nur bei diesem Fehler der Fall.

Mit dem Skripten habe ich es gerade dar nicht so :roll: Stehe wie ein Ochs vorm Berg und kapier mal garnix.
Mit meiner gestrige Portion Spinat habe ich Dein "Blende=2 ^ (get_av96 / 192) " aufgegriffen und das in HDR-Hyper eingesetzt. Als ich das dann drinnen hatte stellte ich mir die Frage wieso ich das überhaupt mache. Ging doch vorher auch mit get_av. Hat allerdings den Mehraufwand mit der "fehlenden Blende", jedoch einen kleinen zeitlichen Vorteil weil das "shoot-half" wegfällt.

Die Focal Length habe ich für das HDR-Hyper schon mal gesammelt, siehe Anhang.

gruß gehtnix
Dateianhänge
Focal Length.txt
(1.96 KiB) 35-mal heruntergeladen
Bild
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 13:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS50 101b

Beitragvon elektronikfreak » 20.12.2009, 20:11

gehtnix hat geschrieben:...stellte ich mir die Frage wieso ich das überhaupt mache. Ging doch vorher auch mit get_av.

Hallo gehtnix,
ich dachte auch erst mal an get_av, aber mein Lua-Skript wollte davon nichts wissen. Sowie die Funktion im Skript steht, sagt die Kamera, kennt sie nicht, hat sie nie gesehen - da bin ich auf get_av96 ausgewichen.
Ich denke mal, die Funktion ist in Lua nicht implementiert, weil es in CHDK-Lua nur Ganzzahlen gibt. Dann ergibt get_av wegen der Nachkommastellen keinen Sinn. Deshalb habe ich auch diese Krücke mit av1000 gebraucht.

Aber noch eine Anmerkung: auch get_av96 funktioniert nur dann richtig, wenn man vorher shoot_half ausführt und wartet, bis get_shooting auf true geht. Das ist, wie gesagt, ein prinzipielles Problem: egal welche Blende vorgewählt oder ermittelt wurde: eingestellt wird sie erst mit shoot_half bzw. shoot. Und nur dann liefern die Funktionen die richtigen Werte zurück.

Gruß

elektronikfreak
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon gehtnix » 20.12.2009, 22:42

elektronikfreak hat geschrieben:Dann ergibt get_av wegen der Nachkommastellen keinen Sinn.
Da gibt es keine Nachkommastellen, da gibt es eine ID-Nr. Siehe HDR-Hyper.

Deine Lösung hat den Vorteil bei der 1 Sekundengrenze, wenn die Kamera die Blende von 8 runter schaltet. Da muß HDR-Hyper passen.

Wenn Du gerade nicht weißt was Du tun sollst, schreib mir doch mal bitte die DOF-Formel auf qbasic um. Das bekomme ich momentan nicht gebacken.

DOF=0 kann man ja mit einer Schleife hochrechnen lassen bis DOF=1. Dann hat man den Fokus. Dort liegt dann der kleinste Startpunkt.

gruß gehtnix
Bild
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 13:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS50 101b

Beitragvon elektronikfreak » 21.12.2009, 11:04

gehtnix hat geschrieben:Da gibt es keine Nachkommastellen, da gibt es eine ID-Nr. Siehe HDR-Hyper.

Ok, dort ist die Umrechnung in "echte" Blendenwerte mit einer Lookup-Tabelle realisiert, alles klar. Die wäre für get_av96 natürlich etwas länglich, da es dort auch alle möglichen Zwischenwerte gibt. Deshalb habe ich das mit der Approximationsformel gelöst.
gehtnix hat geschrieben:Deine Lösung hat den Vorteil bei der 1 Sekundengrenze, wenn die Kamera die Blende von 8 runter schaltet. Da muß HDR-Hyper passen.
Mir ist nicht klar, wieso das ein dort ein Problem ist - dann hast du halt eine andere Blende und rechnest mit der weiter.
gehtnix hat geschrieben:Wenn Du gerade nicht weißt was Du tun sollst
:badgrin:
gehtnix hat geschrieben:...schreib mir doch mal bitte die DOF-Formel auf qbasic um. Das bekomme ich momentan nicht gebacken.

Poste doch einfach mal das, was du versucht hast, und schreib' dazu, was das Problem ist. Dann werde ich schon sehen, warum es nicht geht.
gehtnix hat geschrieben:DOF=0 kann man ja mit einer Schleife hochrechnen lassen bis DOF=1. Dann hat man den Fokus. Dort liegt dann der kleinste Startpunkt.

Könnte man, aber dann kann man in Bereichen mit DOF<1 gar keine Fotos machen. Besser ist if DOF<1 then DOF=1. Dann werden dort die Bilder halt mit 1 mm Abstand gemacht, auch wenn die Tiefenschärfe in Wirklichkeit noch geringer ist. Aber besser als gar nichts.

Gruß elektronikfreak
A710IS, EOS500D
elektronikfreak
CHDK-Begeisterter
CHDK-Begeisterter
 
Beiträge: 74
Registriert: 31.03.2009, 21:33
Wohnort: München

Beitragvon gehtnix » 21.12.2009, 16:02

elektronikfreak hat geschrieben:Mir ist nicht klar, wieso das ein dort ein Problem ist - dann hast du halt eine andere Blende und rechnest mit der weiter.
Nun, wenn Du Blende 8 eingestellt hast und zuwenig Licht ist, da schaltet die Kamera im AV-Modus wegen der 1 Sekundengrenze selber runter auf die passende Blende . Das kommt aber erst nach dem half_shoot zum Vorschein.
Hat man jetzt Blende 2.8 und Brennweite bei 9,5mm dann kann ich das mit der Lookuptabelle im Voraus auf die geänderte Blende 3.2 berechnen und fokussieren.
Ein half_shoot ist hier nicht notwendig. Das bringt mir nach meinem Vorgehen einen zeitlichen Vorteil.
Mit get_av96 wird ja bei jedem Auslösen ein half_shoot notwendig, auch wenn sich an der Kamereinstellung garnix verändert hat.
Mit meinem Skript wird aber obiges runterschalten auf Blende 7.1 nicht ausgeglichen, das bekommt das Skript nicht mit.

Das HDR-Hyper-Skript ist anders angelegt. Nach dem Skriptstart steht der Fokus automatisch auf dem Hyperfocalen. Zoomt frau/mann ebenso, wird unmittelbar nachgeführt. Auf den Auslöser gedrückt, erfolgt ohne weiteres fokussieren das Foto.

elektronikfreak hat geschrieben:Poste doch einfach mal das, was du versucht hast
In Susi2Stack erfolgt am Anfang ein halt_shoot wegen der Entfernung. Das könnte ich die Blende nehmen. Weiter unten wird dann get_dof genommen. Da könnte jetzt der DOF errechnet werden. Aber ahhhh, dann brauchen wir die Brennweite... das würde dann für jede Kamera ein Skript ergeben.

elektronikfreak hat geschrieben:Besser ist if DOF<1 then DOF=1
Auch eine Möglichkeit

Gruß gehtnix
Bild
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 13:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS50 101b

Nächste

Zurück zu Code-Ecke

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste