Take webcam picture from shell with minimal delay

3

1

I am looking for a command-line tool that can take a picture from a webcam as fast as possible and write it to stdout. In addition, I would like to be able to specify settings like input format, resolution and output format.

My first try was ffmpeg:

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

However, this has two drawbacks:

  1. It takes about 3 seconds until the image is written to stdout, which seems to be due to the time the webcam needs to initialize.

  2. The picture taken this way is rather dark, probably the webcam needs to capture a view video frames to adjust brightness etc..

My next idea is to continuously capture video frames from the webcam (i.e. "keep the webcam active"), stream these video frames somewhere, and then grab single video frames and convert them to an image on demand. However, I do not know how to do this (and if there is a better way).

EDIT: I need a one-off command that writes the image to stdout, so I can use it in a http server to serve a http GET request. It needs to be quick, because taking the picture is blocking a mechanical process in a machine.

x-ray

Posted 2017-09-20T15:20:14.600

Reputation: 141

Answers

3

For my webcam, fswebcam takes a picture in less than half a second:

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

It takes a bit longer to write to stdout and then save it:

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

You can also take images every n seconds (--loop n), if this is what you need (you didn't explain why you want it as fast as possible, and if or how a loop can help).

You can brighten the image, or adjust contrast etc. with the controls shown with fswebcam --list-controls.

dirkt

Posted 2017-09-20T15:20:14.600

Reputation: 11 627

1For the "minimal delay" you can also send signal SIGUSR1 to fswebcam to have it capture immediately, when it is in timed loop mode. – meuh – 2017-09-20T20:00:02.087

1Thank you dirkt and @meuh. I updated my question to explain why I need this. I see now that my webcam is simply slow when getting the first picture. I will see if using fswebcam with the loop option in combination with SIGUSR1 helps. I found another solution (I'll post it here), but it is also not optimal (it lowers the cameras fps). – x-ray – 2017-09-20T22:31:38.437

Did you find a way to take pictures fast ? – razor – 2019-04-02T09:45:00.880

1

I found one possible solution myself, although it is not optimal, because on the Raspberry Pi where I want to implement this it reduces the FPS to half the value that the camera supports (and lower FPS = more possible delay until next video frame which can be extracted as picture).

I use ffmpeg to copy the video data from the hardware device at /dev/video0 to a v4l2-loopback device at /dev/video1. This way the camera stays active becaues ffmpeg is reading from it at /dev/video0, while I can use another instance of ffmpeg to extract pictures from /dev/video1.

To install v4l2-loopback on Raspbian GNU/Linux 9 (stretch):

  1. Install kernel headers: apt-get install raspberrypi-kernel-headers (Re: How to install kernel-headers)
  2. Install v4l2-loopback: apt-get install v4l2loopback-dkms (v4l2-loopback distributions)
  3. Add loopback device: modprobe v4l2loopback or with more devices modprobe v4l2loopback devices=2 (v4l2-loopback run)

To copy the video from /dev/video0 to /dev/video1:

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

My camera supports the formats mjpeg and yuyv422, but only a "raw" format can be copied to the loopback device, so I must use yuyv422. The camera supports up to 6 fps with yuyv422 and 1920x1080, but the Raspberry Pi 2 Model B only manages to copy about 3 fps to the loopback device.

Now I can use the command I already mentioned in the question to extract the pictures, as JPEG:

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

Or as 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

With these command reading from the loopback device, the images are not dark and it takes about 1.3 seconds (JPEG) or 1.1 seconds (bitmap) to send them to stdout.

x-ray

Posted 2017-09-20T15:20:14.600

Reputation: 141