13.3.1.3. Transmitindo quadros¶
Um script que captura quadros na câmera pode transmitir cada quadro de volta para o host pela USB. O padrão são duas chamadas na instância openmv.Camera: streaming() para ligar ou desligar a transmissão, e read_frame() para retirar o próximo quadro do canal.
13.3.1.3.1. Um laço mínimo de transmissão e exibição¶
O script do lado da câmera é o laço de snapshot habitual; o que há de novo é que o host abre a transmissão e lê o resultado de volta:
from openmv import Camera
script = """
import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
while True:
csi0.snapshot()
"""
with Camera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(script)
cam.streaming(True)
while True:
if frame := cam.read_frame():
print(f"{frame['width']}x{frame['height']}, "
f"{frame['raw_size']} bytes")
A câmera captura quadros continuamente; o host retira cada um do buffer de transmissão à medida que chega. A câmera sobrescreve o buffer de transmissão a cada novo snapshot, de modo que um host que faz polling mais devagar do que a câmera captura vai descartar quadros silenciosamente – esse é o comportamento correto para casos de uso no estilo de visualização.
13.3.1.3.2. O dicionário do quadro¶
read_frame() retorna None (nenhum quadro aguardando) ou um dict com cinco entradas:
Chave |
Significado |
|---|---|
|
Largura do quadro em pixels. |
|
Altura do quadro em pixels. |
|
Identificador do formato de pixel que a câmera declarou (um inteiro vindo das constantes |
|
Para formatos compactados (JPEG, PNG), o tamanho da imagem compactada em bytes. Não utilizado para formatos não compactados. |
|
O quadro como um buffer |
|
Bytes que a câmera enviou pela USB antes da decodificação. Útil para o cálculo real de throughput. |
O pacote converte o formato nativo da câmera (GRAYSCALE, RGB565, JPEG) para RGB888 antes de retornar, de modo que o host nunca precisa lidar sozinho com o RGB565 empacotado em bits nem com o caminho de descompressão de JPEG. Quadros em escala de cinza retornam com o valor de luminância replicado nos três canais.
O buffer data é organizado linha por linha, de cima para baixo; passá-lo diretamente para uma biblioteca de exibição ou salvá-lo como um arquivo RGB bruto funciona sem qualquer reorganização adicional.
13.3.1.3.3. Modo de transmissão bruta (raw)¶
Por padrão, a câmera comprime em JPEG cada quadro capturado antes de colocá-lo no canal de transmissão, e read_frame() descomprime no host. Em câmeras sem suporte a JPEG por hardware, a compressão por software é o passo mais lento do laço. Passar raw=True o ignora:
cam.streaming(True, raw=True, resolution=(320, 240))
A câmera então envia o buffer de pixels sem compressão. Quadros não compactados são muito maiores que seus equivalentes em JPEG, então a câmera reduz a escala de cada quadro capturado para caber no canal de transmissão antes de enviá-lo; o argumento resolution=(width, height) define esse alvo. O host ainda recebe RGB888 no campo data – o pacote converte a partir de qualquer formato de pixel que a câmera tenha informado em format.
13.3.1.3.4. Deixando os eventos conduzirem o laço¶
Um laço de polling que chama read_frame() mais rápido do que a câmera produz quadros passa a maior parte do tempo recebendo None de volta. Quando o host também tem outras tarefas a fazer (uma interface a atualizar, outros canais para consultar), read_status() é a verificação mais barata: ela retorna um dicionário que mapeia cada nome de canal registrado para um booleano de “dados prontos”:
while True:
status = cam.read_status()
if status.get('stream'):
frame = cam.read_frame()
# ... process the frame ...
if status.get('stdout'):
text = cam.read_stdout()
print(text, end='')
if status.get('my_channel'):
data = cam.channel_read('my_channel')
# ... process custom-channel data ...
Esse é o formato de laço que o próprio visualizador de CLI utiliza.
13.3.1.3.5. Interrompendo a transmissão¶
Chame streaming() com enable=False para parar. A câmera continua executando seu script, mas não preenche mais o buffer de transmissão; read_frame() simplesmente retorna None a partir desse ponto. Chamar stop() faz o mesmo de forma implícita ao interromper o script.