4.15. Međuspremnici slike

Kada se senzor kamere inicijalizira, kontinuirano emitira sličice pri svojoj brzini sličica – jednu novu sličicu svakim periodom sličice, bez obzira na to je li aplikacija spremna za nju ili ne. Svaka sličica treba negdje u RAM-u sletjeti ili je izgubljena. Skup međuspremnika slike mjesto je gdje te sličice borave između izlaska iz DMA-a i obrade od strane korisničkog koda, a koliko međuspremnika slike kamera drži u tom skupu određuje kako ih DMA i aplikacija dijele. Izbor je dostupan kroz framebuffers(), a na raspolaganju su četiri načina rada, odabrana brojem međuspremnika.

4.15.1. Jedan međuspremnik (count = 1)

Jedan međuspremnik slike u RAM-u. DMA ga puni; aplikacija čita iz njega; sljedeći poziv snapshot() ne može započeti dok aplikacija ne otpusti međuspremnik, jer je isti međuspremnik potreban za oboje.

Kamera i aplikacija rade u koraku. DMA mora čekati da aplikacija završi, a aplikacija mora čekati da DMA završi, što znači da je ostvariva brzina sličica u najboljem slučaju polovica brzine sličica senzora – svaka druga sličica koju senzor emitira stiže dok je međuspremnik zauzet i izgubljena je.

Ovaj način rada najmanji je u RAM-u i najsporiji u propusnosti. Koristite ga samo kada je RAM-a premalo da se dodijeli drugi međuspremnik.

4.15.2. Dvostruki međuspremnik (count = 2)

Dva međuspremnika slike u RAM-u: jedan stražnji (back) međuspremnik koji DMA puni i jedan prednji (front) međuspremnik iz kojeg aplikacija čita. Kada aplikacija završi s prednjim međuspremnikom, dvije se uloge zamijene, a DMA počinje puniti tek otpušteni međuspremnik dok aplikacija čita iz upravo napunjenog.

Sve dok aplikacija obrađuje svaku sličicu u manje od jednog perioda sličice kamere, aplikacija vidi punu brzinu sličica senzora – sljedeća sličica DMA-a već čeka u stražnjem međuspremniku kada aplikacija ponovno pozove snapshot(). Međutim, čim vrijeme obrade premaši jedan period sličice, brzina se prepolovi: kamera će proizvesti dvije sličice u vremenu koje je aplikaciji potrebno za obradu jedne, a bit će isporučena samo druga od te dvije.

Nakon te točke brzina se glatko smanjuje s vremenom obrade. Svaki put kada DMA završi novu sličicu stražnjeg međuspremnika dok aplikacija još radi na prednjem međuspremniku, nova sličica prepisuje prethodnu snimku na mjestu umjesto da bude odbačena. Aplikacija pri svojoj sljedećoj snapshot() uvijek dobiva najnoviju sličicu koju je kamera proizvela, a ostvariva brzina aplikacije postaje obrnuta vrijednost njezina vremena obrade.

4.15.3. Trostruki međuspremnik (count = 3)

Tri međuspremnika slike u RAM-u: dva stražnja (back) međuspremnika kroz koja DMA kruži i jedan prednji (front) međuspremnik na kojem aplikacija trenutačno radi. Ovo je zadani način rada koji OpenMV Cam odabire kada ima dovoljno slobodnog RAM-a, uz automatsko vraćanje na dvostruki ili jednostruki međuspremnik kada ga nema.

Treći međuspremnik potpuno razdvaja brzinu sličica kamere od brzine sličica aplikacije. DMA uvijek ima međuspremnik u koji može pisati; aplikacija uvijek ima međuspremnik iz kojeg može čitati; pri svakoj snapshot() najnoviji spremni stražnji međuspremnik postaje novi prednji međuspremnik, a prethodni prednji međuspremnik oslobađa se za DMA. Brzina sličica aplikacije odgovara vremenu koje stvarno treba za obradu svake sličice – bez koraka od 1/2 u koji upada dvostruki međuspremnik kada vrijeme obrade tek malo premaši jedan period sličice.

4.15.4. Video FIFO (count = 4 ili više)

Četiri ili više međuspremnika slike u RAM-u, raspoređenih kao prsten sličica snimljenih jedna za drugom. Svaka sličica koju kamera isporuči stavlja se u red u FIFO, a snapshot() vraća najstariju sličicu u redu, a ne najnoviju. Aplikacija prolazi kroz snimljene sličice redoslijedom snimanja, u vremenu koje stvarno ima za svaku od njih.

Ovaj način rada pravi je izbor kada je svaka sličica bitna i kada se očekuju kratki zastoji u obradi: pisanje videozapisa na SD karticu čiji se sloj pohrane može blokirati desetke milisekundi tijekom brisanja, streamanje preko USB-a na domaćina koji nakratko prestane čitati ili međuspremanje kratkog niza brzog događaja radi pregleda u kodu.

Dvije politike rješavaju slučaj kada se FIFO napuni prije nego što ga je aplikacija ispraznila.

  • Odbacivanje starih sličica (zadano). Kada se FIFO napuni, sve sličice u redu osim aktivne odbacuju se kako bi sljedeća snapshot() vratila nedavnu, a ne zastarjelu sličicu. DMA cijelo vrijeme nastavlja snimati, tako da aplikacija nakon zastoja uvijek vidi svježe podatke. Ovo je prava politika kada je cilj održavanje snimljenog streama aktualnim – snimanje videozapisa, streamanje uživo.

  • Zaustavljanje snimanja pri prelijevanju. Proslijedite fflush=False konstruktoru CSI i DMA prestaje puniti FIFO kada je pun, ostavljajući sličice u redu netaknutima. snapshot() nastavlja vraćati sličice redoslijedom snimanja dok ih aplikacija ne isprazni, nakon čega DMA nastavlja s radom. Ovo je prava politika kada je cilj očuvanje svake sličice kratkog niza – snimanje brzog kretanja radi pregleda sličicu po sličicu u kodu naknadno.

Pogledajte csi.CSI.framebuffers() za potpuni API.

4.15.5. Okidani način rada

Alternativa gore navedenim načinima rada koji su uvijek aktivni jest okidano snimanje, gdje senzor emitira sličicu samo kada snapshot() to zatraži. Kamera miruje između snimaka i svaki put kada je aplikacija pozove započinje novu ekspoziciju.

Cijena je propusnost: okidano snimanje ne može se preklapati s prethodnim, pa je najveća ostvariva brzina sličica polovica uobičajene brzine senzora. Korist je u vremenskom usklađivanju ekspozicije. Snimak točno kontrolira kada ekspozicija započinje, što aplikacija želi kada se ekspozicija mora poklopiti s vanjskim događajem – bljeskom stroboskopa, senzorom položaja na traci, impulsom na GPIO liniji – umjesto da se nađe gdje god se rotirajuća sličica slobodno tekućeg senzora slučajno zatekne kada je aplikacija spremna pročitati je.

Okidani način rada specifičan je za senzor. Na podržanim senzorima omogućuje se pozivom csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True), a onemogućuje prosljeđivanjem False.