Stereo Vision with OpenCV and QT

 

Demo


 

Hardware

Consists of two USB Web Cameras connected one next to another:

IMG_0891.JPG

 

Software

Source code available here:

http://code.google.com/p/opencvstereovision/source/browse/#svn/trunk

Requirements:

- QT SDK  http://www.qtsoftware.com/downloads

- OpenCV Library (* At the time of this article I was using  Version 1.1pre1, October, 2008)

 

Once you have instaleld the libraries and downloaded the code open OpenCV-Qt-StereoVision.pro in QT Creator.

Update the paths to where your OpenCV library is installed (replace every occurrence of  C:\SDK\OpenCV\  to the path where you installed OpenCV).

It is assumed that you have 2 USB cameras connected to your PC and there are no other cameras connected to computer. If this is not the case then you might want to have a look at  StereoCamera::setup()  in stereocamera.cpp.

It is assumed your cameras can capture 640x480 images.

If you don't have the cameras yet, but would like to test the sofware using the included images sets (see /images/ folder). Open mainwindow.cpp and comment out  timer.start(50); while uncommenting one of the 2 lines:

  //stereoVisionTest("../images/set1/",7,4);  //run test1
  //stereoVisionTest("../images/set2/",9,6);  //run test2

If you get any compiler errors make sure your Qt and OpenCV libraries are installed correctly. For that matter try to create a new test QT project and make sure it compiles.

 

Calibration

Before your cameras can see in 3D you need to perform a calibration sequence.

- print out the following PDF : ChessBoard - Stereo Calibration.pdf and tape it to a solid piece of wood, plastic or fiber glass (make sure the image is not bent or calibration will not work).

- focus your cameras so that the text on the chessboard is readable, make sure you don't modify the focus of cameras after calibration or during calibration since the focus is an important factor in calibration .

- start calibration by clicking on Start Calibration button in software, place the chessboard in front of the cameras so that it is completely visible in both cameras.

-software will take samples every 5 seconds , until the specified number of samples has been taken (10 by default).

-once calibration is complete click "Save Calibration" to save calibration data to a file (calibration will be reloaded next time you start the program automatically).

-if you modify position or focus of cameras you will need to calibrate.

-pay attention to 'rectified' image , if a line intersects an object or a spot on the left image it should intersect same object or spot on the right image. This is an indicator that your calibration is correct.

-if you have valid calibration data you should see the normalized depth image in the "Depth" window

Good luck !

//starlino//

Related Articles:

Comments/Updates:

Add Comment
Ricardo (2009-08-13 ):
Hi,

A question about Qt. I can't get your program to compile because I get this:

"d:\qtstereovision\stereocamera.h:8: error: Cannot open include file: 'vector.h': No such file or directory"

I am using Qt Creator with Qt 4.5, Windows Vista. I have compiled qt programs with the visual studio integration before, but haven't tried qt Creator alone.
Starlino (2009-08-13 ):
Vector.h is part of STL. It is disributed with QT (4.5) , mine is at this location:

C:\Qt\2009.02\mingw\include\c++\3.4.2\backward\vector.h

If you don't have it then check installation options.

(You will get a backward warning when compiling with this file ).
Ska1ix (2009-08-14 ):
Thank you for sharing your project. I have also been trying to get the calibration work with little effort, maybe because I didn't use a solid surface. Anyway, if OpenCV is installed in a path with sapces, like "Program Files" QT doesn'a accept it. I had to copy the contents of C:\Program Files\OpenCV to C:\SDK\OpenCV, then it worked.
Starlino (2009-08-14 ):
1)
Did you try enclose paths with spaces in quotes ?

2)
For calibration to work use the PDF file supplied and attach it to a solid board. Use good light conditions (daylight is the best). Make sure your cameras are focused.

IMPORTANT:
Make sure you did not switch left and right camera.
How to check ?

The screen with the Right camera should have objects on the right that are not on the Left camera (i.e. image is shifted to the right relative to the left camera). Similar the screen with the Left camera should show an image shifted to the left relative to the right camera. If you got it wrong , just switch the USB ports where the cameras are conencted and restart application.
rbha311 (2009-10-16 ):
I saw your video on the stereo-vision project you have done and I must say that it is definitely impressive. I am working on a similar project with opencv but everytime i try and capture the stream from the two cameras, i get an error saying that the cameras have exceeded the usb bandwidth. Did you have such a problem when implementing your system and do you think you could help me figure out a solution to this problem?
I would really appreciate your help in this. Thanks heaps in advance.
starlino (2009-10-16 ):
I dont think the exceeded bandwidth problem has anything to do with Qt or OpenCV it's more of a Windows/Hardware problem. You might be using a low speed hub , depending on your computer some USB ports may also be internally connected to the same hub. Try using the back USB ports instead. Try different combinations.

To troubleshoot this you can use USBDeview utility

http://www.nirsoft.net/utils/usb_devices_view.html

scroll all the way to the right and you'll see the Hub / Port column.

Make sure no other devices are connected to the same hub

Also try to adjust your camera frame rates (decrease it), you cameras might have their own dedicated control panel, or try window's Control Panel > Scanners and Cameras.
While you at it you might want to adjust your resolution to 640x480.

//starlino//



Mukesh Kumar (2009-10-21 ):
Hello,

I downloaded the code from code.google.com project. I had installed opencv and QT SDK on windows Xp. I tried to compile the code i am getting these errors. I am first time user of QT. So please help me out to make it run. the compiler output is as given bellow.

Running build steps for project OpenCV-Qt-StereoVision...
Configuration unchanged, skipping QMake step.
Starting: C:/Qt/2009.04/mingw/bin/mingw32-make.exe -w
mingw32-make: Entering directory `C:/Documents and Settings/mukesh.kumar/Desktop/opencvstereovision'
C:/Qt/2009.04/mingw/bin/mingw32-make -f Makefile.Debug
mingw32-make[1]: Entering directory `C:/Documents and Settings/mukesh.kumar/Desktop/opencvstereovision'
g++ -c -g -frtti -fexceptions -mthreads -Wall -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -DQT_NEEDS_QMAIN -I'../../../../Qt/2009.04/qt/include/QtCore' -I'../../../../Qt/2009.04/qt/include/QtGui' -I'../../../../Qt/2009.04/qt/include' -I'../../../../SDK/OpenCV/cxcore/include' -I'../../../../SDK/OpenCV/cv/include' -I'../../../../SDK/OpenCV/cvaux/include' -I'../../../../SDK/OpenCV/otherlibs/highgui' -I'../../../../Qt/2009.04/qt/include/ActiveQt' -I'debug' -I'.' -I'../../../../Qt/2009.04/qt/mkspecs/win32-g++' -o debug/stereovision.o stereovision.cpp
In file included from C:/Qt/2009.04/mingw/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/backward/vector.h:59,
from stereovision.h:8,
from stereovision.cpp:1:
C:/Qt/2009.04/mingw/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the header for the header for C++ includes, or instead of the deprecated header . To disable this warning use -Wno-deprecated.
stereovision.cpp: In member function `int StereoVision::calibrationEnd()':
stereovision.cpp:127: error: `CV_CALIB_SAME_FOCAL_LENGTH' was not declared in this scope
stereovision.cpp:127: error: `cvStereoCalibrate' was not declared in this scope
stereovision.cpp:130: error: `cvUndistortPoints' was not declared in this scope
stereovision.cpp:150: error: `cvStereoRectifyUncalibrated' was not declared in this scope
stereovision.cpp:169: error: `cvInitUndistortRectifyMap' was not declared in this scope
stereovision.cpp:127: warning: unused variable 'CV_CALIB_SAME_FOCAL_LENGTH'
stereovision.cpp:127: warning: unused variable 'cvStereoCalibrate'
stereovision.cpp:150: warning: unused variable 'cvStereoRectifyUncalibrated'
stereovision.cpp: In member function `int StereoVision::stereoProcess(CvArr*, CvArr*)':
stereovision.cpp:190: error: `CvStereoBMState' was not declared in this scope
stereovision.cpp:190: error: `BMState' was not declared in this scope
stereovision.cpp:190: error: `cvCreateStereoBMState' was not declared in this scope
stereovision.cpp:199: error: `cvFindStereoCorrespondenceBM' was not declared in this scope
stereovision.cpp:202: error: `cvReleaseStereoBMState' was not declared in this scope
stereovision.cpp:190: warning: unused variable 'CvStereoBMState'
stereovision.cpp:190: warning: unused variable 'cvCreateStereoBMState'
stereovision.cpp:199: warning: unused variable 'cvFindStereoCorrespondenceBM'
stereovision.cpp:202: warning: unused variable 'cvReleaseStereoBMState'
mingw32-make[1]: Leaving directory `C:/Documents and Settings/mukesh.kumar/Desktop/opencvstereovision'
mingw32-make: Leaving directory `C:/Documents and Settings/mukesh.kumar/Desktop/opencvstereovision'
mingw32-make[1]: *** [debug/stereovision.o] Error 1
mingw32-make: *** [debug] Error 2
Exited with code 2.
Error while building project OpenCV-Qt-StereoVision
When executing build step 'Make'





Thanks & Regards
Mukesh Kumar
http://forum.genericembedded.com
Kris (2009-11-05 ):
Can you tell me what drivers you used for the webcams ? I have the same cams but can't get them to work simultaneously with openncv 2.0 .. thnx
Starlino (2009-11-05 ):
You should ask the Ebay seller for drivers.

Try these drivers http://www.colordrives.net/ : LED 350K webcam driver (however I can't guarantee they will work with your cameras).
Ricardo Arango (2009-11-09 ):
Hi,

Have you had any problems with the results of the calibration? I am using cvStereoCalibrate and both my translation and rotation matrices are far from the correct position. Not very far, but are not precise enough. Do you have any advice on how to improve the calibration?

Thanks.
starlino (2009-11-09 ):
Ricardo,

Small deviation will always be present due to the camera distortion model not matching the real world distortion. you can read more about this in the opencv book see the right column. Even with this you can improve calibration results by:
- ensuring good lightning
- increase image contrast. See if you can find settings on your computer to increase camera contrast during calibration.
- focus the camera well , the text on the board should be readable
- changing focus after calibration will void calibration, moving camera position after calibration relative to the other camera will void calibration so make sure your rig is rigid enough. avoid cameras with auto-focus
- make sure samples you take are different, i.e. rotate the board , move it a little bit further or closer to the camera.
- try more or less samples count for the calibration, too few samples might not be representative, too many samples may result in over-fitting.

Well this is what I can think of so far. Let me know how it goes.
Fernando (2009-11-17 ):
Hello,

I must admit your work is so interesting for those of us who are starting in this issue. But I have an aspect from above which is not very clear for me and it concerns to the focus of the camera. What is the influence of the focus in the calibration parameters? Focal length shouldn´t change and rotation and translation vectors neither...My question arise since I am choosing the cameras for my stereo system and I don´t know if they could have auto-focus (and therefore, easier to implement ...). Thank you so much in advance.
starlino (2009-11-17 ):
Fernando ,

Focusing will change the distance between the center of the lens and the projection plane (the sensor). Although this variation might seem relatively small, from my experience it is enough to void the calibration. I would be interested in your results if you choose to use auto-focusing cameras, although my intuition would say that auto-focusing would introduce and extra unknown and unstable factor into the system.
Enoch (2009-11-24 ):
Hi,

C:/Dokumente und Einstellungen/WSUSUpdateAdmin/Eigene Dateien/stereo_calib/stereocamera.h:8: from stereocamera.h:8

I have the file vector.h in my Qt folder but the error still appears everytime i compile. Any idea how solve this issue?

And when the programme runs, the error "connecting to cameras...failed" appears in the plainTextEdit. I have checked that both of my logitech cams are working perfectly fine.
starlino (2009-11-24 ):
Enoch: There's a warning regarding vector.h (it it's not an error than it's fine). I am assuming it was a warning since you were able to run the application.

Maybe your cameras have a different index, try this utility and see where are your cameras detected (look under Devices menu).

http://noeld.com/programs.asp?cat=video

The demo code assumes you only have only 2 cameras in your system (but often times there are other devices , i.e. it might be your built-in laptop camera , or some virtual devices).


If your cameras appear at 2-nd and 3-rd position for example , then update this in stereocamera.cpp

captures[0] = cvCaptureFromCAM(CV_CAP_DSHOW + 0);
captures[1] = cvCaptureFromCAM(CV_CAP_DSHOW + 1);

to

captures[0] = cvCaptureFromCAM(CV_CAP_DSHOW + 1);
captures[1] = cvCaptureFromCAM(CV_CAP_DSHOW + 2);

If this doesn't help I recommend to isolate the problem - find sample code and make your cameras work with OpenCV (try just one camera at first).
Enoch (2009-11-24 ):
Hi,
I have checked the indexes of my cams and they are right(0 and 1). It appears that it only works with one camera.

R u running this programme on Linux? I'm using windows Vista and it seems these commands only work in linux. Even cvSetCaptureProperty to change the resolution of the camera doesn't work in windows.
Fernando (2009-11-24 ):
You are true starlino, focal length changes minimally...Finally, I am using autofocus which is enough for me at the moment. One more point, have you tried to get the distance of the objects from your camera, that´s say Z. I am stimating it now but I am afraid I will not get good results...

(By the way, I realized you have a little error calling "cvInitUndistortRectifyMap(&_M2,&_D1,&_R2,&_M2,mx2,my2)" since _D1 should be _D2, although in this case is not significant because the cameras are the same ;))
Eikel (2009-11-25 ):
Hey starlino,

is your system capable to measure depths? Sorry if my question seems daffy - i'm just getting started with machine vision...
Thanks in advance
Eikel
starlino (2009-11-25 ):
If one would like to translate the grayscale color value from the depth image to a real distance , then two approaches can be taken:
1) go through all the theory and calculate the distance formula
2) or you could just position an object at a known distance and then measure the grayscale level on the depth image, from this you can derive a conversion coefficient experimentally.

Please note that you have to disable the cvNormalize as the last step if you're interested in absolute distance values. What cvNormalize does - it simply remaps colors so that the minimum color becomes 0 and maximum becomes 255. So keep this in mind.

Thanks Frenando for pointing out the bug, I will update the SVN repository with the fix.

Alex (2009-11-25 ):
"if you modify position or focus of cameras you will need to calibrate."

Hi, can you tell me "modify the position" is means modify the position between the tow cameras or move the tow cameras together?
starlino (2009-11-25 ):
Alex: I mean you should avoid to modify relative position of one camera from the other one. But you can obviously move both cameras as long as they move together.
ST Pan (2009-12-14 ):
I received a compiler error due to the following:

c:\qtsdk\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/gcj/javaprims.h:19: error: gcj/libgcj-config.h: No such file or directory

I did a file search in my Qt SDK directory for the file "libgcj-config.h", I couldn't find it. Do I have to re-install QT SDK in order to recompile successfully?
Fernando (2010-01-13 ):
Hi again starlino,

some time ago I asked you for depth calculation. I used reprojectImageTo3d() and I get results which doesn´t make sense. However, rectification is done well because I can calculate the disparity of the two images with good results. Therefore I checked the matrix Q from the calibration process and I can see, for example, focal length (Q[3][4]) is 474,228, baseline (1/Q[4][3]) is shorter than actually it is and so on..Have you tried to check this values? I don´t know which is the metric used by opencv, but I suposse it is in milimeters.

To add more information , I calibrate whit stereoCalibrate() and recitify with stereoRectify(). Thank you in advance.
Starlino (2010-01-13 ):
Fernando, I will check as soon as I get back to this project. You might have a good lead so let me know if you find something.
Fernando (2010-01-13 ):
The only idea which cames to my mind is that these parameters are measured in pixels, and therefore Z will be in pixels? It is not clear for me because I have calculated how long a pixel is ( pixels in horizontal / width of pixel) and after I have multiplied it by Z and the distance obtained has been astronomical.
Starlino (2010-01-13 ):
Fernando,
I would go the experimental way:

Place an object at known distance d1 from camera and measure grayscale value of it's image on the depth image it should be a value in range 0..255 let's name it g1.
You need to measure this grayscale value on the non-normalized depth image.
Then I would compute a coefficient k = d1/g1
Do this several times and compute an average value for k . Also observe if different experiments, by placing the object at different distances from camera trigger consistent results. I am assuming we have a linear relation here (but it might be a curve) so make a chart and analyze the relationship just in case.

Now if I have another grayscale value g2 i can compute the unknown physical distance d2 as follows:

d2 =~ g2 * d1 / g1 = g2 * k

Let me know if this worked.
Fernando (2010-01-26 ):
Hi starlino,

the only thing I have discovered is that all the units in the intrinsic matrix are in pixels. So, I use the following expression to calculate the Z:

Z =f*b /d

f -> focal length in pixels
b = baseline in CENTIMETERS (it´s used to convert from pixel world to cm world)
d = disparity in pixels (note that the disparity returned by Opencv is multiplied by 16, so you have to divide it for that in order to get the real disparity)

That way, if adjust a little bit the baseline placing an object in a known distance and measuring how much I have to modify the baseline to get a good measure, I can get good results.

To conclude, I haven´t been able to understand why baseline from the intrinsic matrix is so different from the real one. However, focal length is almost the same for both intrisic matrix and the measured one. I will follow this blog to see if you have tried with this issue again. Thank you anyway!
Glitch (2010-01-26 ):
Thanks a lot for your code. It is really helpful.
I've noticed you are using Hartley's method for preparing rectification parameters.
I made an experiment and used cvStereoRectify to get Rr, Rl and Pl, Pr matrices.
It seems that your method works better or maybe I am doing smth wrong.
Have you tested cvStereoRectify at some point?

This is how i do it:
///////////////////////////////////////////////////////////////////////////////////
cvStereoCalibrate( &_objectPoints, &_imagePoints1,
&_imagePoints2, npoints,
cameraMatrix1,distCoeffs1,cameraMatrix2,distCoeffs2,
imageSize, R, T, E, F,
cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, 1e-5)//,
//CV_CALIB_FIX_ASPECT_RATIO + CV_CALIB_ZERO_TANGENT_DIST + CV_CALIB_SAME_FOCAL_LENGTH
);
//prepare Rl,Rr,Pl,Pr - rectifiation parameters
cvStereoRectify(cameraMatrix1,
cameraMatrix2,
distCoeffs1,
distCoeffs2,
imageSize,
R,
T, //input up to here
Rl,
Rr,
Pl,
Pr); //2 default params: optional 4-by-4 reprojection matrix Q, flags
//create maps for left camera
cvInitUndistortRectifyMap(cameraMatrix1,
distCoeffs1,
Rl,
Pl,
mapx1,
mapy1);
//create maps for right camera
cvInitUndistortRectifyMap(cameraMatrix2,
distCoeffs2,
Rr,
Pr,
mapx2,
mapy2);
/////////////////////////////////////////////////////////////////////

I have two Logitech USB 2MP cameras with autofocus, unfortunately.
Glitch (2010-01-28 ):
The difference was coming from the flags in cvStereoCalibrate. Just set the flags the same as Starlino has set.
sir_nacnud (2010-02-15 ):
What version of OpenCV does you code require? I'm not for sure if I can just drop in 2.0.
Starlino (2010-02-15 ):
At the time of this article I was using OpenCV 1.1pre1, October, 2008
Glitch (2010-02-19 ):
It works with OpenCV 2.0 without problems.
Fernando (2010-02-22 ):
Just to say be careful with the OpenCV 2.0 warp for C++ because I found a bug in the function stereoCalibrate. I don´t know if it is fixed now but if you use cvStereoCalibrate (C version) you won´t get any problems. Enjoy.
Starlino (2010-03-14 ):
OpenCV Mono/Stereo Calibration in Python:

https://code.ros.org/svn/ros-pkg/stacks/image_pipeline/trunk/camera_calibration/src/camera_calibration/calibrator.py

Project home:

http://www.ros.org/browse/details.php?name=camera_calibration
Powered by WebRing.