13.3.1.3. Transmissão de fotogramas em tempo real¶
Um script que captura fotogramas na câmara pode transmitir cada fotograma de volta ao anfitrião via USB. O padrão consiste em duas chamadas à instância openmv.Camera: streaming() para ativar ou desativar a transmissão, e read_frame() para extrair o próximo fotograma do canal.
13.3.1.3.1. Um ciclo mínimo de transmissão e visualização¶
O script do lado da câmara é o ciclo de captura habitual; o que é novo é que o anfitrião 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âmara captura fotogramas continuamente; o anfitrião extrai cada um do buffer de transmissão assim que chega. A câmara sobrescreve o buffer de transmissão a cada nova captura de imagem, pelo que um anfitrião que faça polling mais lentamente do que a câmara captura irá perder fotogramas silenciosamente – esse é o comportamento correto para casos de uso de visualizador.
13.3.1.3.2. O dicionário do fotograma¶
read_frame() devolve None (nenhum fotograma em espera) ou um dict com cinco entradas:
Chave |
Significado |
|---|---|
|
Largura do fotograma em pixels. |
|
Altura do fotograma em pixels. |
|
Identificador de formato de pixel declarado pela câmara (um inteiro das constantes |
|
Para formatos comprimidos (JPEG, PNG), o tamanho da imagem comprimida em bytes. Não utilizado para formatos não comprimidos. |
|
O fotograma como buffer |
|
Bytes enviados pela câmara via USB antes da descodificação. Útil para calcular o débito real. |
O pacote converte o formato nativo da câmara (GRAYSCALE, RGB565, JPEG) para RGB888 antes de devolver, pelo que o anfitrião nunca tem de lidar com o RGB565 em bit-packed ou com a descompressão JPEG. Os fotogramas em escala de cinzentos são devolvidos com o valor de luminância replicado nos três canais.
O buffer data está disposto linha por linha, de cima para baixo; alimentá-lo diretamente a uma biblioteca de visualização ou guardá-lo como ficheiro RGB em bruto funciona sem qualquer reorganização adicional.
13.3.1.3.3. Modo de transmissão em bruto¶
Por defeito, a câmara comprime com JPEG cada fotograma capturado antes de o colocar no canal de transmissão, e read_frame() descomprime no anfitrião. Em câmaras sem suporte de hardware JPEG, a compressão por software é o passo mais lento do ciclo. Passar raw=True ignora essa etapa:
cam.streaming(True, raw=True, resolution=(320, 240))
A câmara envia então o buffer de pixels sem compressão. Os fotogramas não comprimidos são muito maiores do que os seus equivalentes JPEG, pelo que a câmara redimensiona cada fotograma capturado para caber no canal de transmissão antes de o enviar; o argumento resolution=(width, height) define essa resolução alvo. O anfitrião continua a receber RGB888 no campo data – o pacote converte a partir do formato de pixel que a câmara indicou em format.
13.3.1.3.4. Deixar os eventos conduzir o ciclo¶
Um ciclo de polling que chama read_frame() mais rápido do que a câmara produz fotogramas passa a maior parte do tempo a obter None como resposta. Quando o anfitrião tem também outro trabalho a fazer (uma interface a atualizar, outros canais a monitorizar), read_status() é a verificação mais económica: devolve um dicionário que mapeia cada nome de canal registado 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 ...
Esta é a forma de ciclo que o próprio visualizador da linha de comandos utiliza.
13.3.1.3.5. Parar a transmissão¶
Chame streaming() com enable=False para parar. A câmara continua a executar o seu script mas deixa de preencher o buffer de transmissão; read_frame() passa a devolver apenas None a partir desse momento. Chamar stop() faz o mesmo implicitamente ao interromper o script.