4.15. Bildbuffertar¶
När kamerasensorn väl har initierats sänder den kontinuerligt ut bildrutor i sin bildhastighet – en ny bildruta varje bildperiod, oavsett om applikationen är redo för den eller inte. Varje bildruta behöver någonstans i RAM att landa, annars går den förlorad. Bildbuffertpoolen är där dessa bildrutor lever mellan att de lämnar DMA:n och att de bearbetas av användarkoden, och hur många bildbuffertar kameran håller i den poolen styr hur DMA:n och applikationen delar på dem. Valet exponeras via framebuffers(), och fyra lägen finns tillgängliga, valda utifrån antalet buffertar.
4.15.1. Enkel buffert (count = 1)¶
En bildbuffert i RAM. DMA:n fyller den; applikationen läser från den; nästa anrop till snapshot() kan inte starta förrän applikationen har frigjort bufferten, eftersom samma buffert behövs för båda.
Kameran och applikationen körs i låst takt. DMA:n måste vänta på att applikationen blir klar, och applikationen måste vänta på att DMA:n blir klar, vilket innebär att den uppnåeliga bildhastigheten i bästa fall är hälften av sensorns bildhastighet – varannan bildruta som sensorn sänder ut anländer medan bufferten är upptagen och går förlorad.
Detta läge är det minsta i RAM och det långsammaste i genomströmning. Använd det endast när RAM är för knappt för att allokera en andra buffert.
4.15.2. Dubbel buffert (count = 2)¶
Två bildbuffertar i RAM: en bakre buffert som DMA:n fyller, och en främre buffert som applikationen läser från. När applikationen blir klar med den främre bufferten byter de två rollerna plats, och DMA:n börjar fylla den nyss frigjorda bufferten medan applikationen läser från den nyss fyllda.
Så länge applikationen bearbetar varje bildruta på mindre än en kamerabildperiod ser applikationen sensorns fulla bildhastighet – DMA:ns nästa bildruta väntar redan i den bakre bufferten när applikationen anropar snapshot() igen. I samma ögonblick som bearbetningstiden överstiger en bildperiod halveras dock hastigheten: kameran producerar två bildrutor under den tid applikationen tar på sig att bearbeta en, och endast den andra av dessa två levereras.
Efter den punkten avtar hastigheten jämnt med bearbetningstiden. Varje gång DMA:n blir klar med en ny bildruta i den bakre bufferten medan applikationen fortfarande arbetar på den främre bufferten, skriver den nya bildrutan över den föregående bilden på plats istället för att kastas. Applikationen får alltid den senaste bildrutan kameran producerade vid sitt nästa snapshot(), och den uppnåeliga applikationshastigheten blir det inverterade värdet av dess bearbetningstid.
4.15.3. Trippel buffert (count = 3)¶
Tre bildbuffertar i RAM: två bakre buffertar som DMA:n växlar mellan och en främre buffert som applikationen för närvarande arbetar på. Detta är standardläget OpenMV Cam väljer när det finns tillräckligt med RAM att avvara, med automatisk återgång till dubbel eller enkel buffert när det inte finns det.
Den tredje bufferten frikopplar helt kamerans bildhastighet från applikationens bildhastighet. DMA:n har alltid en buffert att skriva till; applikationen har alltid en buffert att läsa från; vid varje snapshot() blir den senast färdiga bakre bufferten den nya främre bufferten och den föregående främre bufferten frigörs för DMA:n. Applikationens bildhastighet motsvarar den tid det faktiskt tar att bearbeta varje bildruta – utan det 1/2-steg som dubbel buffert hamnar i när bearbetningstiden glider precis förbi en bildperiod.
4.15.4. Video-FIFO (count = 4 eller fler)¶
Fyra eller fler bildbuffertar i RAM, ordnade som en ring av bildrutor fångade i följd. Varje bildruta kameran levererar köas in i FIFO:n, och snapshot() returnerar den äldsta köade bildrutan istället för den senaste. Applikationen går igenom de fångade bildrutorna i fångstordning, under den tid den faktiskt har att lägga på var och en.
Detta läge är det rätta valet när varje bildruta är viktig och korta bearbetningsstopp förväntas: att skriva video till ett SD-kort vars lagringsstack kan blockera i tiotals millisekunder under en radering, att strömma över USB till en värd som tillfälligt slutar läsa, eller att buffra en kort skur av en snabb händelse för granskning i kod.
Två policyer hanterar fallet där FIFO:n fylls innan applikationen har tömt den.
Släpp gamla bildrutor (standard). När FIFO:n fylls kastas alla köade bildrutor utom den aktiva, så att nästa
snapshot()returnerar en aktuell bildruta istället för en föråldrad. DMA:n fortsätter att fånga hela tiden, så applikationen ser alltid färska data efter ett stopp. Detta är den rätta policyn när målet är att hålla den fångade strömmen aktuell – videoinspelning, livestreaming.Sluta fånga vid överflöde. Skicka
fflush=FalsetillCSI-konstruktorn så slutar DMA:n fylla FIFO:n när den är full, och lämnar de köade bildrutorna intakta.snapshot()fortsätter att returnera bildrutor i fångstordning tills applikationen har tömt dem, varefter DMA:n återupptas. Detta är den rätta policyn när målet är att bevara varje bildruta av en kort skur – att fånga snabb rörelse för att granska bildruta för bildruta i kod efteråt.
Se csi.CSI.framebuffers() för det fullständiga API:t.
4.15.5. Utlöst läge¶
Ett alternativ till de alltid-igångvarande lägena ovan är utlöst fångst, där sensorn sänder ut en bildruta endast när snapshot() ber om en. Kameran står stilla mellan stillbilder och startar en ny exponering varje gång applikationen anropar.
Kostnaden är genomströmning: en utlöst fångst kan inte överlappa med den föregående, så den maximalt uppnåeliga bildhastigheten är hälften av sensorns normala hastighet. Fördelen är exponeringstidpunkten. Snapshot styr exakt när exponeringen börjar, vilket är vad en applikation vill ha när exponeringen måste sammanfalla med en extern händelse – ett blixtljus, en transportörspositionssensor, en puls på en GPIO-linje – istället för att hamna varhelst den fritt löpande sensorns rullande bildruta råkar vara när applikationen är redo att läsa den.
Utlöst läge är sensorspecifikt. På sensorer som stöds aktiveras det genom att anropa csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) och inaktiveras genom att skicka False.