Hi Leute, ich breche mir gerade die Ohren auf der Suche nach einer geeigneten Konfiguration, damit meine OV7670-Kamera (ohne FIFO) halbwegs farbechte Bilder auswirft (QVGA, YUV422). Hat jemand von Euch das schon einmal geschafft? Wenn ja: mit welchen Register Settings? Viele Grüße Igel1
Wie weit bist du denn vom Resultat entfernt? Kannst du schon erkennbare Bilder samplen? Das mit den Echtfarben hängt leider auch von der genutzten Linse ab, also Feinabstimmungen gegenüber anderen funktionnierenden Projekten wirst du in jedem Fall machen müssen. Ich hab's gerade nicht bei mir, kann dir aber morgen Abend meinen Code schicken. (wenn ich's nicht vergesse) macload1
In einem meiner Projekte hatte ich mich an diesen Register-Werten orientiert: https://github.com/dinuxbg/pru-gcc-examples/tree/master/ov7670-cam/host-uio Gab ein ziemlich blasses Bild, aber gut erkennbar und die Farben gingen schon in die richtige Richtung! Ich hoffe, dass dir das weiterhilft.
@Macload1: Vielen Dank schon einmal für Deine Hinweise! Ja, ich kann bereits QVGA-Bilder von der Kamera auf dem kleinen Display meines STM32F429-Discovery-Boards anzeigen. Der Weg ist: OV7670 -> DCMI -> DMA -> internes RAM meines STM32F429 Mikrocontrollers -> SPI -> ILI9341 Die Bilder scheinen mir korrekt und halbwegs scharf, aber ich habe bislang entweder nur sehr blasse Schwarzweiss-Bilder oder schwache Buntbilder mit Fehlfarben in Dunkelbereichen erhalten. Kontrast ist ebenfalls eher schwach und die automatische Belichtung neigt zur Überbelichtung. Zur Berechnung der RGB-Werte aus den YUV-Werten habe ich Jorge Aparicio's Formeln aus seinem Blog verwendet. Formeln: https://upload.wikimedia.org/wikipedia/en/math/4/e/b/4ebf7992636ec7100e2f0f68a4f2c2ca.png Blog: http://embeddedprogrammer.blogspot.de/2012/07/hacking-ov7670-camera-module-sccb-cheat.html Den von Dir verlinkten Codee werde ich einmal ausprobieren. Zusätzlich würde mich mich sehr freuen, wenn Du Deinen Code zur Verfügung stellen könntest. Viele Grüße Igel1 ---------------------------------------------------------------------- PS: Mit dieser Initialisierung erhalte ich eher Schwarz-Weiss-Bilder, die bereits bei leicht sich ändernder Beleuchtung in der Belichtung stark schwanken:
1 | // QVGA 320x240 |
2 | static unsigned char OV9655_QVGA[][2]= |
3 | { |
4 | 0x12, 0x80, |
5 | |
6 | 0x11, 0x01, |
7 | 0x12, 0x00, |
8 | 0x0C, 0x04, |
9 | 0x3E, 0x19, |
10 | 0x70, 0x3A, |
11 | 0x71, 0x35, |
12 | 0x72, 0x11, |
13 | 0x73, 0xF1, |
14 | 0xA2, 0x02 |
15 | } |
Und so verwandle ich den YUV422 - Code in RGB-Farben, die ich über eine Bibliotheksfunktion von Tilen Majerle an mein ILI9341 sende. Der Code ist weder schön noch effizient - es geht mir erst einmal nur darum, saubere Bilder zu sehen - Geschwindigkeit kommt später dran:
1 | // Bitte beachten: im Code wird zwar überall QQVGA als Bezeichner verwendet, |
2 | // in Wirklichkeit sind's aber QVGA-Werte, die ich nutze |
3 | |
4 | for(y_0=0; y_0<QQVGA_HEIGHT; y_0++) { |
5 | for(x_0=0; x_0<QQVGA_WIDTH; x_0+=2){ |
6 | if((x_0%4)==0){ |
7 | mycolorY = (int32_t)qqvgaframe1[x_0*2 + 1 + y_0*QQVGA_WIDTH*2]; |
8 | mycolorCb = (int32_t)qqvgaframe1[x_0*2 + 0 + y_0*QQVGA_WIDTH*2]; |
9 | mycolorCr = (int32_t)qqvgaframe1[x_0*2 + 2 + y_0*QQVGA_WIDTH*2]; |
10 | } else { |
11 | mycolorY = (int32_t)qqvgaframe1[x_0*2 + 1 + y_0*QQVGA_WIDTH*2]; |
12 | mycolorCb = (int32_t)qqvgaframe1[x_0*2 + 2 + y_0*QQVGA_WIDTH*2]; |
13 | mycolorCr = (int32_t)qqvgaframe1[x_0*2 + 0 + y_0*QQVGA_WIDTH*2]; |
14 | } |
15 | mycolorR = mycolorY + 1.402 * (mycolorCr - 128); |
16 | mycolorG = mycolorY - 0.34414 * (mycolorCb - 128) - 0.71414 * (mycolorCr - 128); |
17 | mycolorB = mycolorY + 1.772 * (mycolorCb - 128); |
18 | |
19 | // For ILI9341: RGB565 = [RRRRRGGG.GGGBBBBB] |
20 | mycolor=(uint32_t)(((mycolorR<<8)&0xF800) | ((mycolorG<<3)&0x07E0) | ((mycolorB>>3)&0x001F)); |
21 | //TM_ILI9341_DrawPixel(x_0, y_0, mycolor); // Doesn't work properly - fade/transparent colors |
22 | TM_ILI9341_DrawFilledCircle(x_0, y_0, 1, mycolor); // Works, slowly - has to be changed |
23 | } |
24 | } |
Ich sehe, dass du da eher die Initialisierungswerte vom OV9655 verwendest... Das würde sehr wohl dieses Verhalten erklären. Mit den Registern vom oben genannten Code, brauchst du auch keine "manuelle" Farbumwandlung vornehmen. Der OV7670 kann ganz alleine RGB Werte ausgeben anstatt YUV. Notfalls kannst du auch die folgenden Registerwerte versuchen: https://github.com/ArduCAM/Arduino/blob/master/ArduCAM/ov7670_regs.h macload1
Und wenn man mal die folgenden Begriffe bei Google eingibt, dann bekommt man richtig viele Resultate mit sehr viel Source-Code: "stm32 ov7670 dcim". Du brauchst ja auch eigentlich nur mehr die Registerwerte zu ändern, da der Rest ja schon zu funktionnieren scheint.
macload1 schrieb: > Ich sehe, dass du da eher die Initialisierungswerte vom OV9655 > verwendest... > > Das würde sehr wohl dieses Verhalten erklären. Oh, sorry - that's just to confuse the russian. Ich hatte ursprünglich Teile des Codes aus der Standard Peripheral Library von ST genommen - dort gibt es Beispiele für die OV9655 Kamera. Diesen Code habe ich anschließend auf die OV7670 angepasst - nur den Namen der Variablen habe ich nicht angepaßt. Das verwirrt natürlich - sorry. Die Initialisierungswerte stammen allen schön brav aus dem QVGA (30 fps QVGA YUV mode) Beispiel aus dem "OV7670/OV7171 CMOS VGA (640x480) CameraChip™ Implementation Guide", siehe dort S. 9 Mitte: http://www.haoyuelectronics.com/Attachment/OV7670%20+%20AL422B%28FIFO%29%20Camera%20Module%28V2.0%29/OV7670%20Implementation%20Guide%20%28V1.0%29.pdf Braver geht's schon gar nicht mehr :-) > > Mit den Registern vom oben genannten Code, brauchst du auch keine > "manuelle" Farbumwandlung vornehmen. Der OV7670 kann ganz alleine RGB > Werte ausgeben anstatt YUV. Ja - hast schon recht, aber ich hatte trotzdem erst einmal mit YUV begonnen, weil ich zunächst nur die Y-Komponente für ein S/W-Bild verwendet hatte. Damit konnte ich mir grundsätzliche Funktion erst einmal erarbeiten und dabei möglichst viele Fehlerquellen ausschließen. Und wo ich so schön bei YUV bin, möchte ich's auch erst einmal per YUV bunt bekommen. > > Notfalls kannst du auch die folgenden Registerwerte versuchen: > https://github.com/ArduCAM/Arduino/blob/master/ArduCAM/ov7670_regs.h > > macload1 Werde ich ausprobieren - Danke für den Tipp! Viele Grüße Igel1
macload1 schrieb: > Und wenn man mal die folgenden Begriffe bei Google eingibt, dann bekommt > man richtig viele Resultate mit sehr viel Source-Code: "stm32 ov7670 > dcim". ... von denen ich die meisten im Vorfeld schon gelesen habe - und trotzdem frage ich hier, weil viele von denen eben auch keine wirklich gute Register-Kombination gefunden haben und die meisten schon froh waren "irgendein" Bild aus der Kiste rauszuholen. > Du brauchst ja auch eigentlich nur mehr die Registerwerte zu ändern, da > der Rest ja schon zu funktionnieren scheint. Wenn Du das "nur" wegläßt, so stimme ich Dir zu. Es sind leider Dutzende von Registern - eins schlechter als das andere dokumentiert und ich wollte gerne eine wochenlange Try-and-Error Session vermeiden und von Leuten profitieren, die bereits gute Konfigurationen herausgefunden haben. Daher bin ich auch so an Deinem Code interessiert ;-) Viele Grüße Igel1
macload1 schrieb: > > [...] > > Notfalls kannst du auch die folgenden Registerwerte versuchen: > https://github.com/ArduCAM/Arduino/blob/master/ArduCAM/ov7670_regs.h > Hab's ausprobiert - es ergibt leider nur eine tannenbaumgrüne Fläche. Kein Bild nix. Viele Grüße Igel1
mit den Werten aus dem von dir angegebenen Tutorial hatte ich farblich gute Bilder: Beitrag "Re: DMA-Datentransfer OV7670 -> ARM-MCU"
Andreas S. schrieb: > Es sind leider Dutzende von Registern - eins schlechter als das andere > dokumentiert und ich wollte gerne eine wochenlange Try-and-Error Session > vermeiden und von Leuten profitieren, die bereits gute Konfigurationen > herausgefunden haben. ...das gerade Bitluni wohl recht erfolgreich hinter sich gebracht: http://bitluni.net/esp32-i2s-camera-ov7670/
Jan L. schrieb: > ...das gerade Bitluni wohl recht erfolgreich hinter sich gebracht: > http://bitluni.net/esp32-i2s-camera-ov7670/ Ja - sein Video kenne ich. Sieht definitiv gut aus. Habe mir auch gerade seinen Code angeguckt. Nur leider kann ich die Register-Settings nicht komprimiert an einer Stelle in seinem C++-Code finden. Außerdem verwendet er RGB. Es riecht etwas nach Arbeit, die benötigten OV6770-Register-Settings aus seinem Code zu extrahieren (stöööhn ...). Mal sehen, ob ich mir das in diesem Jahr noch antun möchte. Gibt's nicht vielleicht irgendwo doch noch eine einfachere Quelle, wo gut funktionierende Register-Settings alle schön an einer Stelle aufgeführt sind? Viele Grüße Igel1
Damit Ihr eine Vorstellung vom Stand meiner Forschungen habt, hier zwei Bilder: - einmal mein Roboter mit einer Samsung Galaxy S7 - Kamera aufgenommen und - einmal mit der OV7670 aufgenommen und auf einem ILI9341 - Display ausgegeben. (Achtung: dies ist eine etwas andere Szenerie - ich halte hier die Roboter vor die Kamera und im Hintergrund ist kein gemasertes Holz sondern die Zimmerdecke). Gut sichtbar: Rot und Grün sind irgendwie noch vertauscht und auch sonst ist noch nicht alles perfekt. Viele Grüße Igel1
:
Bearbeitet durch User
Ich habe mir einmal meinen oben zitierten Programmabschnitt genauer angeschaut und dabei festgestellt, dass ich nur jedes zweite Pixel in x-Richtung auslese und später auf das Display schreibe. War wohl doch etwas spät in der Nacht gewesen, als ich diesen Code zusammengeklopft hatte. Auch erklärt dies, warum meine Farben immer so blass und transparent waren: ein testweise zuvor gemalter Vollkreis war nämlich von meinem Bild niemals komplett überschrieben worden, sondern "schimmerte" immer durch - kein Wunder, wenn ich nur jedes zweite Pixel gesetzt habe ...). Zum Glück war dieser Fehler schnell gefixed. Zudem kann ich jetzt die Funktion "TM_ILI9341_DrawPixel" statt der Funktion "TM_ILI9341_DrawFilledCircle" verwenden - vormals war DrawPixel nicht "farbdeckend" genug. Jetzt weiss ich natürlich warum. Kleiner Nebeneffekt: das Bild wird nun ca. 10x so schnell gezeichnet. Sodann habe ich pragmatisch die Formeln zur Berechung von R-Wert und G-Wert vertauscht und schwupps - schon stimmen die Farben (jedenfalls überwiegend). Nun habe ich nur noch mit besonders hellen Bildbereichen zu kämpfen - dort kommt es zu "Farbsprüngen" - vermutlich irgendein Fehler beim Cast von Integern oder bei der Bitschieberei. Ich freue mich jetzt erst einmal über das nette Zwischenergebnis - siehe Bild im Anhang - und widme mich weihnachtlicheren Dingen ... Viele Grüße Igel1
Du bist Dir aber schon sicher, das die Farbausgabe auf dem ILI9341 richtig ist? Da gibt es ja auch diverse Konfigurationsregister bzgl. der Farbfolge und Bittiefe...
Egon schrieb: > Du bist Dir aber schon sicher, das die Farbausgabe auf dem ILI9341 > richtig ist? Da gibt es ja auch diverse Konfigurationsregister bzgl. der > Farbfolge und Bittiefe... Ja, relativ sicher: ich habe die folgenden 3 Bitkombinationen geprüft und damit testweise alle Pixel meines ILI-Display gefüllt: - 1111 1000.0000 0000 => Rot - 0000 0111.1110 0000 => Grün - 0000 0000.0001 1111 => Blau Daher denke ich, dass es stimmen müsste. Viele Grüße Igel1
Bin doch der Versuchung erlegen und habe noch ein bißchen herumprobiert. Mein Verdacht für die Pixel mit den Fehlfarben waren ja Cast-Fehler, die im Falle von Über- bzw. Unterläufen bei der Umwandlung von YUV (bzw. YCrCb) nach RGB entstehen. Also habe ich testweise den Code brute-force-mäßig so angepaßt, dass R,G,B-Werte in den Bereich 0 ... 255 "getrimmt" werden. Werte unter 0 habe ich dafür auf 0 hochgesetzt und Werte über 255 auf 255 heruntergesetzt. Schaut selber das Ergebnis an ... Hübsch gelle?! Und das Bild sieht in Wirklichkeit deutlich besser aus als auf dem Foto - und das trotz einer relativ miesen Ausleuchtung der Motive. Viele Grüße Igel1 --------------------------------------------------------------------
1 | // Bitte beachten: im Code wird zwar überall QQVGA als Bezeichner verwendet, |
2 | // in Wirklichkeit sind's aber QVGA-Werte, die ich nutze |
3 | |
4 | |
5 | for(y_0=0; y_0<QQVGA_HEIGHT; y_0++) { |
6 | for(x_0=0; x_0<QQVGA_WIDTH; x_0+=1){ |
7 | if((x_0%2)==0){ |
8 | mycolorY = (int32_t)qqvgaframe1[x_0*2 + 1 + y_0*QQVGA_WIDTH*2]; |
9 | mycolorCb = (int32_t)qqvgaframe1[x_0*2 + 0 + y_0*QQVGA_WIDTH*2]; |
10 | mycolorCr = (int32_t)qqvgaframe1[x_0*2 + 2 + y_0*QQVGA_WIDTH*2]; |
11 | } else { |
12 | mycolorY = (int32_t)qqvgaframe1[x_0*2 + 1 + y_0*QQVGA_WIDTH*2]; |
13 | mycolorCb = (int32_t)qqvgaframe1[x_0*2 - 2 + y_0*QQVGA_WIDTH*2]; |
14 | mycolorCr = (int32_t)qqvgaframe1[x_0*2 + 0 + y_0*QQVGA_WIDTH*2]; |
15 | } |
16 | mycolorG = (mycolorY + 1.402 * (mycolorCr - 128)); |
17 | mycolorR = (mycolorY - 0.34414 * (mycolorCb - 128) - 0.71414 * (mycolorCr - 128)); |
18 | mycolorB = (mycolorY + 1.772 * (mycolorCb - 128)); |
19 | |
20 | if (mycolorR<0) mycolorR=0; |
21 | if (mycolorG<0) mycolorG=0; |
22 | if (mycolorB<0) mycolorB=0; |
23 | |
24 | if (mycolorR>255) mycolorR=255; |
25 | if (mycolorG>255) mycolorG=255; |
26 | if (mycolorB>255) mycolorB=255; |
27 | |
28 | // For ILI9341: RGB565 = [RRRRRGGG.GGGBBBBB] |
29 | mycolor = (uint32_t)((mycolorR<<8 & 0xF800) | (mycolorG<<3 & 0x07E0) | (mycolorB>>3 & 0x001F)); |
30 | TM_ILI9341_DrawPixel(x_0, y_0, mycolor); |
31 | } |
32 | } |
:
Bearbeitet durch User
Karl K. schrieb: > mit den Werten aus dem von dir angegebenen Tutorial hatte ich farblich > gute Bilder: Ich bin verwirrt: welches von mir angegebene Tutorial meinst Du? Sodann habe ich soeben Deinen Link durchgearbeitet: > Beitrag "Re: DMA-Datentransfer OV7670 -> ARM-MCU" Ergebnis: ich kann dort keinen Code finden, der die OV7670-Register setzt. Evtl. müßtest Du mich nochmals mit der Nase darauf stoßen - ich scheine blind zu sein. Viele Grüße Igel1
Andreas S. schrieb: > welches von mir angegebene Tutorial meinst Du? http://embeddedprogrammer.blogspot.de/2012/07/hacking-ov7670-camera-module-sccb-cheat.html Das ist schon länger her. Ich meine, bei diesem tutorial war zumindest ein Verweis auf Standard-sccb-code.
grundschüler schrieb: > Andreas S. schrieb: >> welches von mir angegebene Tutorial meinst Du? > > http://embeddedprogrammer.blogspot.de/2012/07/hacking-ov7670-camera-module-sccb-cheat.html > > Das ist schon länger her. Ich meine, bei diesem tutorial war zumindest > ein Verweis auf Standard-sccb-code. Jetzt bin ich etwas verwirrt, denn da passen ein paar Sachen nicht zusammen: - meine Frage ging an Karl K. (leluno) und es antwortet "gundschüler". Bist Du derselbe? => bitte unter demselben Alias schreiben. - meine Frage bezog sich auf > Beitrag "Re: DMA-Datentransfer OV7670 -> ARM-MCU" Und Du verweist auf eine ganz andere Seite. - meine Frage bezog sich auf Register-Settings und Du verweist auf SCCB-Code. SCCB funktioniert bei mir - ich bin hauptsächlich an guten Register-Settings interessiert. Die von Dir zitierte Seite kenne ich - diese Seite ist wirklich gut, aber die Register-Settings aus dem referenzierten Code ergaben keine allzu dollen Bilder. Ich will aber nicht undankbar sein, daher: danke für die Mühen - nur versucht bitte auch ein bißchen auf meine Fragen einzugehen ... Viele Grüße Igel1
Andreas S. schrieb: > aber die Register-Settings aus dem referenzierten Code ergaben keine > allzu dollen Bilder. Ich wollte dich lediglich darauf hinweisen, dass die Registersettings aus dem von dir referenzierten Code - die meiner Erinnerung nach per sccb-protokoll in die kamera übertragen werden - bei meinen Versuchen farblich perfekte Bilder ergeben haben, so dass du mglw. Fehler nicht bei den Registersettings suchen musst. Ich würde dir die damals von mir verwendeten settings gerne zum Abgleich zur Verfügung stellen aber die Festplatte gibts leider nicht mehr. grundschüler karl k.
grundschüler schrieb: > Ich wollte dich lediglich darauf hinweisen, dass die Registersettings > aus dem von dir referenzierten Code - die meiner Erinnerung nach per > sccb-protokoll in die kamera übertragen werden - bei meinen Versuchen > farblich perfekte Bilder ergeben haben, so dass du mglw. Fehler nicht > bei den Registersettings suchen musst. Ah soooo ... Jetzt verstehe ich, was Du meinst. Nein, ich hatte keinerlei Code von dieser Seite verwendet, weil ich dort seinerzeit keinen Code gefunden hatte. Außerdem hatte ich anfangs noch den Ehrgeiz, alles selbst zu stricken - habe ich aber nicht lange durchgehalten. Das ganze endete letztendlich in Code, der von ca. ein Dutzend Websites zusammengemoppst und mit ca. 20% eigenem Code zusammengeklebt ist - nicht schön, aber läuft. Nur die Erkläuterungen zur Funktionsweise der Kamera hatte ich mir von der genannten Seite angelesen - genial einfach beschrieben von Jorge Aparicio. Nach Deinen Hinweisen und einigem Suchen habe ich nun aber tatsächlich den Code von Jorge Aparicio gefunden: Ein winziger Link auf seiner Seite verweist auf den Code - verborgen im Satz "You can (hopefully) see here (sorry, it's buried among other files) the schematic of the model I'm using in this post." Über den Link, hinter "here" kommt man an eine RAR-Datei OV7670.rar, in der sich der Source-Code befindet. Dort wiederum findet sich eine Datei "ov7670_init.c" mit zwei Funktionen, in denen jede Menge Register initialisiert werden: - static void init_yuv_12fps(void) - static void init_yuv_25fps(void) Damit werde ich in 2018 einmal mein Glück versuchen. Leider ist so eine Übernahme der Registerwerte in meinen Code recht aufwändig, denn ich muss (bzw. möchte) ja jeweils nachlesen, welcher Wert nun was genau bewirkt und ob's zu meinem Code passt. Denn sicherlich werden dort auch Auflösungen und Timings festgelegt, die nicht zu meinem Code passen. Anyway - Du hast mir auf jeden fall schon einmal gute Hoffnung gegeben, dass ich dort die gesuchten Register-Settings finden werde. Den Code von Jorge Aparicio's hatte ich beim ersten Lesen glatt übersehen. Danke also ganz herzlich für Deinen Hinweis! Viele Grüße Igel1
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.