10.2. Devolver uma captura de imagem¶
Um endpoint de estado é útil, mas a razão pela qual a câmara existe é a objetiva. Adicione um endpoint que devolve o JPEG do que quer que o sensor esteja a ver neste momento.
import csi
from microdot import Response
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
@app.get('/snapshot.jpg')
async def snapshot(request):
img = csi0.snapshot().compress(quality=85)
return Response(
body=img.bytearray(),
headers={'Content-Type': 'image/jpeg'},
)
Aceda a http://<cam-ip>/snapshot.jpg a partir de um browser e um JPEG da vista atual preenche o separador. Atualize e obterá um novo.
10.2.1. O objeto Response¶
Um manipulador que devolve um dicionário deixa o microdot tratar do resto. Os bytes JPEG precisam do formato longo: um microdot.Response construído explicitamente. O argumento body aceita qualquer valor semelhante a bytes – o buffer image.Image da câmara é exposto via bytearray(), pelo que o mesmo buffer em que o sensor escreveu vai diretamente para o socket.
Content-Type: image/jpeg é o que diz ao browser para renderizar o corpo como uma imagem. Sem isso, o browser tentaria mostrar os bytes JPEG como texto e veria um ecrã cheio de caracteres sem sentido.
image.Image.compress() executa a codificação JPEG no buffer de imagem existente no lugar e devolve a mesma imagem (agora em formato JPEG) para que os seus bytes possam ser enviados tal como estão. quality=85 é o valor predefinido habitual – suficientemente alto para que a imagem seja nítida, suficientemente baixo para que o ficheiro passe por uma ligação lenta.
10.2.2. A captura bloqueia o ciclo¶
csi.CSI.snapshot() aguarda que o sensor termine a exposição e a transferência DMA de um fotograma antes de retornar. Dentro de um manipulador assíncrono, isso significa que o ciclo de eventos fica parado durante a duração da exposição – dez, vinte, cinquenta milissegundos dependendo da iluminação. Com um cliente a pedir uma rota de cada vez, isto é invisível; com múltiplos clientes, ou uma corrotina de captura a correr em paralelo, bloquearia tudo o resto.
Existe uma variante não bloqueante de snapshot() para o caso de múltiplas corrotinas (blocking=False devolve o próximo fotograma pronto ou None). Para uma captura por pedido, a chamada bloqueante predefinida é adequada.
O proprietário pode agora aceder a um URL e obter um fotograma atualizado.