OpenCV + Linux + badly supported camera = wrong pixel format - opencv

I'm trying to grab frames from a web cam using OpenCV. I also tried 'cheese'. Both give me a pretty weird picture: distorted, wrong colors. Using mplayer I was able to figure out the correct codec "yuy2". Even mplayer sometimes would select the wrong codec ("yuv"), which makes it look just like using OpenCV / cheese to capture an image.
Can I somehow tell OpenCV which codec to use?
Thanks!

in the latest version of opencv you can set the capture format form the camera with the same fourcc style code you would use for video. See http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture
it may still take a bit of trial-and-error, terms like YUV, YUYV, YUY2 are used a bit loosely by the camera maker, the driver maker, the operating system, the directshow layer and opencv !

OpenCV automatically selects the first available capture backend (see here). It can be that it is not using V4L2 automatically.
Also set both -D WITH_V4L=ON and -D WITH_LIBV4L=ON if building from source.
In order to set the pixel format to be used set the CAP_PROP_FOURCC property of the capture:
capture = cv2.VideoCapture(self.cam_id, cv2.CAP_V4L2)
scapture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
width = 1920
height = 1080
capture.set(cv2.CAP_PROP_FRAME_WIDTH, width)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, height)

Related

V4L2 / Beaglebone Black / Radiumboard HD Camera / Controls

I am trying to take snapshots with a Beaglebone Black paired with a RadiumBoards HD Camera Cape. I've noticed that using the built-in application (like cheese) will auto-adjust exposure. However, if I write custom C/C++ code on top of the v4l2 libraries to take a snapshot, the exposure is off (too bright or too dark, rarely correct). I would like to be able to either manually adjust exposure or allow the camera to auto-adjust. How can I do this in C/C++ source code?
Resources online indicate that I can change exposure settings through v4l2-ctl. This doesn't work for me. When I issue v4l2-ctl -l to list available controls, I get none.
The driver is reported as cssp_camera version 3.8.13.
I am not really sure if this is the issue, but you may try to specify the device that you want to control.
Assuming that is /dev/video0, you may do that by:
$ v4l2-ctl -d /dev/video0 -l
I am also assuming that you have granted permissions to the device.
Hope that I have helped.
Cheers

How to find the frame type(i frame,p frame, b frame)?

i am working in opencv 2.4.7 , is there any function to determine whether the captured frame is I frame, P frame , B frame?
if not which libs i must use to identify the frames
Caveat - I don't use opencv.
There doesn't seem to be a well-documented library function for it, but would either of these at least suggest a route?
How to get number of I/P/B frames of a video file?
OpenCV. How to identify i-frames only for a video file encoded in MPEG format

cvCaptureFromCAM() / cvQueryFrame(): disable automatic image correction?

I'm using the two OpenCV functions mentioned above to retrieve frames from my webcam. No additional properties are set, just running with default parameters.
While reading frames in a loop I can see that the image changes, brightness and contrast seem to be adjusted automatically. It definitely seems to be a operation of OpenCV because the image captured by the camera is not changed and lit constantly.
So how can I disable this automated correction? I could not find a property that seems to be able to do that job.
You should try to play around with these three parameters:
CV_CAP_PROP_BRIGHTNESS Brightness of the image (only for cameras)
CV_CAP_PROP_CONTRAST Contrast of the image (only for cameras)
CV_CAP_PROP_SATURATION Saturation of the image (only for cameras)
Try to set them all to 50. Also (if it won't help) try to change another camera capture parameters from documentation.
To answer that for my own: OpenCV is buggy or outdated here.
it seems to be impossible to get images in native resolution of the camera, they're always 640x480; also forcing it to an other value by setting width and height properties does not change anything
it seems to be impossible to disable the automatic image correction, the properties mentioned above seem not to work
the brightness/contrast properties doesn't seem to work as well - or at least I could not find any good values for it or the automatic image correction always overrides them
To sum it up: I'd not recommend to use OpenCV for some more enhanced image capturing.

opencv VideoCapture.set greyscale?

I would avoid to convert each frame taken by video camera with cvtColor(frame, image, CV_RGB2GRAY);
Is there anyway to set VideoCapture to get directly in greyscale?
Example:
VideoCapture cap(0);
cap.set(CV_CAP_PROP_FRAME_WIDTH,420);
cap.set(CV_CAP_PROP_FRAME_HEIGHT,340);
cap.set(CV_CAP_GREYSCALE,1); //< ???
If your camera supports YUV420 then you could just take the Y channel:
http://en.wikipedia.org/wiki/YUV
How to do that is well explained here:
Access to each separate channel in OpenCV
Warning: the Y channel might not be the first Mat you get with split() so you should do an imshow() of all of them separately and chose the one that looks like the "real" gray image. The others will just be waaaay out of contrast so it'll be obvious. For me it was the second mat.
Usually, any camera should be able to do YUV420 since sending frames directly in RGB is slower so YUV is pretty much used by nearly every camera. :)
This is impossible. Here's list of all codes:
CV_CAP_PROP_POS_MSEC - position in milliseconds from the file beginning
CV_CAP_PROP_POS_FRAMES - position in frames (only for video files)
CV_CAP_PROP_POS_AVI_RATIO - position in relative units (0 - start of the file, 1 - end of the file)
CV_CAP_PROP_FRAME_WIDTH - width of frames in the video stream (only for cameras)
CV_CAP_PROP_FRAME_HEIGHT - height of frames in the video stream (only for cameras)
CV_CAP_PROP_FPS - frame rate (only for cameras)
CV_CAP_PROP_FOURCC - 4-character code of codec (only for cameras).
Or (if it's possible, using some utilities) you can setup your camera to show only grayscale image.
To convert colored image to grayscale you have to call cvtColor with code CV_BGR2GRAY. This shouldn't take much time.
This is not possible if you use v4l (the default cv capture method on desktop Linux). The CV_CAP_PROP_FORMAT exists but is simply ignored. You have to convert the images to grayscale manually. If your device supports it, you may want to reimplement cap_v4l.cpp in order to interface v4l to set the format to grayscale.
On Android this is possible with the following native code (for the 0th device):
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/highgui/highgui_c.h>
cv::VideoCapture camera(0);
camera->open(0);
cv::Mat dest(480,640,CV_8UC1);
if(camera->grab())
camera->retrieve(dest,CV_CAP_ANDROID_GREY_FRAME);
Here, passing CV_CAP_ANDROID_GREY_FRAME to the channel parameter of cv::VideoCapture::retrieve(cv::Mat,int) causes the YUV NV21 (a.k.a yuv420sp) image to be color converted to grayscale. This is just a mapping of the Y channel to the grayscale image, which does not involve any actual conversion or memcpy, therefore very fast. You can check this behavior in https://github.com/Itseez/opencv/blob/master/modules/videoio/src/cap_android.cpp#L407 and the "color conversion" in https://github.com/Itseez/opencv/blob/master/modules/videoio/src/cap_android.cpp#L511. I agree that this behavior is not documented at all and is very awkward, but it saved a lot of CPU time for me.
If you use <raspicam/raspicam_cv.h>]1 you can do it.
you need to open a device like this:
RaspiCam_Cv m_rapiCamera;
Set any parametters that you need using below code:
m_rapiCamera.set(CV_CAP_PROP_FORMAT, CV_8UC1);
And then open the stream like below:
m_rapiCamera.open();
And you will get only one channel.
Good luck!

cv::VideoCapture in android native code

I am using a cv::VideoCapture in native code and I am having issues with it :
In android java code, Videocapture gives a Yuv420 frame, in native code it's a BGR one. Since I need a gray image, having a Yuv image would be better (I read there was no cost in converting Yuv to GRAY).
Here are my questions :
A im using a Asus TF201, acquiring a frame takes about 26ms which is a lot... as the standard android camera API gives Yuv does the native version of VideoCapture performs a conversion ? (which would explain the time cost)
Is it possible to change the format with CV_CAP_PROP_FORMAT ? Whenever I try mycapture.get(CV_CAP_PROP_FORMAT) my app crashes...
EDIT : Andrey Kamaev answered this one. I have to use grab/retrieve methods adding a argument in the second one :
capture.retrieve(frame, CV_CAP_ANDROID_GRAY_FRAME);
Thanks
Look at the OpenCV samples for Android. Most of them are getting gray image from a VideoCapture object:
capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
Internally this gray image is "converted" from yuv420 frame in the most efficient way - even without extra copying.

Resources