Saturday, December 24, 2011

QWT Library Installation in QT


The Qwt library contains GUI Components and utility classes which are primarily useful for programs with a technical background. Beside a 2D plot widget it provides scales, sliders, dials, compasses, thermometers, wheels and knobs to control or display values, arrays, or ranges of type double. Qwt is distributed under the terms of the Qwt License, Version 1.0. It is compatible with Qt Creator >=4.4. QwtPlot can be downloaded from HERE. 
I will explain the easy way of installation in STEPS
  • At First extract the zip file(preferably C:) you have downloaded and you will get a folder named qwt-6.0.0. Inside the folder qwt-6.0.0 you will get a qwt.pro file. Open the qwt.pro file with QT and run it(Ctrl+r).
  • Even you might get error during runtime but will get another folder qwt named qwt-build-desktop. Here you might want to install the library with qMake and so on but I go the library without installing them with qmake and so on. Hence I would not prefer to install library with qmake and so on
  • Copy the dll files named qwt.dll and qwtd.dll from qwt-6.0.0/lib folder  preferably to C:/Qt?bin folder oe you can also copy it to windows/system 32.
  • Now statically link the library file and header files of QWT with your QT project. In order to link simply provide the path in the PRO section of your new project in QT:                                                       QWT_LOCATION = C:/qwt-6.0.0
    INCLUDEPATH += $${QWT_LOCATION}/src
    LIBS = -L$${QWT_LOCATION}/lib \
    -lqwt 
  • Now start coding in mainwindow.cpp section by #include <qwt.h> and so on.                                                  

Friday, December 23, 2011

Camera Calibration using Chessboard



OpenCV provides several algorithms to help us compute these intrinsic parameters.The actual calibration is done via cvCalibrateCamera2(). In this routine, the method of calibration is to target the camera on a known structure that has many individual and identifiable points. By viewing this structure from a variety of angles, it is possible to then compute the (relative) location and orientation of the camera at the time of each image as well as the intrinsic parameters of the camera 


Our stereo set up was configured in a more common  and simpler manner in which principal rays intersect at infinity as shown in figure  .The OpenCV library function called cvStereoCalibrate() can solve for R and T as well as distortion, essential and fundamental matrix. [OReilly’s learning opencv by example.
The function is feeded with number of images of a chessboard at different orientation. Because of image noise and rounding errors, each chessboard pair results in slightly different values for R and T. An iterative algorithm is used to get minimum of the reprojection error of the chessboard corners for both camera views and return a solution for R and T. The image planes mathematically gets coplanar .The chessboard used during calibration in our project was of 10 by 7 squares with 54 corners. It is shown in the figure .
10 by 7 chessboard with 54 corners used during camera calibration
I would not be going through the theoretical parts as the theory is best explained in the book Learning OpenCV , OREILLY. Instead I will going going straight through the code for which directly calculates the intrinsic parameter of the camera and also gives you the undistorted image
//
"
int n_boards = ?; //Will be set by input list
const int board_dt = 20; //Wait 20 frames per chessboard view
int board_w=10;
int board_h=7;
//int main(int argc, char* argv[]) {
//if(argc != 4){
//printf(“ERROR: Wrong number of input parameters\n”);
//return -1;
//}
board_w = 10;
board_h = 7;
n_boards = 10;
int board_n = board_w * board_h;
CvSize board_sz = cvSize( board_w, board_h );
CvCapture* capture = cvCreateCameraCapture( 0 );
assert( capture );
cvNamedWindow( "Calibration" );
//ALLOCATE STORAGE
CvMat* image_points = cvCreateMat(n_boards*board_n,2,CV_32FC1);
CvMat* object_points = cvCreateMat(n_boards*board_n,3,CV_32FC1);
CvMat* point_counts = cvCreateMat(n_boards,1,CV_32SC1);
CvMat* intrinsic_matrix = cvCreateMat(3,3,CV_32FC1);
CvMat* distortion_coeffs = cvCreateMat(5,1,CV_32FC1);
CvPoint2D32f* corners = new CvPoint2D32f[ board_n ];
int corner_count;
int successes = 0;
int step, frame = 0;
IplImage *image = cvQueryFrame( capture );
IplImage *gray_image = cvCreateImage(cvGetSize(image),8,1);//subpixel
// CAPTURE CORNER VIEWS LOOP UNTIL WE’VE GOT n_boards
// SUCCESSFUL CAPTURES (ALL CORNERS ON THE BOARD ARE FOUND)
//
while(successes < n_boards) {
//Skip every board_dt frames to allow user to move chessboard
if(frame++ % board_dt == 0) {
//Find chessboard corners:
int found = cvFindChessboardCorners(
image, board_sz, corners, &corner_count,
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS
);
//Get Subpixel accuracy on those corners
cvCvtColor(image, gray_image, CV_BGR2GRAY);
cvFindCornerSubPix(gray_image, corners, corner_count,
cvSize(11,11),cvSize(-1,-1), cvTermCriteria(
CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
//Draw it
cvDrawChessboardCorners(image, board_sz, corners,
corner_count, found);
cvShowImage( "Calibration", image );
// If we got a good board, add it to our data
if( corner_count == board_n ) {
step = successes*board_n;
for( int i=step, j=0; j<board_n; ++i,++j ) {
CV_MAT_ELEM(*image_points, float,i,0) = corners[j].x;
CV_MAT_ELEM(*image_points, float,i,1) = corners[j].y;
CV_MAT_ELEM(*object_points,float,i,0) = j/board_w;
CV_MAT_ELEM(*object_points,float,i,1) = j%board_w;
CV_MAT_ELEM(*object_points,float,i,2) = 0.0f;
}
CV_MAT_ELEM(*point_counts, int,successes,0) = board_n;
successes++;
}
} //end skip board_dt between chessboard capture
//Handle pause/unpause and ESC
int c = cvWaitKey(15);
if(c == 'p'){
c = 0;
while(c != 'p' && c != 27){
c = cvWaitKey(250);
}
}
if(c == 27)
//return 0;
image = cvQueryFrame( capture ); //Get next image
} //END COLLECTION WHILE LOOP.
//ALLOCATE MATRICES ACCORDING TO HOW MANY CHESSBOARDS FOUND
CvMat* object_points2 = cvCreateMat(successes*board_n,3,CV_32FC1);
CvMat* image_points2 = cvCreateMat(successes*board_n,2,CV_32FC1);
CvMat* point_counts2 = cvCreateMat(successes,1,CV_32SC1);
//TRANSFER THE POINTS INTO THE CORRECT SIZE MATRICES
//Below, we write out the details in the next two loops. We could
//instead have written:
//image_points->rows = object_points->rows = \
//successes*board_n; point_counts->rows = successes;
//
for(int i = 0; i<successes*board_n; ++i) {
CV_MAT_ELEM( *image_points2, float, i, 0) =
CV_MAT_ELEM( *image_points, float, i, 0);
CV_MAT_ELEM( *image_points2, float,i,1) =
CV_MAT_ELEM( *image_points, float, i, 1);
CV_MAT_ELEM(*object_points2, float, i, 0) =
CV_MAT_ELEM( *object_points, float, i, 0) ;
CV_MAT_ELEM( *object_points2, float, i, 1) =
CV_MAT_ELEM( *object_points, float, i, 1) ;
CV_MAT_ELEM( *object_points2, float, i, 2) =
CV_MAT_ELEM( *object_points, float, i, 2) ;
}
for(int i=0; i<successes; ++i){ //These are all the same number
CV_MAT_ELEM( *point_counts2, int, i, 0) =
CV_MAT_ELEM( *point_counts, int, i, 0);
}
cvReleaseMat(&object_points);
cvReleaseMat(&image_points);
cvReleaseMat(&point_counts);
// At this point we have all of the chessboard corners we need.
// Initialize the intrinsic matrix such that the two focal
// lengths have a ratio of 1.0
//
CV_MAT_ELEM( *intrinsic_matrix, float, 0, 0 ) = 1.0f;
CV_MAT_ELEM( *intrinsic_matrix, float, 1, 1 ) = 1.0f;
//CALIBRATE THE CAMERA!
cvCalibrateCamera2(
object_points2, image_points2,
point_counts2, cvGetSize( image ),
intrinsic_matrix, distortion_coeffs,
NULL, NULL,0 //CV_CALIB_FIX_ASPECT_RATIO
);
// SAVE THE INTRINSICS AND DISTORTIONS
cvSave("Intrinsics.xml",intrinsic_matrix);
cvSave("Distortion.xml",distortion_coeffs);
// EXAMPLE OF LOADING THESE MATRICES BACK IN:
CvMat *intrinsic = (CvMat*)cvLoad("Intrinsics.xml");
CvMat *distortion = (CvMat*)cvLoad("Distortion.xml");
// Build the undistort map that we will use for all
// subsequent frames.
//
IplImage* mapx = cvCreateImage( cvGetSize(image), IPL_DEPTH_32F, 1 );
IplImage* mapy = cvCreateImage( cvGetSize(image), IPL_DEPTH_32F, 1 );
cvInitUndistortMap(
intrinsic,
distortion,
mapx,
mapy
);
// Just run the camera to the screen, now showing the raw and
// the undistorted image.
//
cvNamedWindow( "Undistort" );
while(image) {
IplImage *t = cvCloneImage(image);
cvShowImage( "Calibration", image ); // Show raw image
cvRemap( t, image, mapx, mapy ); // Undistort image
cvReleaseImage(&t);
cvShowImage("Undistort", image); // Show corrected image
//Handle pause/unpause and ESC
int c = cvWaitKey(15);
if(c == 'p') {
c = 0;
while(c != 'p' && c != 27) {
c = cvWaitKey(250);
}
}
if(c == 27)
break;
image = cvQueryFrame( capture );
}
//return 0;



At the End the when you provide your camera with 20frames as in above code then the code calculates the intrinsic parameter of your camera and gives you the rectified image necessary for stereo-vision purpose.

Problem in Using two USB Camera Simultaneously



When We Tried to Use Two Camera Simultaneously at a time for stereo-vision , the real problem occurs 
when the camera all appear in the device manager but only one camera will work at a time.
This is probably the Camera Driver problem which could not support total bandwidth of dual camera. We managed to solve our problem in windows Environment but could not. So we decided to migrate to Linux(Ubuntu 10.10) and fortunately Ubuntu had inbuilt Driver for PS3 USB camera which supported dual camera.
I will show use the reason mathematically why two USB camera were not supported simultaneously.

Total Bandwidth of USB 2.0=480Mbits/sec
Bandwidth of single USB Camera = number of channels*total bits*resolution*frames
per sec
=3*24*640*480 *15
=3317760000 bit/sec
=331.776Mbits/sec
Hence bandwidth of single camera exceeded 50% of the total bandwidth of USB 2.0. Also the
USB Ports on laptop are on the same hub and they share same common resources
(bandwidth). Also the Driver of PS3 Eye cam (USB Webcam) did not support the dual camera
even at minimum resolution and minimum frame rates per second.
With two identical USB cameras, the hardest thing is to make them work together
simultaneously. In some cases, camera drivers don't allow/support viewing both cameras
simultaneously - one might watch one camera or another, but not both.
Fortunately Ubuntu 10.04 and newer version had inbuilt support for PS3 Eye cam Driver and
supported the simultaneous running of dual USB camera.

Dual PS3 Camera mounted Mechanically

Configuring Open CV in QT

First of all you will have to download open cv version 2.1 from here
Extract the zip file in your Drive(preferably C Drive)
Go inside the folder that is :Open CV2.1/bin folder and copy all those dll files to C:/Qt/2010.05/bin. The . Dll files are cv210.dll, cv210d.dll,cvaux210.dll, cxcore210.dll, highgui210.dll, ml210.dll,   opencv_ffmpeg210.dll.
Then Start New Project in QT and you will need to prove the path for the library files statically in your project. In the PRO section of new project provide path for header files and library files as well.
"INCLUDEPATH += C:\OpenCV2.1\include\opencv\
LIBS += C:\OpenCV2.1\lib\cv210.lib \
C:\OpenCV2.1\lib\cvaux210.lib \
C:\OpenCV2.1\lib\cxcore210.lib\
C:\OpenCV2.1\lib\cxts210.lib \
C:\OpenCV2.1\lib\highgui210.lib \
C:\OpenCV2.1\lib\ml210.lib 
"
INCLUDEPATH provides path for the header files of Open-CV and LIBS+ statically include the library files to the QT project.
Finally Start coding in Mainwindows.cpp by
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
Check whether Open CV is sucessfully configured or not by the following code.


    IplImage *img=cvLoadImage("Image_name.jpg");
    cvNamedWindow("rss",CV_WINDOW_AUTOSIZE);
    cvShowImage("rss",img);
    cvWaitKey(0);
    cvReleaseImage(&img);
    cvDestroyWindow("rss");


Include the image you want to display in the build folder of your project. For Example your folder name is Image_display the copy the image (Image_name.jpg) inside the folder Image_display-build-desktop. Or If you find the problem then simplly you can provide path in this section


IplImage *img=cvLoadImage("C:\Qt\Image_name.jpg");



Configuration of QextserialPort Library


Tips for the configuration of QextserialPort library

I used QextSerialPort library for Serial communication in Qt Application.

As QextserialPort is an external library you will need to configure in pro section and provide appropriate path
for the library files
Steps:
1)Download the Qextserial port library and save it in C Drive(I prefer C Drive) Download
2)After you have completed the download extract the zip file and open the file qextserialport.pro(PRO FILE).
    Run the .pro file in Qt by clicking Run(or ctrl+R).After you click the run, you will get a new folder named 
    qextserialport-build.
    Inside the folder you will get your library files libqextserialport.a and libqextserialportd.a(actually inside
    qextserialport-build/build) and two dll files also.
3)Copy those dll files which is present inside the qextserialport-build folder preferably to C:/Qt/2010.05/bin or you can also copy it to the system32 folder (
     i.e. C:\Windows\system32) 
4)Start a new QT project
5)Link the header files(.h extension) present in another folder qextserialport-1.2win-aplha. 
   If you Don't have any idea how to link the just copy and paste the following command in your new Qt project
   section.
   Just provide path for the header files by;
    "INCLUDEPATH += C:/qextserialport-1.2win-alpha
    QMAKE_LIBDIR += C:/qextserialport-build/build
    CONFIG(debug, debug|release):LIBS += -lqextserialportd
    else:LIBS += -lqextserialport 
    unix: DEFINES = _TTY_POSIX_
    win32: DEFINES = _TTY_WIN_"
    If you find it difficult to understand them just simply copy and paste them in .pro section of your project file.
6)then you can start coding in mainwindow.cpp section only after #include <qextserialport.h>
    These are the configuration that you need to setup for inorder to proper working of the Qextserialport Library. 

Codes for Serial Port Communication in QT

At first you need to include the header files at windows.cpp section and start coding
#include <qextserialport.h>
QextSerialPort *port;//create new object of class QextSerialPort.
port=new QextSerialPort(COM3);//use 3 or 4 according to your PC
if(port->isOpen())
        {
        port->flush();
        po 
 if(port->isOpen())
{
port->flush();
port->close(); 
        port->close();
 //serial port initialization before openinng the port for reading and writing purpose
port->open(QIODevice::ReadWrite | QIODevice::Unbuffered); 
port->setBaudRate(BAUD9600);
port->setFlowControl(FLOW_OFF); 
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setQueryMode(QextSerialPort::EventDriven);

//writing data from serial port
QByteArray b;
unsigned char c = somevalue;
QString sdata = QString(c);
b = sdata.toAscii();
ui->lineEdit_2->setText(QString::number(somevalue));
port->write(b);
    b.clear();
port->write(b);
b.clear(); 
port->flush(); 

//for reading purpose
//for reading purpose
char buff[1024];
if(port->bytesAvailable())
{
int i = port->read(buff, 1);//read 1 byte at a time
buff[i] = '\0';
if(i != -1)
{
QString str(buff);
ui->textBrowser->append(QString::number(buff[i-1]));//append the data in textbrowser to see whether the data written is correct or not
}
else
{
qDebug("error in port");