OpenCV VideoCapture() doesn't work

OpenCV 4.5 - Ubuntu - Jetson Nano 2GB - C++

Hello I have a problem with getting video from my webcam (connected by USB to JetsonNano) by OpenCV

Here’s my code:

 // cv::VideoCapture cap( ... );
    cv::Mat frame;
    if (!cap.isOpened())  // if not success, exit program
    {
        cout << "Cannot open the video cam" << endl;
        return -1;
    }
    cv::namedWindow("test", cv::WINDOW_AUTOSIZE);
    while(true)
    {
        try
        {
            cap >> frame;
            cv::imshow("test", frame);
        }
        catch(const std::exception& e)
        {
            std::cerr << e.what() << '\n';
        }
        

    }

1 | cv::VideoCapture cap(0) gives me:

[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (935) open OpenCV | GStreamer warning: Cannot query video position: status=0, value=-1, duration=-1

2 | cv::VideoCapture cap("/dev/video0") gives me:

[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (1761) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module source reported: Could not read from resource.
[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (888) open OpenCV | GStreamer warning: unable to start pipeline
[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (480) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
Cannot open the video cam

3 | When I try to open camera by command, this one works:
$ gst-launch-1.0 v4l2src device=\"/dev/video0\" ! xvimagesink
so I gave it a try:
cv::VideoCapture cap("v4l2src device=\"/dev/video0\" ! xvimagesink") it gives me:

[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (803) open OpenCV | GStreamer warning: cannot find appsink in manual pipeline
[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (480) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
Cannot open the video cam

If I gave other sinks : autosink or appsink, it’s also doesn’t work.

4 | I tried the solution from that link

cv::VideoCapture cap("v4l2src device=/dev/video0 ! video/x-raw,width=1920,height=1080,format=UYVY,framerate=30/1 ! videoconvert ! video/x-raw,format=BGR ! appsink") and it’s gives me :

[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (1761) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module v4l2src0 reported: Internal data stream error.
[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (888) open OpenCV | GStreamer warning: unable to start pipeline
[ WARN:0] global /home/legion/opencv/modules/videoio/src/cap_gstreamer.cpp (480) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
[ERROR:0] global /home/legion/opencv/modules/videoio/src/cap.cpp (142) open VIDEOIO(CV_IMAGES): raised OpenCV exception:

OpenCV(4.5.0) /home/legion/opencv/modules/videoio/src/cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): v4l2src device=/dev/video0 ! video/x-raw,width=1920,height=1080,format=UYVY,framerate=30/1 ! videoconvert ! video/x-raw,format=BGR ! appsink in function 'icvExtractPattern'

Someone knows what’s going on and how to fix it?

Thanks ~~

May you check your camera first:

v4l2-ctl --list-devices

And may try to put cv2.waitKey(1) in your loop.

Yeah, my camera show on the list, and adding waitKey() do not solve my issue :<

It would help to know what formats, resolution and framerate your camera provides for better advice.
You would get these with (v4l2-ctl is provided by apt package v4l-utils):

v4l2-ctl -d0 --list-formats-ext

or you can get the working case with verbose mode of gst-launch:

gst-launch-1.0 -v v4l2src device=/dev/video0 ! xvimagesink

From opencv video capture, you may specify the wanted backend.
If your camera/driver provides a format that opencvio can handle from V4L API to provide BGR, you may use:

cv::VideoCapture cap(0, cv::CAP_V4L);

Using gstreamer backend, you would try:

cv::VideoCapture cap("v4l2src device=/dev/video0 ! videoconvert ! video/x-raw, format=BGR ! appsink", cv::CAP_GSTREAMER);

As mentionned by @Ayuchan, for using imshow you would have to add waitKey in the loop, so that opencv drawing thread can be scheduled. Note however that imshow is CPU only and not so efficient on Jetsons with high resolution*framerate, so better start with a low resolution.

2 Likes

Here’s my camera formats :

VIDIOC_ENUM_FMT
Index       : 0
Type        : Video Capture
Pixel Format: 'MJPG' (compressed)
Name        : Motion-JPEG
	Size: Discrete 1280x720
		Interval: Discrete 0.033s (30.000 fps)
	Size: Discrete 640x480
		Interval: Discrete 0.033s (30.000 fps)

Index       : 1
Type        : Video Capture
Pixel Format: 'YUYV'
Name        : YUYV 4:2:2
	Size: Discrete 1280x720
		Interval: Discrete 0.100s (10.000 fps)
	Size: Discrete 640x480
		Interval: Discrete 0.040s (25.000 fps)

This solved the issue for me!

cv::VideoCapture cap(0, cv::CAP_V4L);

Thank you!
Can you tell me why it’s so? So I could solve similar issues in the future?

Whish you plenty of candy @Honey_Patouceul !

If you don’t specify backend for videocapture, opencv videoio may try itself but may be wrong.
From the logs you’ve posted, I think it has tried CAP_IMAGES, but this may be very slow on Jetson.

Specifying V4L backend improves.

With gstreamer backend, you may use your sensor in RAW mode with:

cv::VideoCapture cap("v4l2src device=/dev/video0 ! video/x-raw, format=YUY2 ! videoconvert ! video/x-raw, format=BGR ! appsink", cv::CAP_GSTREAMER);

You may also use MJPG format. It would require less USB bandwidth, but this may take more resources:

cv::VideoCapture cap("v4l2src device=/dev/video0 ! image/jpeg ! jpegparse ! nvv4l2decoder mjpeg=1 ! nvvidconv ! video/x-raw, format=BGRx ! videoconvert ! video/x-raw, format=BGR ! appsink", cv::CAP_GSTREAMER);
1 Like