OpenCv with the webcam c930e logitech - c++

Here is the situation :
we have managed to get the camera to work with OpenCv 2.4.0 and Qt 5.0.2.
The camera is supposed to be able to record 1080p videos at 30 fps.
However we are stuck at 10 fps when recording in 1920x1080.
Here is the code we are using :
Capture cv::VideoCapture;
Capture.open(0);
Capture.set(CV_CAP_PROP_FRAME_WIDTH, 1920):
Capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
We have already tried to use this command (that we got from Capturing 1080p at 30fps from logitech c920 with openCV 2.4.3):
Capture.set(CV_CAP_PROP_FOURCC, 'M', 'J', 'P', 'G');
but without any success.
We believe the camera's stream can be captured in h264 (thanks to the internal conversion the camera does) or in mjpg.
Like we said we are a bit confused/lost.
Any suggestion is welcomed !
Thanks

The solution for your problem is already mentioned in the other question you linked to: You have to set the codec before you set the wanted resolution:
Capture cv::VideoCapture;
Capture.open(0);
Capture.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M','J','P','G'))
Capture.set(CV_CAP_PROP_FRAME_WIDTH, 1920):
Capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);

Related

OpenCv read / write video color difference

I am trying to simply open a video with openCV, process frames and write the processed frames into a new video file.
My problem is that even if I don't process frames at all (just opening a video, reading frames with VideoCapture and writing them with VideoWriter to a new file), the output file appears more "green" than the input.
The code to do that can be found in any openCV tutorial, nothing special.
I use openCV c++ 4.4.0 on Windows 10.
I use openCV with ffmpeg through opencv_videoio_ffmpeg440_64.dll
The input video is mp4.
I write the output as a .avi with huffyuv codec :
m_video_writer.reset(new cv::VideoWriter(m_save_video_path.toStdString(), cv::VideoWriter::fourcc('H', 'F', 'Y', 'U'), // lossless compression
m_model->getFps(), cv::Size(m_frame_size.width(), m_frame_size.height())));
I tried many other codecs and the problem remains.
The difference in pixels is small, not constant in value but always varying in the same way : blue channel is lower, red and green are higher.
Strange fact : when I open both input or output video with opencv, the matrix are actually exactly the same. So I guess the problem is in the reading ??
Here are the properties of each video file, as exported with Windows Media Playre (MPC-HC).
VS
What should I investigate ?
Thx !!
Full code here (copying the first 100 frames of my video):
VideoCapture original("C:/Users/axelle/Videos/original.MP4");
int frame_height = original.get(CAP_PROP_FRAME_HEIGHT);
int frame_width = original.get(CAP_PROP_FRAME_WIDTH);
int fps = original.get(CAP_PROP_FPS);
VideoWriter output("C:/Users/axelle/Videos/output.avi", VideoWriter::fourcc('H', 'F', 'Y', 'U'),
fps, cv::Size(frame_width, frame_height));
int count = 0;
while (count < 100)
{
count++;
Mat frame;
original >> frame;
if (frame.empty())
{
break;
}
//imshow("test", frame);
//waitKey(0);
output.write(frame);
}
original.release();
output.release();
Note: the difference in colors can be seen in the imshow already.
There is a bug in OpenCV VideoCapture when reading video frames using FFmpeg backend.
The bug results a "color shift" when H.264 video stream is marked as BT.709 color standard.
The subject is too important to leave it unanswered...
The important part of the post, is reproducing the problem, and proving the problem is real.
The solution I found is selecting GStreamer backend instead of FFmpeg backend.
The suggested solution has downsides (like the need to build OpenCV with GStreamer support).
Note:
The problem is reproducible using OpenCV 4.53 under Windows 10.
The problem is also reproducible under Ubuntu 18.04 (using OpenCV in Python).
The issue applies both "full range" and "limited range" of BT.709 color standard.
Building synthetic video pattern for reproducing the problem:
We can use FFmpeg command line tool create a synthetic video to be used as input.
The following command generates an MP4 video file with H.264 codec, and BT.709 color standard:
ffmpeg -y -f lavfi -src_range 1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -i testsrc=size=192x108:rate=1:duration=5 -vcodec libx264 -crf 17 -pix_fmt yuv444p -dst_range 1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -bsf:v h264_metadata=video_full_range_flag=1:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 bt709_full_range.mp4
The above command uses yuv444p pixel format (instead of yuv420p) for getting more pure colors.
The arguments -bsf:v h264_metadata=video_full_range_flag=1:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 use Bitstream Filter for marking the H.264 stream as "full range" BT.709.
Using MediaInfo tool, we can view the following color characteristics:
colour_range: Full
colour_primaries: BT.709
transfer_characteristics: BT.709
matrix_coefficients: BT.709
Capturing the video using OpenCV:
The following C++ code grabs the first frame, and save it to 1.png image file:
#include "opencv2/opencv.hpp"
void main()
{
cv::VideoCapture cap("bt709_full_range.mp4");
cv::Mat frame;
cap >> frame;
cv::imwrite("1.png", frame);
cap.release();
}
We may also use the following Python code:
import cv2
cap = cv2.VideoCapture('bt709_full_range.mp4')
_, frame = cap.read()
cv2.imwrite('1.png', frame)
cap.release()
Converting bt709_full_range.mp4 into images sequence using FFmpeg:
ffmpeg -i bt709_full_range.mp4 -pix_fmt rgb24 %03d.png
The file name of the first "extracted" frame is 001.png.
Comparing the results:
The left side is 1.png (result of OpenCV)
The right side is 001.png (result of FFmpeg command line tool)
As you can see, the colors are different.
The value of the red color pixels of OpenCV are RGB = [232, 0, 3].
The value of the red color pixels of FFmpeg are RGB = [254, 0, 0].
The original RGB value is probably [255, 0, 0] (value is 254 due to colors conversion).
As you can see, the OpenCV colors are wrong!
Solution - selecting GStreamer backend instead of FFmpeg backend:
The default OpenCV release excludes GStreamer support (at least in Windows).
You may use the following instruction for building OpenCV with GStreamer.
Here is a C++ code sample that uses GStreamer backend for grabbing the first frame:
void main()
{
cv::VideoCapture cap("filesrc location=bt709_full_range.mp4 ! decodebin ! videoconvert ! appsink", cv::CAP_GSTREAMER);
cv::Mat frame;
cap >> frame;
cv::imwrite("1g.png", frame);
cap.release();
}
Result:
The left side is 1g.png (result of OpenCV using GStreamer)
The right side is 001.png (result of FFmpeg command line tool)
The value of the red color pixels of OpenCV using GStreamer are RGB = [254, 0, 1]. (blue is 1 and not zero due to colors conversion).
Conclusions:
Using GStreamer backend (instead of FFmpeg) backend seems to solve the "color shifting" problem.
OpenCV users need to be aware of the color shifting problem.
Let's hope that OpenCV developers (or FFmpeg plugin developers) fix the problem.

c++ video capture using opencv

I try to capture video using Logitech C920 webcam with full hd resolution. It provides 30 fps with this resolution.
It works with windows camera application at 30 fps but whatever I try, I could not get this fps rate with opencv videoCapture.
Note: I use windows 10 and vs15.
I tried with different usb ports, opencv versions and codecs. Result is same, ~5 fps.
I measured fps ignoring first 10 frames. Here are my calculations: only read = "5.04fps" , read+imshow = "4.97fps" and read+imshow+write = "4.91fps"
void main()
{
mainStream.open(0);
mainStream.set(CV_CAP_PROP_FRAME_WIDTH, 1920);
mainStream.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
mainStream.set(CV_CAP_PROP_FPS, 30);
mainStream.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
mainWriter.open("outputnew2.avi", CV_FOURCC('M', 'J', 'P', 'G'), 30, cv::Size(frameW, frameH), true);
namedWindow("frame", 1);
while (true){
Mat frame;
mainStream >> frame;
imshow("frame", frame);
if (waitKey(5) == 27)
break;
mainWriter << frame;
}
mainStream.release();
mainWriter.release();
}
First of all:
The imshow method is very slow (in a pretty relative scope). Try to measure the real fps while you do not show the image and do not write the image to a file.
After that is done, you can check the real fps and determine which one of the two options (showing or writing) is slowing down your achieved fps rate.
Please post results of the achieved fps rate without showing or writing the image.
Edit:
Alright, you nearly always get 5 fps, which is kind of slow. Does the saved video (or images) match the resolution you wanted? Are they really 1920x1080
?
In that case, do the measured times differ from release and debug build?
Edit2:
If the same code works with other usb cams (and they produce more fps than the C920) my immediate suspect is the C920 itself (or its driver at least). Does it help if you deinstall the driver for it (eventually reboot) and install the newest driver again?
Another thing: Do the measured fps change if you do not request 30 but maybe like 20 fps?
Edit3:
It seems it was a driver issue (merged from comments). Reinstalling the driver is one method to adress this

Setting gstreamer capsfilter with OpenCV in c++

With the Microsoft LifeCam Cinema (on Ubuntu) in guvcview I get 30fps on 1280x720. In my OpenCV program, I only get 10fps (only queryframe and showimage, no image processing is done). I found out that it is a problem in gstreamer. A solution is to set a capsfilter in gstreamer, in terminal I can do it like this:
gst-launch v4l2src device=/dev/video0 !
'video/x-raw-yuv,width=1280,height=720,framerate=30/1' ! xvimagesink
This works! The question is:
How do I implement this in my c++/OpenCV program?
Or is it possible to set gstreamer to always use this capsfilter?
I already found this question Option 3, but I can't get it working with a webcam.
Unfortunately, there is no way to set the format (YUV) of the frames retrieved from the camera, but for the rest of the settings you could try using cvSetCaptureProperty():
cvSetCaptureProperty(capture, CV_CAP_PROP_FPS, 30);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 1280);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 720);
If setting the frame size doesn't work, I strongly suggest you read this post: Increasing camera capture resolution in OpenCV
My bad, I was setting my webcam to 1280x800, which forces it to use YUVY with max 10 fps. Setting it back to 1280x720 in my program gave me 30 fps

cv::VideoWriter yields unreadable video

I want to produce a video file out of a stream of RGB images flowing at 52fps. I found the opencv api pretty handy to use (cv::VideoWriter). The problem is that I can play the produced avi only with VLC; which plays the video but yells:
[0x28307b0] xcb_xv generic error: no available XVideo adaptor
Any other video player (on the same computer) is not able to read and play the video.
While recording everything looks ok: I get information about the output, about the size of the frame, the video codec, the fps, etc...no error.
Output #0, avi, to '01-23-12_15-24-51.avi':
Stream #0.0: Video: flv, yuv420p, 500x242, q=2-31, 7744 kb/s, 90k tbn, 52tbc
As OpenCv only supports avi as video container, the only thing I could change is the video codec, I tried (FOURCC code) FLV1, DIVX, DIV3 but none of them works correctly.
I would like to play this video with any video player on different computers. How can I make it work? is VideoWriter the right choice?
Any suggestion is very welcome.
Thanks.
If you have a video source for your images, it would be a good idea to use the same codec for output:
int videoType = (int)cap.get(CV_CAP_PROP_FORMAT);
VideoWriter vout;
vout.open(videofile + "_out.avi", videoType, 30, imgSize);
Or, you can try an older, simpler FOURCC. Or a Microsoft-specific, if you want to run it only on Windows.

Setting video capture properties no longer works in OpenCV 2.2?

Prior OpenCV 2.2, I was able to do
VideoCapture capture(0);
capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
in order to modify the frame size. But after when I compiled my application against OpenCV 2.2, setting the properties no longer works (the video is displayed correctly though). If I do a get of these values, 0 is returned. And if I look at the size of the captured frame, it is 160 x 120.
I searched online but most of the posts were about the problem in Linux whereas I am running Windows 7 64-bit. My webcam is a Logitech QuickCam Ultra Vision.
Is there anyone experiencing the same problem? Or no problem at all?
Thanks in advance!
This problem has been solved in OpenCV 2.3, even with my old Logitech QuickCam Ultra Vision webcam.
May be you should try with VideoInput, which is also supported by OpenCV, and included in OpenCV 2.0.3.
See an example at http://opencv.willowgarage.com/wiki/CameraCapture