![]() |
![]() |
![]() |
![]() ![]() |
Autofocus
Das automatische Fokussieren einer Kamera, ist ein recht interessanter Vorgang. Mit einer Wärmebildkamera, oder einer S/W (oder Mono) Kamera, lässt sich sowas relativ einfach machen. Schließlich gibt es hier nur eine Intensität, die es auszuwerten gilt. Bei Farbkameras ist das Ganze noch etwas komplexer, da hier auch Farbdifferenzen berücksichtigt werden sollten (geht auch ohne, aber dann schlechter). Man kann einerseits das ganze Bild im Durchschnitt scharfstellen, oder wie bei den meisten Kameras üblich, die Scharfstellung auf einen Teil des Bildes begrenzen. Es kommt ja schließlich nicht selten vor, dass die betrachteten Objekte in unterschiedlicher Entfernung stehen und daher ist es dem Nutzer zu überlassen, was er davon gern scharfgestellt hätte. Nachdem der Autofokus aktiviert wurde, wird mit einem Mausklick festgelegt, wo eigentlich der Autofokusbereich ist.
Hier der Code (C#) für die Kantenberechnung: int[,] dataset = new int[30,20]; for (int x = 0; x<30; x++) { for (int y = 0; y<20; y++) { //Datenerfassung: 43.5°C -> 435 dataset[x,y] = (int)(tempData[autofoc.X-15+x,autofoc.Y-10+y]*10); if (dataset[x,y]>max) { max = dataset[x,y]; } if (dataset[x,y]<min) { min = dataset[x,y]; } } } //dataset als Bild -> siehe Bild 1 autofoc_temp += max-min; for (int x = 1; x<30; x++) { for (int y = 1; y<20; y++) { int data=0; int val = dataset[x,y]-dataset[x-1,y];//Kante horizontal //differenzen aller Kanten zusammen addieren if (val<0) { data+=0-val; } else { data+=val; } val=dataset[x,y]-dataset[x,y-1];//Kante vertikal if (val<0) { data+=0-val; } else { data+=val; } val=dataset[x,y]-dataset[x-1,y-1];//Kante diagonal if (val<0) { data+=0-val; } else { data+=val; } //data als Bild -> siehe Bild 2 autofoc_cnt += val; //byte grenze if (data > 255) { data = 255; } if (data < 0) { data = 0; } C.red = (byte)data; C.green = (byte)data; C.blue = (byte)data; bmp_Source.SetPixel(x,y,C); } } Wenn die Kanten entsprechend ausgewertet sind, erhält man den Focuswert (hier autofoc_cnt genannt). Je besser Focussiert ist, desto stärker sind die Differenzen der benachbarten Pixel. Wenn die Focusintensität erst mal berechnet ist, muss nun noch die Bewegung der Linse entsprechend gesteuert werden. Unten ist zu sehen, wie ich das ganze bei meiner Mobir M8 umgesetzt hab. Es gibt bestimmt auch bessere Wege und dieser Code müsste für jede Kamera etwas angepasst werden. Aber die Grundstruktur dürfte erkennbar sein. Immerhin werden hier nur ein Bildsignal und 2 Linsenbewegungen (nah/fern) gebraucht. Auf eine Positionsangabe oder ähnliches, kann verzichtet werden. //Mitteln (durchschnitt aus 2 Messwerten) if (autofoc_lastcnt != 0) { //beim ersten durchlauf nicht halbieren autofoc_cnt = autofoc_cnt / 2; autofoc_temp = autofoc_temp / 2; } //beste Messwerte erfassen if (autofoc_cnt_max<autofoc_cnt) { autofoc_cnt_max = autofoc_cnt; } if (autofoc_temp_max<autofoc_temp) { autofoc_temp_max = autofoc_temp; } if (autofoc_far) { //nur Fern ############################# if (autofoc_temp>autofoc_temp_last||autofoc_cnt>autofoc_lastcnt) { label_Info.Text = "Focus: weiter weg..."; m8.Move("FAR"); autofoc_movecnt++; } else { autofoc_errcnt++; } if (autofoc_errcnt>5||autofoc_movecnt>40) { //genug Fehler -> weiter in die andere Richtung autofoc_movecnt = 0; autofoc_errcnt = 0; autofoc_far = false; autofoc_near = true; } } else if (autofoc_near) { //nur Nah ########################### if (autofoc_temp>autofoc_temp_last||autofoc_cnt>autofoc_lastcnt) { label_Info.Text = "Focus: zur Kamera..."; m8.Move("NEAR"); autofoc_movecnt++; if (autofoc_errcnt>0) { autofoc_errcnt--; } } else { autofoc_errcnt++; } if (autofoc_errcnt>5||autofoc_movecnt>40) { //genug Fehler -> weiter in die andere Richtung autofoc_movecnt = 0; autofoc_errcnt = 0; autofoc_near = false; } } else {//Nah und Fern #################################### if (autofoc_cnt>autofoc_cnt_max-autofoc_toleranz) { //Messwert nah genug am besten bisher gemessenen dran -> PASS do_autofoc = false; label_Info.Text = "Autofocus PASS..."; timer_infolabel.Enabled = true; return; } if (autofoc_errcnt>30) { //zu viele Fehlversuche, Autofocus fehlgeschlagen do_autofoc = false; label_Info.Text = "Autofocus FAIL..."; autofoc_movecnt = 0; autofoc_errcnt = 0; return; } if (autofoc_cnt>autofoc_cnt_max-autofoc_toleranz) { //Focuswert kleiner als der Letzte -> Richtungswechsel autofoc_switch=!autofoc_switch; } autofoc_errcnt++; if (autofoc_switch) { label_Info.Text = "Focus: zur Kamera..."; m8.Move("NEAR"); } else { label_Info.Text = "Focus: weiter weg..."; m8.Move("FAR"); } //Motorbewegung abwarten thread.Sleep(100); } autofoc_lastcnt = autofoc_cnt; autofoc_temp_last = autofoc_temp; Die Messwerte unterliegen leider nicht ganz unwesentlichen Schwankungen, weshalb autofoc_cnt und autofoc_temp auch leicht gemittelt werden (AVR = 2). Das wird einfach dadurch erreicht, dass während der Berechnung die neuen Werte zu den alten hinzugefügt werden. Dann werden sie vor dem Auswerten durch 2 geteilt (außer beim ersten Durchlauf). Inzwischen funktioniert der Autofocus recht passabel. Es klappt leider nicht immer (trotz gutem Kontrast). Aber wenn für die Berechnungen mehr gemittelt werden würde, wäre es zwar genauer, aber eben auch um einiges langsamer (Messwerte zum Mitteln, sind nur bedingt zur Berechnung nützlich). Es gilt die Balance zwischen Geschwindigkeit und Qualität zu waren...
|
|