4.15. Framebuffers¶
Una vez que el sensor de la cámara se inicializa, emite fotogramas de forma continua a su velocidad de fotogramas: un nuevo fotograma en cada periodo de fotograma, esté o no preparada la aplicación para recibirlo. Cada fotograma necesita un lugar en la RAM donde aterrizar o, de lo contrario, se pierde. El conjunto de framebuffers es donde residen esos fotogramas entre el momento en que salen del DMA y el momento en que el código de usuario los procesa, y la cantidad de framebuffers que la cámara mantiene en ese conjunto controla cómo se los reparten el DMA y la aplicación. Esta elección se expone a través de framebuffers(), y hay cuatro modos disponibles, seleccionados según el número de búferes.
4.15.1. Búfer único (count = 1)¶
Un framebuffer en la RAM. El DMA lo llena; la aplicación lee de él; la siguiente llamada a snapshot() no puede comenzar hasta que la aplicación haya liberado el búfer, porque ambos necesitan el mismo búfer.
La cámara y la aplicación funcionan al unísono. El DMA tiene que esperar a que la aplicación termine, y la aplicación tiene que esperar a que el DMA termine, lo que significa que la velocidad de fotogramas alcanzable es, en el mejor de los casos, la mitad de la velocidad de fotogramas del sensor: uno de cada dos fotogramas que emite el sensor llega cuando el búfer está ocupado y se pierde.
Este modo es el que menos RAM consume y el de menor rendimiento. Úselo únicamente cuando la RAM sea demasiado escasa para asignar un segundo búfer.
4.15.2. Doble búfer (count = 2)¶
Dos framebuffers en la RAM: un búfer trasero que el DMA llena y un búfer frontal del que lee la aplicación. Cuando la aplicación termina con el búfer frontal, los dos roles se intercambian, y el DMA empieza a llenar el búfer recién liberado mientras la aplicación lee del que se acaba de llenar.
Mientras la aplicación procese cada fotograma en menos de un periodo de fotograma de la cámara, la aplicación ve la velocidad de fotogramas completa del sensor: el siguiente fotograma del DMA ya está esperando en el búfer trasero cuando la aplicación vuelve a llamar a snapshot(). Sin embargo, en el momento en que el tiempo de procesamiento supera un periodo de fotograma, la velocidad se reduce a la mitad: la cámara producirá dos fotogramas en el tiempo que la aplicación tarda en procesar uno, y solo se entregará el segundo de esos dos.
A partir de ese punto, la velocidad se degrada de forma gradual con el tiempo de procesamiento. Cada vez que el DMA termina un nuevo fotograma en el búfer trasero mientras la aplicación sigue trabajando en el búfer frontal, el nuevo fotograma sobrescribe la captura anterior en su sitio en lugar de descartarse. La aplicación siempre obtiene el fotograma más reciente que produjo la cámara en su siguiente snapshot(), y la velocidad alcanzable de la aplicación pasa a ser la inversa de su tiempo de procesamiento.
4.15.3. Triple búfer (count = 3)¶
Tres framebuffers en la RAM: dos búferes traseros por los que el DMA va rotando y un búfer frontal en el que la aplicación está trabajando en ese momento. Este es el modo predeterminado que elige la OpenMV Cam cuando hay suficiente RAM disponible, con repliegue automático a doble o único búfer cuando no la hay.
El tercer búfer desacopla por completo la velocidad de fotogramas de la cámara de la velocidad de fotogramas de la aplicación. El DMA siempre tiene un búfer en el que escribir; la aplicación siempre tiene un búfer del que leer; en cada snapshot(), el búfer trasero listo más reciente se convierte en el nuevo búfer frontal y el búfer frontal anterior se libera para el DMA. La velocidad de fotogramas de la aplicación coincide con el tiempo que realmente tarda en procesar cada fotograma, sin el salto de 1/2 en el que cae el doble búfer cuando el tiempo de procesamiento supera ligeramente un periodo de fotograma.
4.15.4. FIFO de vídeo (count = 4 o más)¶
Cuatro o más framebuffers en la RAM, organizados como un anillo de fotogramas capturados de forma consecutiva. Cada fotograma que entrega la cámara se encola en la FIFO, y snapshot() devuelve el fotograma encolado más antiguo en lugar del más reciente. La aplicación recorre los fotogramas capturados en el orden de captura, en el tiempo del que realmente dispone para cada uno.
Este modo es la opción adecuada cuando cada fotograma importa y se esperan breves pausas de procesamiento: escribir vídeo en una tarjeta SD cuya pila de almacenamiento puede bloquearse durante decenas de milisegundos durante un borrado, transmitir por USB a un host que deja de leer brevemente, o almacenar en búfer una ráfaga corta de un evento rápido para inspeccionarla en el código.
Dos políticas gestionan el caso en que la FIFO se llena antes de que la aplicación la haya vaciado.
Descartar fotogramas antiguos (predeterminado). Cuando la FIFO se llena, todos los fotogramas encolados excepto el activo se descartan, de modo que la siguiente
snapshot()devuelva un fotograma reciente en lugar de uno obsoleto. El DMA sigue capturando durante todo el proceso, por lo que la aplicación siempre ve datos nuevos tras una pausa. Esta es la política adecuada cuando el objetivo es mantener actualizado el flujo capturado: grabación de vídeo, transmisión en directo.Detener la captura ante un desbordamiento. Pase
fflush=Falseal constructor deCSIy el DMA dejará de llenar la FIFO cuando esté llena, dejando intactos los fotogramas encolados.snapshot()sigue devolviendo fotogramas en el orden de captura hasta que la aplicación los haya vaciado, momento tras el cual el DMA se reanuda. Esta es la política adecuada cuando el objetivo es preservar cada fotograma de una ráfaga corta: capturar un movimiento rápido para inspeccionarlo fotograma a fotograma en el código después.
Consulte csi.CSI.framebuffers() para ver la API completa.
4.15.5. Modo disparado¶
Una alternativa a los modos siempre activos anteriores es la captura disparada, donde el sensor emite un fotograma solo cuando snapshot() lo solicita. La cámara permanece inactiva entre capturas e inicia una nueva exposición cada vez que la aplicación la invoca.
El coste es el rendimiento: una captura disparada no puede solaparse con la anterior, por lo que la velocidad de fotogramas máxima alcanzable es la mitad de la velocidad normal del sensor. La ventaja es la sincronización de la exposición. La captura controla exactamente cuándo comienza la exposición, que es lo que una aplicación necesita cuando la exposición debe coincidir con un evento externo (un destello de estroboscopio, un sensor de posición de una cinta transportadora, un pulso en una línea GPIO) en lugar de caer donde resulte estar el fotograma de barrido del sensor de funcionamiento libre cuando la aplicación esté lista para leerlo.
El modo disparado es específico de cada sensor. En los sensores compatibles se habilita llamando a csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) y se deshabilita pasando False.