OpenCV changing VideoCapture resolution causes colour issues and glitches - python

I want to capture 1920x1080 video from my camera but I've run into two issues
When I initialize a VideoCapture, it changes the width/height to 640/480
When I try to change the width/height in cv2, the image becomes messed up
Images
When setting 1920x1080 in cv2, the image becomes blue and has a glitchy bar at the bottom
cap = cv2.VideoCapture('/dev/video0')
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
Here's what's happening according to v4l2-ctl. The blue image doesn't seem to be a result of a pixelformat change (eg. RGB to BGR)
And finally, here's an example of an image being captured at 640x480 that has the correct colouring. The only difference in the code is that width/height is not set in cv2

Problem:
Actually the camera you are using has 2 mode:
640x480
1920x1080
One is for main stream, one is for sub stream. I also met this problem couple of times and here is the possible reasons why it doesn't work.
Note: I assume you tried different ways to run on full resolution(1920x1080) such as cv2.VideoCapture(0) , cv2.VideoCapture(-1) , cv2.VideoCapture(1) ...
Possible reasons
First reason could be that the camera doesn't support the resolution you desire but in your case we see that it supports 1920x1080 resolution. So this can not be the reason for your isssue.
Second reason which is general reason is that opencv backend doesn't support your camera driver. Since you are using VideoCaptureProperties of opencv, Documentation says:
Reading / writing properties involves many layers. Some unexpected result might happens along this chain. Effective behaviour depends from device hardware, driver and API Backend.
What you can do:
In this case, if you really need to reach that resolution and make compatible with opencv, you should use the SDK of your camera(if it has).

Related

Setting camera width / height (field of view) opencv while streaming images works with Windows but not Linux

I am writing a python app that utilizes opencv to display an image using pyqt. I wrote the application on windows originally using DirectShow camera API preference. When the camera was displayed I could set the width/height of the camera easily using the opencv API cap.set(3, X) cap.set(4, y). I need to shrink these values in order to boost the FPS of my camera I am using.
However, I just moved my code over to Ubuntu and everything works exactly the same except as soon as I change the FOV values, the camera freezes and I no longer can get frames. I am able to change other camera features like brightness, contrast, etc, but for some reason the width/height is a problem.
I tried different API preferences: CAP_V4L2, CAP_V4L, CAP_GSTREAMER. None of these allowed me to edit it on the fly while streaming images.
Any ideas why the change?

How to alter resolution to portrait mode values with opencv-python?

I want to change the video resolution from landscape to portrait mode for output from my inbuilt webcam on the laptop (cv2.VideoCapture(0)). I tried rescaling the frames to get it to work, it does go to portrait mode ( height bigger than width) but the video is skewed/stretched. Is there a way around this ? please help. I am using opencv with python.
Welcome to Stackoverflow. What you want to achieve depends on the webcam you use. The Resolution you want need to be supported by your cam. this small tutorial explains it very good.
If your camera does not support the Resolution you want, you have two possibilites:
You Crop the Image to the Resolution you want.
If your max resolution does not allow your resolution you can crop it to the biggest resultion possible with your wanted ratio and after that upscale it.
Careful with upscaling. You have different interpolation methods available.

Opencv read image when camera is refocus (still blur)

I have a python program which uses opencv VideoCapture to capture webcam image (in my case logitech c922). It has autofocus feature which is great but I don't know when the refocus is done and that makes the image that I capture blurred (not focus yet)
Is there any way to know when the camera already focusses?
Besides interacting with camera hardware that #ZdaR has mentioned, you can determine whether the image is sharp or not every frame. If the image is sharp, most probably the camera is in focus.
There are some great answers here on determining the sharpness of an image.
In the case of having a depth-of-view (the object is sharp while the background is blurry), you can set the threshold on some of the sharpest pixels only (i.e. sharpest 20% pixels). Since a out-of-focus or focusing image should be blurry altogether.
You can set the focus manually so that the camera is focused already when you need to use the camera.
Here is the code:
cap.set(3, 1280) # set the resolution
cap.set(4, 720)
cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)

Is there a way to adjust shutter speed or exposure time of a webcam using Python and OpenCV

In my robotic vision project, I need to detect a marker of a moving object but motion causes blurring effect in the image. Deconvolution methods are quite slow. So I was thinking to use a higher fps camera. Someone said I don't need higher fps, instead I need shorter exposure time.
OpenCV's Python Interface cv2 provides a method to change the settings of camera but it does not include "Exposure Time" or "Shutter Speed" settings. I'm also afraid that webcams don't even support this kind of settings.
Any other thoughts about:
Eliminating blurring effect using camera setting?
OR
Restoration of Image with real-time performance?
OR
Any suggestion about a low cost camera for real-time robotic applications?
There is a method available to change properties of VideoCapture object in OpenCV which can be used to set exposure of input image.
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_EXPOSURE, 40)
However this parameter is not supported by all cameras. Each camera type offers a different interface to set its parameters. There are many branches in OpenCV code to support as many of them, but of course not all the possibilities are covered.
Same is the case with my camera. So I had to find a different solution. That is using v4l2_ctl utility from command line terminal.
v4l2-ctl -d /dev/video0 -c exposure_absolute=40
But this retains its value for current video session only. That means you have to start video preview first and then set this property As soon as VideoCapture is released, the exposure value is restored to default.
I wanted to control exposure within my python script, so I used subprocess module to run linux bash command. e.g.
import subprocess
subprocess.check_call("v4l2-ctl -d /dev/video0 -c exposure_absolute=40",shell=True)
For instance
I was trying with a c920 for a while whithout success, but sometimes worked, other not using this:
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_EXPOSURE, -4)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) # after not change the exposure
But finally I realized that I was setting the width and height just after, and so I change the order and now is working fine!! DonĀ“t blow your mind trying to disable the CAP_PROP_AUTO_EXPOSURE flag!! Its not necessary(at least with c920 on windows)!!
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) # before works fine
cap.set(cv2.CAP_PROP_EXPOSURE, -4)
By the way, the range of exposure in C920 is from -2 to -11!!(on windows 10)
Thanks a lot

OpenCV (via python) on Linux: Set frame width/height?

I'm using openCV via python on linux (ubuntu 12.04), and I have a logitech c920 from which I'd like to grab images. Cheese is able to grab frames up to really high resolutions, but whenever I try to use openCV, I only get 640x480 images. I have tried:
import cv
cam = cv.CaptureFromCAM(-1)
cv.SetCaptureProperty(cam,cv.CV_CAP_PROP_FRAME_WIDTH,1920)
cv.SetCaptureProperty(cam,cv.CV_CAP_PROP_FRAME_WIDTH,1080)
but this yields output of "0" after each of the last two lines, and when I subsequently grab a frame via:
image = cv.QueryFrame(cam)
The resulting image is still 640x480.
I've tried installing what seemed to be related tools via (outside of python):
sudo apt-get install libv4l-dev v4l-utils qv4l2 v4l2ucp
and I can indeed apparently manipulate the camera's settings (again, outside of python) via:
v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=1
v4l2-ctl --set-parm=30
and observe that:
v4l2-ctl -V
indeed suggests that something has been changed:
Format Video Capture:
Width/Height : 1920/1080
Pixel Format : 'H264'
Field : None
Bytes per Line : 3840
Size Image : 4147200
Colorspace : sRGB
But when I pop into the python shell, the above code behaves exactly the same as before (printing zeros when trying to set the properties and obtaining an image that is 640x480).
Being able to bump up the resolution of the capture is pretty mission critical for me, so I'd greatly appreciate any pointers anyone can provide.
From the docs,
The function cvSetCaptureProperty sets the specified property of video capturing. Currently the function supports only video files: CV_CAP_PROP_POS_MSEC, CV_CAP_PROP_POS_FRAMES, CV_CAP_PROP_POS_AVI_RATIO .
NB This function currently does nothing when using the latest CVS download on linux with FFMPEG (the function contents are hidden if 0 is used and returned).
I had the same problem as you. Ended up going into the OpenCV source and changing the default parameters in modules/highgui/src/cap_v4l.cpp, lines 245-246 and rebuilding the project.
#define DEFAULT_V4L_WIDTH 1920
#define DEFAULT_V4L_HEIGHT 1080
This is for OpenCV 2.4.8
It seems to be variable by cammera.
AFIK, Logitech cameras have particularly bad linux support (though It;s gotten better) Most of their issues are with advanced features like focus control. i would advise sticking with basic cameras (IE manual focus Logitech cameras) just to play it safe.
My built in laptop camera has no issue and displays at normal resolution.
My external logitech pro has issues initalizing.
However, I can overcome the resolution issue with these two lines.
Yes, they are the same as you used.
cv.SetCaptureProperty(self.capture,cv.CV_CAP_PROP_FRAME_WIDTH, 1280)
cv.SetCaptureProperty(self.capture,cv.CV_CAP_PROP_FRAME_HEIGHT, 720)
My Logitech still throws errors but the resolution is fine.
Please make sure the resolution you set is a supported by your camera or v4l will yell at you. If I set an unsupported native resolution, I have zero success.
Not sure if it works, but you can try to force the parameters to your values after you instantiate camera object:
import cv
cam = cv.CaptureFromCAM(-1)
os.system("v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=1")
os.system("v4l2-ctl --set-parm=30")
image = cv.QueryFrame(cam)
That's a bit hacky, so expect a crash.
## Sets up the camera to capture video
cap = cv2.VideoCapture(device)
width = 1280
height = 720
#set the width and height
cap.set(3,width)
cap.set(4,height)

Categories

Resources