Tire foto da webcam do shell com o mínimo de atraso

2

Estou procurando uma ferramenta de linha de comando que possa tirar uma foto de uma webcam o mais rápido possível e gravá-la no stdout. Além disso, gostaria de poder especificar configurações como formato de entrada, resolução e formato de saída.

Minha primeira tentativa foi ffmpeg:

ffmpeg -f video4linux2 -video_size 1920x1080 -input_format yuyv422 -i /dev/video0 -f image2 -frames:v 1 -qscale:v 2 pipe:1

No entanto, isso tem dois inconvenientes:

  1. Demora cerca de 3 segundos até a imagem ser gravada em stdout, o que parece ser devido ao tempo que a webcam precisa para inicializar.

  2. A foto tirada dessa maneira é um pouco escura, provavelmente a webcam precisa capturar quadros de vídeo para ajustar o brilho etc.

Minha próxima idéia é capturar continuamente quadros de vídeo da webcam (ou seja, "manter a webcam ativa"), transmitir esses quadros de vídeo em algum lugar e, em seguida, capturar quadros de vídeo e convertê-los em uma imagem sob demanda. No entanto, eu não sei como fazer isso (e se há uma maneira melhor).

EDIT: Eu preciso de um comando único que grava a imagem para stdout, para que eu possa usá-lo em um servidor http para servir uma solicitação HTTP GET. Ele precisa ser rápido, porque tirar a foto está bloqueando um processo mecânico em uma máquina.

    
por x-ray 20.09.2017 / 17:20

2 respostas

3

Para minha webcam, fswebcam tira uma foto em menos de meio segundo:

$ time fswebcam test1.jpg
...
real    0m0.491s
user    0m0.024s
sys     0m0.000s

Demora um pouco mais para gravar no stdout e depois salvá-lo:

$ time fswebcam - > test2.jpg
...
real    0m0.538s
user    0m0.029s
sys     0m0.000s

Você também pode capturar imagens a cada n segundos ( --loop n ), se é isso que você precisa (você não explicou por que você quer isso tão rápido quanto possível, e se ou como um loop pode ajudar).

Você pode clarear a imagem ou ajustar o contraste, etc. com os controles mostrados com fswebcam --list-controls .

    
por 20.09.2017 / 18:29
1

Eu mesmo encontrei uma solução possível, embora não seja a melhor, porque no Raspberry Pi onde eu quero implementar isso reduz o FPS à metade do valor que a câmera suporta (e menor FPS = mais atraso possível até o próximo vídeo quadro que pode ser extraído como imagem).

Eu uso o ffmpeg para copiar os dados de vídeo do dispositivo de hardware em / dev / video0 para um dispositivo v4l2-loopback em / dev / video1. Desta forma, a câmera permanece ativa porque o ffmpeg está lendo a partir dela em / dev / video0, enquanto eu posso usar outra instância do ffmpeg para extrair imagens de / dev / video1.

Para instalar o v4l2-loopback no Raspbian GNU / Linux 9 (extensão):

  1. Instale os cabeçalhos do kernel: apt-get install raspberrypi-kernel-headers ( Re: Como instalar cabeçalhos de kernel )
  2. Instale o v4l2-loopback: apt-get install v4l2loopback-dkms ( distribuições do v4l2-loopback )
  3. Adicionar dispositivo de loopback: modprobe v4l2loopback ou com mais dispositivos modprobe v4l2loopback devices=2 ( execução de loopback v4l2 )

Para copiar o vídeo de / dev / video0 para / dev / video1:

 ffmpeg -f video4linux2 -video_size 1920x1080 -input_format yuyv422 -i /dev/video0 -codec copy -f video4linux2 /dev/video1

Minha câmera suporta os formatos mjpeg e yuyv422, mas somente um formato "raw" pode ser copiado para o dispositivo de loopback, portanto, devo usar o yuyv422. A câmera suporta até 6 qps com yuyv422 e 1920x1080, mas o Raspberry Pi 2 Modelo B só consegue copiar cerca de 3 qps para o dispositivo de loopback.

Agora posso usar o comando que já mencionei na pergunta para extrair as imagens, como JPEG:

ffmpeg -f video4linux2 -video_size 1920x1080 -input_format yuyv422 -i /dev/video1 -f image2 -frames:v 1 -qscale:v 2 pipe:1

Ou como bitmap:

 ffmpeg -f video4linux2 -video_size 1920x1080 -input_format yuyv422 -i /dev/video1 -c:v bmp -f image2 -pix_fmt bgr24 -frames:v 1 pipe:1

Com estes comandos a partir do dispositivo de loopback, as imagens não são escuras e demora cerca de 1,3 segundos (JPEG) ou 1,1 segundos (bitmap) para as enviar para a stdout.

    
por 21.09.2017 / 00:26