19 #include <opencv2/core/base.hpp>
20 #include <opencv2/imgproc.hpp>
21 #include <opencv2/calib3d.hpp>
22 #include <opencv2/core/core_c.h>
23 #include <opencv2/calib3d/calib3d_c.h>
26 #ifdef OPENCV_GREATER_2
27 #include <opencv2/xfeatures2d/nonfree.hpp>
29 #include <opencv2/nonfree/nonfree.hpp>
33 #include "iCub/stereoVision/stereoCamera.h"
77 Mat StereoCamera::buildRotTras(Mat &R, Mat &T) {
78 Mat A = Mat::eye(4, 4, CV_64F);
79 for(
int i = 0; i < R.rows; i++)
81 double* Mi = A.ptr<
double>(i);
82 double* MRi = R.ptr<
double>(i);
83 for(
int j = 0; j < R.cols; j++)
86 for(
int i = 0; i < T.rows; i++)
88 double* Mi = A.ptr<
double>(i);
89 double* MRi = T.ptr<
double>(i);
107 return this->InliersL;
112 return this->InliersR;
117 this->rectify=rectify;
118 this->epipolarTh=0.01;
119 this->cameraChanged =
true;
121 #if !defined(USING_GPU) && !defined(OPENCV_GREATER_2)
122 cv::initModule_nonfree();
129 Mat KL, KR, DistL, DistR, R, T;
130 loadStereoParameters(rf,KL,KR,DistL,DistR,R,T);
135 this->cameraChanged=
true;
136 this->epipolarTh=0.01;
137 this->rectify=rectify;
138 buildUndistortRemap();
140 #if !defined(USING_GPU) && !defined(OPENCV_GREATER_2)
141 cv::initModule_nonfree();
153 this->cameraChanged=
true;
154 this->rectify=rectify;
155 this->epipolarTh=0.01;
156 buildUndistortRemap();
158 #if !defined(USING_GPU) && !defined(OPENCV_GREATER_2)
159 cv::initModule_nonfree();
168 string elas_string = rf.check(
"elas_setting",Value(
"ROBOTICS")).asString();
170 double disp_scaling_factor = rf.check(
"disp_scaling_factor",Value(1.0)).asFloat64();
172 elaswrap =
new elasWrapper(disp_scaling_factor, elas_string);
175 if (rf.check(
"elas_subsampling"))
176 elaswrap->set_subsampling(
true);
178 if (rf.check(
"elas_add_corners"))
179 elaswrap->set_add_corners(
true);
182 elaswrap->set_ipol_gap_width(40);
183 if (rf.check(
"elas_ipol_gap_width"))
184 elaswrap->set_ipol_gap_width(rf.find(
"elas_ipol_gap_width").asInt32());
187 if (rf.check(
"elas_support_threshold"))
188 elaswrap->set_support_threshold(rf.find(
"elas_support_threshold").asFloat64());
190 if(rf.check(
"elas_gamma"))
191 elaswrap->set_gamma(rf.find(
"elas_gamma").asFloat64());
193 if (rf.check(
"elas_sradius"))
194 elaswrap->set_sradius(rf.find(
"elas_sradius").asFloat64());
196 if (rf.check(
"elas_match_texture"))
197 elaswrap->set_match_texture(rf.find(
"elas_match_texture").asInt32());
199 if (rf.check(
"elas_filter_median"))
200 elaswrap->set_filter_median(rf.find(
"elas_filter_median").asBool());
202 if (rf.check(
"elas_filter_adaptive_mean"))
203 elaswrap->set_filter_adaptive_mean(rf.find(
"elas_filter_adaptive_mean").asBool());
205 cout << endl <<
"ELAS parameters:" << endl << endl;
207 cout <<
"disp_scaling_factor: " << disp_scaling_factor << endl;
209 cout <<
"setting: " << elas_string << endl;
211 cout <<
"postprocess_only_left: " << elaswrap->get_postprocess_only_left() << endl;
212 cout <<
"subsampling: " << elaswrap->get_subsampling() << endl;
214 cout <<
"add_corners: " << elaswrap->get_add_corners() << endl;
216 cout <<
"ipol_gap_width: " << elaswrap->get_ipol_gap_width() << endl;
218 cout <<
"support_threshold: " << elaswrap->get_support_threshold() << endl;
219 cout <<
"gamma: " << elaswrap->get_gamma() << endl;
220 cout <<
"sradius: " << elaswrap->get_sradius() << endl;
222 cout <<
"match_texture: " << elaswrap->get_match_texture() << endl;
224 cout <<
"filter_median: " << elaswrap->get_filter_median() << endl;
225 cout <<
"filter_adaptive_mean: " << elaswrap->get_filter_adaptive_mean() << endl;
237 void StereoCamera::printStereoIntrinsic() {
238 if(this->Kleft.empty())
239 printf(
"Stereo Cameras are not calibrated, run calibration method before..\n");
242 printf(
"Left Intrinsic Parameters: \n");
243 printMatrix(this->Kleft);
244 printf(
"Right Intrinsic Parameters: \n");
245 printMatrix(this->Kright);
250 void StereoCamera::stereoCalibration(vector<string> imagelist,
int boardWidth,
int boardHeight,
float sqsize) {
252 boardSize.width=boardWidth;
253 boardSize.height=boardHeight;
254 runStereoCalib(imagelist, boardSize,sqsize);
259 void StereoCamera::stereoCalibration(
string imagesFilePath,
int boardWidth,
int boardHeight,
float sqsize) {
261 boardSize.width=boardWidth;
262 boardSize.height=boardHeight;
264 vector<string> imagelist;
265 bool ok = readStringList(imagesFilePath, imagelist);
266 if(!ok || imagelist.empty())
268 cout <<
"can not open " << imagesFilePath <<
" or the string list is empty" << endl;
271 runStereoCalib(imagelist, boardSize,sqsize);
275 bool StereoCamera::readStringList(
const string& filename, vector<string>& l )
278 FileStorage fs(filename, FileStorage::READ);
281 FileNode n = fs.getFirstTopLevelNode();
282 if( n.type() != FileNode::SEQ )
284 FileNodeIterator it = n.begin(), it_end = n.end();
285 for( ; it != it_end; ++it )
286 l.push_back((
string)*it);
291 void StereoCamera::runStereoCalib(
const vector<string>& imagelist, Size boardSize,
const float squareSize)
293 if( imagelist.size() % 2 != 0 )
295 cout <<
"Error: the image list contains odd (non-even) number of elements\n";
299 bool displayCorners =
false;
300 const int maxScale = 2;
303 vector<vector<Point2f> > imagePoints[2];
304 vector<vector<Point3f> > objectPoints;
307 int i, j, k, nimages = (int)imagelist.size()/2;
309 imagePoints[0].resize(nimages);
310 imagePoints[1].resize(nimages);
311 vector<string> goodImageList;
313 for( i = j = 0; i < nimages; i++ )
315 for( k = 0; k < 2; k++ )
317 const string& filename = imagelist[i*2+k];
318 Mat img = cv::imread(filename, 0);
321 if( imageSize == Size() )
322 imageSize = img.size();
323 else if( img.size() != imageSize )
325 cout <<
"The image " << filename <<
" has the size different from the first image size. Skipping the pair\n";
329 vector<Point2f>& corners = imagePoints[k][j];
330 for(
int scale = 1; scale <= maxScale; scale++ )
336 resize(img, timg, Size(), scale, scale);
337 found = findChessboardCorners(timg, boardSize, corners,
338 cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
343 Mat cornersMat(corners);
344 cornersMat *= 1./scale;
351 cout << filename << endl;
353 cvtColor(img, cimg, cv::COLOR_GRAY2BGR);
354 drawChessboardCorners(cimg, boardSize, corners, found);
355 imshow(
"corners", cimg);
356 char c = (char)cv::waitKey(500);
357 if( c == 27 || c ==
'q' || c ==
'Q' )
367 goodImageList.push_back(imagelist[i*2]);
368 goodImageList.push_back(imagelist[i*2+1]);
372 std::cout <<
"[StereoCamera] " << j <<
" pairs have been successfully detected." << std::endl;
376 std::cout <<
"[StereoCamera] Error: too few pairs detected." << std::endl;
380 imagePoints[0].resize(nimages);
381 imagePoints[1].resize(nimages);
382 objectPoints.resize(nimages);
384 for( i = 0; i < nimages; i++ )
386 for( j = 0; j < boardSize.height; j++ )
387 for( k = 0; k < boardSize.width; k++ )
388 objectPoints[i].push_back(Point3f(j*squareSize, k*squareSize, 0));
391 std::cout <<
"[StereoCamera] Running stereo calibration.." << std::endl;
393 Mat cameraMatrix[2], distCoeffs[2];
396 if(this->Kleft.empty() || this->Kleft.empty())
398 double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1],
399 this->Kleft, this->DistL,
400 this->Kright, this->DistR,
401 imageSize, this->R, this->T, E, F,
402 #ifdef OPENCV_GREATER_2
403 cv::CALIB_FIX_ASPECT_RATIO+cv::CALIB_ZERO_TANGENT_DIST+cv::CALIB_SAME_FOCAL_LENGTH+
404 cv::CALIB_RATIONAL_MODEL+cv::CALIB_FIX_K3+cv::CALIB_FIX_K4+cv::CALIB_FIX_K5,
405 TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 100, 1e-5));
407 TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 100, 1e-5),
408 CV_CALIB_FIX_ASPECT_RATIO+CV_CALIB_ZERO_TANGENT_DIST+CV_CALIB_SAME_FOCAL_LENGTH+
409 CV_CALIB_RATIONAL_MODEL+CV_CALIB_FIX_K3+CV_CALIB_FIX_K4+CV_CALIB_FIX_K5);
411 std::cout <<
"[StereoCamera] Calibration done with RMS error = " << rms << std::endl;
414 double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1],
415 this->Kleft, this->DistL,
416 this->Kright, this->DistR,
417 imageSize, this->R, this->T, E, F,
418 #ifdef OPENCV_GREATER_2
419 cv::CALIB_FIX_INTRINSIC,
420 TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 100, 1e-5));
422 TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 100, 1e-5),
423 CV_CALIB_FIX_INTRINSIC);
425 std::cout <<
"[StereoCamera] Calibration done with RMS error = " << rms << std::endl;
433 cameraMatrix[0] = this->Kleft;
434 cameraMatrix[1] = this->Kright;
435 distCoeffs[0]=this->DistL;
436 distCoeffs[1]=this->DistR;
442 vector<Vec3f> lines[2];
443 for( i = 0; i < nimages; i++ )
445 int npt = (int)imagePoints[0][i].size();
447 for( k = 0; k < 2; k++ )
449 imgpt[k] = Mat(imagePoints[k][i]);
450 undistortPoints(imgpt[k], imgpt[k], cameraMatrix[k], distCoeffs[k], Mat(), cameraMatrix[k]);
451 computeCorrespondEpilines(imgpt[k], k+1, F, lines[k]);
453 for( j = 0; j < npt; j++ )
455 double errij = fabs(imagePoints[0][i][j].x*lines[1][j][0] +
456 imagePoints[0][i][j].y*lines[1][j][1] + lines[1][j][2]) +
457 fabs(imagePoints[1][i][j].x*lines[0][j][0] +
458 imagePoints[1][i][j].y*lines[0][j][1] + lines[0][j][2]);
464 stereoRectify( this->Kleft, this->DistL, this->Kright, this->DistR, imageSize, this->R, this->T, R1, R2, P1, P2, this->Q, -1);
465 std::cout <<
"[StereoCamera] Average reprojection error = " << err/npoints << std::endl;
472 if( Kleft.empty() || Kright.empty() || DistL.empty() || DistR.empty() || R.empty() || T.empty()) {
473 std::cout <<
"Error: cameras are not calibrated! Run the calibration or set intrinsic and extrinsic parameters" << std::endl;
477 FileStorage fs(intrinsicFilePath+
".yml", FileStorage::WRITE);
480 fs <<
"M1" << Kleft <<
"D1" << DistL <<
"M2" << Kright <<
"D2" << DistR;
484 cout <<
"Error: can not save the intrinsic parameters\n";
486 fs.open(extrinsicFilePath+
".yml", FileStorage::WRITE);
489 fs <<
"R" << R <<
"T" << T <<
"Q" << Q;
493 std::cout <<
"Error: can not save the intrinsic parameters" << std::endl;
495 ofstream fout((intrinsicFilePath+
".ini").c_str());
498 fout <<
"[left]" << endl;
499 fout <<
"fx " << Kleft.at<
double>(0,0) << endl;
500 fout <<
"fy " << Kleft.at<
double>(1,1) << endl;
501 fout <<
"cx " << Kleft.at<
double>(0,2) << endl;
502 fout <<
"cy " << Kleft.at<
double>(1,2) << endl;
503 fout <<
"k1 " << DistL.at<
double>(0,0) << endl;
504 fout <<
"k2 " << DistL.at<
double>(1,0) << endl;
505 fout <<
"p1 " << DistL.at<
double>(2,0) << endl;
506 fout <<
"p2 " << DistL.at<
double>(3,0) << endl;
509 fout <<
"[right]" << endl;
510 fout <<
"fx " << Kright.at<
double>(0,0) << endl;
511 fout <<
"fy " << Kright.at<
double>(1,1) << endl;
512 fout <<
"cx " << Kright.at<
double>(0,2) << endl;
513 fout <<
"cy " << Kright.at<
double>(1,2) << endl;
514 fout <<
"k1 " << DistR.at<
double>(0,0) << endl;
515 fout <<
"k2 " << DistR.at<
double>(1,0) << endl;
516 fout <<
"p1 " << DistR.at<
double>(2,0) << endl;
517 fout <<
"p2 " << DistR.at<
double>(3,0) << endl;
529 return this->imright;
534 return this->Disparity;
539 return this->Disparity16;
550 if(this->Kleft.empty() || this->DistL.empty() || this->Kright.empty() || this->DistR.empty()) {
551 cout <<
" Cameras are not calibrated! Run the Calibration first!" << endl;
554 if(this->imleft.empty() || this->imright.empty()) {
555 cout <<
"Images are not set! set the images first!" << endl;
559 Size img_size = this->imleft.size();
563 lock_guard<mutex> lg(mtx);
564 stereoRectify(this->Kleft, this->DistL, this->Kright, this->DistR, img_size, this->R, this->T, this->RLrect, this->RRrect, this->PLrect, this->PRrect, this->Q, -1);
569 initUndistortRectifyMap(this->Kleft, this->DistL, this->RLrect, this->PLrect, img_size, CV_32FC1, this->map11, this->map12);
570 initUndistortRectifyMap(this->Kright, this->DistR, this->RRrect, this->PRrect, img_size, CV_32FC1, this->map21, this->map22);
573 remap(this->imleft, this->imgLeftRect, this->map11, this->map12, cv::INTER_LINEAR);
574 remap(this->imright, this->imgRightRect, this->map21,this->map22, cv::INTER_LINEAR);
576 cameraChanged =
false;
582 int speckleRange,
int numberOfDisparities,
int SADWindowSize,
583 int minDisparity,
int preFilterCap,
int disp12MaxDiff)
586 if (this->Kleft.empty() || this->DistL.empty() || this->Kright.empty() || this->DistR.empty())
588 cout <<
" Cameras are not calibrated! Run the Calibration first!" << endl;
592 if (this->imleft.empty() || this->imright.empty())
594 cout <<
"Images are not set! set the images first!" << endl;
598 Size img_size=this->imleft.size();
602 lock_guard<mutex> lg(mtx);
603 stereoRectify(this->Kleft, this->DistL, this->Kright, this->DistR, img_size,
604 this->R, this->T, this->RLrect, this->RRrect, this->PLrect,
605 this->PRrect, this->Q, -1);
609 this->RLrect=Mat::eye(3,3,CV_32FC1);
610 this->RRrect=Mat::eye(3,3,CV_32FC1);
611 this->PLrect=this->Kleft;
612 this->PRrect=this->Kright;
618 initUndistortRectifyMap(this->Kleft, this->DistL, this->RLrect, this->PLrect,
619 img_size, CV_32FC1, this->map11, this->map12);
620 initUndistortRectifyMap(this->Kright, this->DistR, this->RRrect, this->PRrect,
621 img_size, CV_32FC1, this->map21, this->map22);
625 remap(this->imleft, img1r, this->map11, this->map12, cv::INTER_LINEAR);
626 remap(this->imright, img2r, this->map21,this->map22, cv::INTER_LINEAR);
629 imgRightRect = img2r;
631 Mat disp,disp8,map,dispTemp;
637 success = elaswrap->compute_disparity(img1r, img2r, disp, numberOfDisparities);
640 map = disp * (255.0 / numberOfDisparities);
645 int cn=this->imleft.channels();
646 #ifdef OPENCV_GREATER_2
647 Ptr<StereoSGBM> sgbm=cv::StereoSGBM::create(minDisparity,numberOfDisparities,SADWindowSize,
648 8*cn*SADWindowSize*SADWindowSize,
649 32*cn*SADWindowSize*SADWindowSize,
650 disp12MaxDiff,preFilterCap,uniquenessRatio,
651 speckleWindowSize,speckleRange,
652 best?StereoSGBM::MODE_HH:StereoSGBM::MODE_SGBM);
653 sgbm->compute(img1r, img2r, disp);
656 sgbm.preFilterCap = preFilterCap;
657 sgbm.SADWindowSize = SADWindowSize;
658 sgbm.P1 = 8*cn*SADWindowSize*SADWindowSize;
659 sgbm.P2 = 32*cn*SADWindowSize*SADWindowSize;
660 sgbm.minDisparity = minDisparity;
661 sgbm.numberOfDisparities = numberOfDisparities;
662 sgbm.uniquenessRatio = uniquenessRatio;
663 sgbm.speckleWindowSize = speckleWindowSize;
664 sgbm.speckleRange = speckleRange;
665 sgbm.disp12MaxDiff = disp12MaxDiff;
668 sgbm(img1r, img2r, disp);
671 disp.convertTo(map, CV_32FC1, 1.0,0.0);
672 map.convertTo(map,CV_32FC1,255/(numberOfDisparities*16.));
682 lock_guard<mutex> lg(mtx);
683 Mat inverseMapL(map.rows*map.cols,1,CV_32FC2);
684 Mat inverseMapR(map.rows*map.cols,1,CV_32FC2);
686 for (
int y=0; y<map.rows; y++)
688 for (
int x=0; x<map.cols; x++)
690 inverseMapL.ptr<
float>(y*map.cols+x)[0]=(
float)x;
691 inverseMapL.ptr<
float>(y*map.cols+x)[1]=(
float)y;
692 inverseMapR.ptr<
float>(y*map.cols+x)[0]=(
float)x;
693 inverseMapR.ptr<
float>(y*map.cols+x)[1]=(
float)y;
697 undistortPoints(inverseMapL,inverseMapL,this->Kleft,this->DistL,this->RLrect,this->PLrect);
698 undistortPoints(inverseMapR,inverseMapR,this->Kright,this->DistR,this->RRrect,this->PRrect);
700 Mat mapperL=inverseMapL.reshape(2,map.rows);
701 Mat mapperR=inverseMapR.reshape(2,map.rows);
702 this->MapperL=mapperL;
703 this->MapperR=mapperR;
705 cameraChanged =
false;
709 remap(map,dispTemp,this->MapperL,x,cv::INTER_LINEAR);
710 dispTemp.convertTo(disp8,CV_8U);
713 disp.convertTo(disp, CV_16SC1, 16.0);
716 lock_guard<mutex> lg(mtx);
717 this->Disparity = disp8;
718 this->Disparity16 = disp;
724 cv::Point2f originalPoint;
727 if(u>=map11.rows || u<0 || v>=map12.cols || v< 0)
731 return originalPoint;
735 originalPoint.x=map11.ptr<
float>(v)[u];
736 originalPoint.y=map12.ptr<
float>(v)[u];
740 originalPoint.x=map21.ptr<
float>(v)[u];
741 originalPoint.y=map22.ptr<
float>(v)[u];
745 return originalPoint;
752 if (this->imleftund.empty() || this->imrightund.empty())
758 this->PointsL.clear();
759 this->PointsR.clear();
761 this->InliersL.clear();
762 this->InliersR.clear();
764 Mat grayleft(imleftund.rows,imleftund.cols, CV_8UC1);
765 imleftund.convertTo(grayleft,CV_8UC1);
767 Mat grayright(imrightund.rows,imrightund.cols,CV_8UC1);
768 imrightund.convertTo(grayright,CV_8UC1);
770 vector<KeyPoint> keypoints1,keypoints2;
771 Mat descriptors1,descriptors2;
773 #ifdef OPENCV_GREATER_2
774 Ptr<xfeatures2d::SIFT> sift=xfeatures2d::SIFT::create();
777 sift->detect(grayleft,keypoints1);
778 sift->compute(grayleft,keypoints1,descriptors1);
780 sift->detect(grayright,keypoints2);
781 sift->compute(grayright,keypoints2,descriptors2);
783 Ptr<cv::FeatureDetector> detector=cv::FeatureDetector::create(
"SIFT");
784 Ptr<cv::DescriptorExtractor> descriptorExtractor=cv::DescriptorExtractor::create(
"SIFT");
786 yAssert(detector!=NULL);
787 yAssert(descriptorExtractor!=NULL);
789 detector->detect(grayleft,keypoints1);
790 descriptorExtractor->compute(grayleft,keypoints1,descriptors1);
792 detector->detect(grayright,keypoints2);
793 descriptorExtractor->compute(grayright,keypoints2,descriptors2);
796 cv::BFMatcher descriptorMatcher;
797 vector<DMatch> filteredMatches;
798 crossCheckMatching(descriptorMatcher,descriptors1,descriptors2,filteredMatches,radius);
800 for (
size_t i=0; i<filteredMatches.size(); i++)
802 Point2f pointL=keypoints1[filteredMatches[i].queryIdx].pt;
803 Point2f pointR=keypoints2[filteredMatches[i].trainIdx].pt;
804 if (fabs(pointL.y-pointR.y)<displacement)
806 this->PointsR.push_back(pointR);
807 this->PointsL.push_back(pointL);
813 cv::drawMatches(this->imleftund,keypoints1,this->imrightund,keypoints2,
814 filteredMatches,matchImg,Scalar(0,0,255,0),Scalar(0,0,255,0));
819 double StereoCamera::reprojectionErrorAvg() {
820 if(PointsL.empty() || PointsR.empty()) {
821 cout <<
"No Matches Found" << endl;
825 if(InliersL.empty()) {
832 Point2f pointL, pointR;
834 vector<Point3f> WorldPoints;
835 Mat J=Mat(4,4,CV_64FC1);
838 for(
int i =0; i<(int)this->InliersL.size(); i++) {
843 point3D=
triangulation(pointL,pointR,this->Pleft,this->Pright);
844 WorldPoints.push_back(point3D);
847 vector<Point2f> reprojection;
849 projectPoints(Mat(WorldPoints), Mat::eye(3,3,CV_64FC1), Mat::zeros(3,1,CV_64FC1), this->Kleft, Mat(), reprojection);
850 double errorLeft = norm(Mat(InliersL), Mat(reprojection), cv::NORM_L2)/InliersL.size();
852 projectPoints(Mat(WorldPoints), this->R, this->T, this->Kright, Mat(), reprojection);
853 double errorRight = norm(Mat(InliersR), Mat(reprojection), cv::NORM_L2)/InliersR.size();
856 errAvg=(errorLeft+errorRight)/2;
864 Mat J=Mat(4,4,CV_64FC1);
866 for(
int j=0; j<4; j++) {
871 J.at<
double>(0,j)=(pointleft.x*this->Pleft.at<
double>(rowB,j))- (this->Pleft.at<
double>(rowA,j));
872 J.at<
double>(2,j)=(pointRight.x*this->Pright.at<
double>(rowB,j))- (this->Pright.at<
double>(rowA,j));
876 J.at<
double>(1,j)=(pointleft.y*this->Pleft.at<
double>(rowB,j))- (this->Pleft.at<
double>(rowA,j));
877 J.at<
double>(3,j)=(pointRight.y*this->Pright.at<
double>(rowB,j))- (this->Pright.at<
double>(rowA,j));
882 point3D.x=(float) ((
float) V.at<
double>(3,0))/((float) V.at<
double>(3,3));
883 point3D.y=(float) ((
float) V.at<
double>(3,1))/((float) V.at<
double>(3,3));
884 point3D.z=(float) ((
float) V.at<
double>(3,2))/((float) V.at<
double>(3,3));
892 Mat F_true(3,3,CV_64FC1);
894 Mat X1(2,4,CV_64FC1);
895 Mat X2(2,4,CV_64FC1);
896 Mat X3(2,4,CV_64FC1);
898 Mat Y1(2,4,CV_64FC1);
899 Mat Y2(2,4,CV_64FC1);
900 Mat Y3(2,4,CV_64FC1);
903 for(
int i=0; i<P1.rows; i++)
905 for(
int j=0; j<P1.cols; j++)
909 X2.at<
double>(1,j)= P1.at<
double>(i,j);
910 X3.at<
double>(0,j)= P1.at<
double>(i,j);
911 Y2.at<
double>(1,j)= P2.at<
double>(i,j);
912 Y3.at<
double>(0,j)= P2.at<
double>(i,j);
916 X1.at<
double>(0,j)= P1.at<
double>(i,j);
917 X3.at<
double>(1,j)= P1.at<
double>(i,j);
918 Y1.at<
double>(0,j)= P2.at<
double>(i,j);
919 Y3.at<
double>(1,j)= P2.at<
double>(i,j);
924 X1.at<
double>(1,j)= P1.at<
double>(i,j);
925 X2.at<
double>(0,j)= P1.at<
double>(i,j);
926 Y1.at<
double>(1,j)= P2.at<
double>(i,j);
927 Y2.at<
double>(0,j)= P2.at<
double>(i,j);
934 std::vector<Mat> MatX;
935 std::vector<Mat> MatY;
946 for(
int i=0; i<F_true.rows; i++)
948 for(
int j=0; j<F_true.cols; j++)
955 cv::vconcat(X,Y,concatenated);
957 F_true.at<
double>(j,i)=cv::determinant(concatenated);
967 this->InliersL.clear();
968 this->InliersR.clear();
970 if (this->PointsL.size()<10 || this->PointsL.size()<10 )
972 cout <<
"Not enough matches in memory! Run findMatch first!" << endl;
973 this->E=Mat(3,3,CV_64FC1);
977 updateExpectedCameraMatrices();
978 Mat F_exp=
FfromP(Pleft_exp,Pright_exp);
980 vector<Point2f> filteredL;
981 vector<Point2f> filteredR;
983 std::cout <<
"[StereoCamera] " << PointsR.size() <<
" Matches Found." << std::endl;
985 Mat pl=Mat(3,1,CV_64FC1);
986 Mat pr=Mat(3,1,CV_64FC1);
988 for (
size_t i=0; i<(int) PointsL.size(); i++)
990 pl.at<
double>(0,0)=PointsL[i].x;
991 pl.at<
double>(1,0)=PointsL[i].y;
992 pl.at<
double>(2,0)=1;
994 pr.at<
double>(0,0)=PointsR[i].x;
995 pr.at<
double>(1,0)=PointsR[i].y;
996 pr.at<
double>(2,0)=1;
998 Mat xrFxl=pr.t()*F_exp*pl;
1000 Mat Fxr=F_exp.t()*pr;
1011 double sampsonDistance=xrFxl.at<
double>(0,0)/(den1.val[0]+den2.val[0]);
1013 if (sampsonDistance<0.1)
1015 filteredL.push_back(PointsL[i]);
1016 filteredR.push_back(PointsR[i]);
1020 std::cout <<
"[StereoCamera] " << filteredL.size() <<
" Matches Left After Kinematics Filtering." << std::endl;
1022 vector<uchar> status;
1023 this->F=findFundamentalMat(Mat(filteredL), Mat(filteredR), status, CV_FM_8POINT, 1, 0.999);
1025 for (
size_t i=0; i<(int) filteredL.size(); i++)
1027 pl.at<
double>(0,0)=filteredL[i].x;
1028 pl.at<
double>(1,0)=filteredL[i].y;
1029 pl.at<
double>(2,0)=1;
1031 pr.at<
double>(0,0)=filteredR[i].x;
1032 pr.at<
double>(1,0)=filteredR[i].y;
1033 pr.at<
double>(2,0)=1;
1035 Mat xrFxl=pr.t()*F*pl;
1047 if (status[i]==1 && xrFxl.at<
double>(0,0)<0.001)
1049 InliersL.push_back(filteredL[i]);
1050 InliersR.push_back(filteredR[i]);
1054 std::cout <<
"[StereoCamera] " << InliersL.size() <<
" Matches Left After RANSAC Filtering." << std::endl;
1056 if (this->InliersL.size()<10 || this->InliersR.size()<10 )
1060 cout <<
"Not enough matches in memory! Run findMatch first!" << endl;
1061 this->E=Mat(3,3,CV_64FC1);
1065 this->F=findFundamentalMat(Mat(InliersL), Mat(InliersR),status, CV_FM_8POINT, 1, 0.999);
1066 this->E=this->Kright.t()*this->F*this->Kleft;
1075 cout <<
"Essential Matrix is empty! Run the estimateEssential first!" << endl;
1079 if (this->InliersL.empty())
1081 cout <<
"No matches in memory! Run findMatch first!" << endl;
1085 Mat W=Mat(3,3,CV_64FC1);
1087 W.at<
double>(0,0)=0;
1088 W.at<
double>(0,1)=-1;
1089 W.at<
double>(0,2)=0;
1091 W.at<
double>(1,0)=1;
1092 W.at<
double>(1,1)=0;
1093 W.at<
double>(1,2)=0;
1095 W.at<
double>(2,0)=0;
1096 W.at<
double>(2,1)=0;
1097 W.at<
double>(2,2)=1;
1101 Mat Y=Mat::eye(3,3,CV_64FC1);
1102 Y.at<
double>(2,2)=0.0;
1113 if (determinant(R1)<0 || determinant(R2)<0)
1125 Mat t1=U(Range(0,3),Range(2,3));
1128 Mat Rnew=Mat(3,3,CV_64FC1);
1130 Mat tnew=Mat(3,1,CV_64FC1);
1132 chierality(R1,R2,t1,t2,Rnew,tnew,this->InliersL,this->InliersR);
1134 Mat rvec_new=Mat::zeros(3,1,CV_64FC1);
1135 Mat rvec_exp=Mat::zeros(3,1,CV_64FC1);
1136 Rodrigues(Rnew,rvec_new);
1137 Rodrigues(R_exp,rvec_exp);
1139 Mat t_est=(tnew/norm(tnew))*norm(this->T);
1141 Mat diff_angles=rvec_exp-rvec_new;
1142 Mat diff_tran=T_exp-t_est;
1144 std::cout <<
"[StereoCamera] Angles Differences: " << diff_angles.at<
double>(0,0) <<
" " <<
1145 diff_angles.at<
double>(1,0) <<
" " <<
1146 diff_angles.at<
double>(2,0) << std::endl;
1148 std::cout <<
"[StereoCamera] Translation Differences: " << diff_tran.at<
double>(0,0) <<
" " <<
1149 diff_tran.at<
double>(1,0) <<
" " <<
1150 diff_tran.at<
double>(2,0) << std::endl;
1156 if (fabs(diff_angles.at<
double>(0,0))<0.15 && fabs(diff_angles.at<
double>(1,0))<0.15 && fabs(diff_angles.at<
double>(2,0))<0.15 &&
1157 fabs(diff_tran.at<
double>(0,0))<0.01 && fabs(diff_tran.at<
double>(1,0))<0.01 && fabs(diff_tran.at<
double>(2,0))<0.01)
1159 lock_guard<mutex> lg(mtx);
1162 this->updatePMatrix();
1163 this->cameraChanged=
true;
1173 Mat A= Mat::eye(3,4,CV_64FC1);
1174 Mat P1 = this->Kleft*Mat::eye(3, 4, CV_64F);
1176 for(
int i = 0; i < R1.rows; i++)
1178 double* Mi = A.ptr<
double>(i);
1179 double* MRi = R1.ptr<
double>(i);
1180 for(
int j = 0; j < R1.cols; j++)
1184 for(
int i = 0; i < t1.rows; i++)
1186 double* Mi = A.ptr<
double>(i);
1187 double* MRi = t1.ptr<
double>(i);
1191 Mat P2=this->Kright*A;
1192 A= Mat::eye(3,4,CV_64FC1);
1194 for(
int i = 0; i < R2.rows; i++)
1196 double* Mi = A.ptr<
double>(i);
1197 double* MRi = R2.ptr<
double>(i);
1198 for(
int j = 0; j < R2.cols; j++)
1201 for(
int i = 0; i < t2.rows; i++)
1203 double* Mi = A.ptr<
double>(i);
1204 double* MRi = t2.ptr<
double>(i);
1207 Mat P3=this->Kright*A;
1208 A= Mat::eye(3,4,CV_64FC1);
1210 for(
int i = 0; i < R1.rows; i++)
1212 double* Mi = A.ptr<
double>(i);
1213 double* MRi = R1.ptr<
double>(i);
1214 for(
int j = 0; j < R1.cols; j++)
1217 for(
int i = 0; i < t1.rows; i++)
1219 double* Mi = A.ptr<
double>(i);
1220 double* MRi = t2.ptr<
double>(i);
1223 Mat P4=this->Kright*A;
1224 A= Mat::eye(3,4,CV_64FC1);
1227 for(
int i = 0; i < R2.rows; i++)
1229 double* Mi = A.ptr<
double>(i);
1230 double* MRi = R2.ptr<
double>(i);
1231 for(
int j = 0; j < R2.cols; j++)
1234 for(
int i = 0; i < t2.rows; i++)
1236 double* Mi = A.ptr<
double>(i);
1237 double* MRi = t1.ptr<
double>(i);
1240 Mat P5=this->Kright*A;
1246 Mat point(4,1,CV_64FC1);
1248 for(
int i=0; i<(int) InliersL.size(); i++)
1251 Mat H1=buildRotTras(R1,t1);
1252 point.at<
double>(0,0)=point3D.x;
1253 point.at<
double>(1,0)=point3D.y;
1254 point.at<
double>(2,0)=point3D.z;
1255 point.at<
double>(0,0)=1.0;
1256 Mat rotatedPoint=H1*point;
1259 if(point3D.z<0 || rotatedPoint.at<
double>(2,0)<0) {
1263 Mat H2=buildRotTras(R2,t2);
1264 point.at<
double>(0,0)=point3D.x;
1265 point.at<
double>(1,0)=point3D.y;
1266 point.at<
double>(2,0)=point3D.z;
1267 point.at<
double>(0,0)=1.0;
1268 rotatedPoint=H2*point;
1271 if(point3D.z<0 || rotatedPoint.at<
double>(2,0)<0) {
1276 Mat H3=buildRotTras(R1,t2);
1277 point.at<
double>(0,0)=point3D.x;
1278 point.at<
double>(1,0)=point3D.y;
1279 point.at<
double>(2,0)=point3D.z;
1280 point.at<
double>(0,0)=1.0;
1281 rotatedPoint=H3*point;
1284 if(point3D.z<0 || rotatedPoint.at<
double>(2,0)<0) {
1289 Mat H4=buildRotTras(R2,t1);
1290 point.at<
double>(0,0)=point3D.x;
1291 point.at<
double>(1,0)=point3D.y;
1292 point.at<
double>(2,0)=point3D.z;
1293 point.at<
double>(0,0)=1.0;
1294 rotatedPoint=H4*point;
1297 if(point3D.z<0 || rotatedPoint.at<
double>(2,0)<0) {
1310 double minErr=10000;
1311 double secondErr=minErr;
1314 if(err1<minErr && t1.ptr<
double>(0)[0]<0)
1321 if(err2<minErr && t2.ptr<
double>(0)[0]<0)
1327 if(err3<minErr && t2.ptr<
double>(0)[0]<0)
1333 if(err4<minErr && t1.ptr<
double>(0)[0]<0)
1373 Mat J=Mat(4,4,CV_64FC1);
1376 for(
int j=0; j<4; j++) {
1381 J.at<
double>(0,j)=(pointleft.x*Camera1.at<
double>(rowB,j))- (Camera1.at<
double>(rowA,j));
1382 J.at<
double>(2,j)=(pointRight.x*Camera2.at<
double>(rowB,j))- (Camera2.at<
double>(rowA,j));
1386 J.at<
double>(1,j)=(pointleft.y*Camera1.at<
double>(rowB,j))- (Camera1.at<
double>(rowA,j));
1387 J.at<
double>(3,j)=(pointRight.y*Camera2.at<
double>(rowB,j))- (Camera2.at<
double>(rowA,j));
1403 point3D.x=(float) ((
float) V.at<
double>(3,0))/((float) V.at<
double>(3,3));
1404 point3D.y=(float) ((
float) V.at<
double>(3,1))/((float) V.at<
double>(3,3));
1405 point3D.z=(float) ((
float) V.at<
double>(3,2))/((float) V.at<
double>(3,3));
1411 double * StereoCamera::reprojectionError(Mat& Rot, Mat& Tras) {
1412 if(PointsL.empty()) {
1413 cout <<
"No keypoints found! Run findMatch first!" << endl;
1417 if(InliersL.empty()) {
1422 Point2f pointL, pointR;
1423 vector<Point3f> WorldPoints;
1424 Mat A = Mat::eye(3, 4, CV_64F);
1425 Mat P1=this->Kleft*A;
1427 for(
int i = 0; i < Rot.rows; i++)
1429 double* Mi = A.ptr<
double>(i);
1430 double* MRi = Rot.ptr<
double>(i);
1431 for(
int j = 0; j < Rot.cols; j++)
1434 for(
int i = 0; i < Tras.rows; i++)
1436 double* Mi = A.ptr<
double>(i);
1437 double* MRi = Tras.ptr<
double>(i);
1440 Mat P2=this->Kright*A;
1442 for(
int i =0; i<(int) this->InliersL.size(); i++) {
1448 WorldPoints.push_back(point3D);
1451 double * err =(
double *) malloc(
sizeof(
double)*2);
1452 vector<Point2f> reprojectionL, reprojectionR;
1454 projectPoints(Mat(WorldPoints), Mat::eye(3,3,CV_64FC1), Mat::zeros(3,1,CV_64FC1), this->Kleft, Mat(), reprojectionL);
1457 projectPoints(Mat(WorldPoints), this->R, this->T, this->Kright, Mat(), reprojectionR);
1459 double errorRight=0;
1460 for(
int i =0; i<(int) WorldPoints.size(); i++) {
1461 errorLeft += pow(sqrt(pow(InliersL[i].x-reprojectionL[i].x,2)+ pow(InliersL[i].y-reprojectionL[i].y,2)),2);
1464 errorRight += pow(sqrt(pow(InliersR[i].x-reprojectionR[i].x,2)+ pow(InliersR[i].y-reprojectionR[i].y,2)),2);
1476 if(this->Kleft.empty() || this->DistL.empty() || this->Kright.empty() || this->DistR.empty()) {
1477 cout <<
" Cameras are not calibrated! Run the Calibration first!" << endl;
1480 if(this->imleft.empty() || this->imright.empty()) {
1481 cout <<
"Images are not set! set the images first!" << endl;
1485 undistort(this->imleft,this->imleftund,this->Kleft,this->DistL);
1486 undistort(this->imright,this->imrightund,this->Kright,this->DistR);
1491 return this->imleftund;
1501 return this->imrightund;
1506 lock_guard<mutex> lg(mtx);
1516 this->updatePMatrix();
1517 this->cameraChanged=
true;
1522 lock_guard<mutex> lg(mtx);
1533 if(!this->Kleft.empty() && !this->Kright.empty())
1534 this->updatePMatrix();
1535 this->cameraChanged=
true;
1539 void StereoCamera::printExtrinsic() {
1540 printMatrix(this->R);
1541 printMatrix(this->T);
1545 void StereoCamera::updateExpectedCameraMatrices()
1547 Mat A = Mat::eye(3, 4, CV_64F);
1550 for(
int i = 0; i < this->R_exp.rows; i++)
1552 double* Mi = A.ptr<
double>(i);
1553 double* MRi = this->R_exp.ptr<
double>(i);
1554 for(
int j = 0; j < this->R_exp.cols; j++)
1557 for(
int i = 0; i < this->T_exp.rows; i++)
1559 double* Mi = A.ptr<
double>(i);
1560 double* MRi = this->T_exp.ptr<
double>(i);
1564 Pright_exp=Kright*A;
1568 void StereoCamera::updatePMatrix()
1570 Mat A = Mat::eye(3, 4, CV_64F);
1573 for(
int i = 0; i < this->R.rows; i++)
1575 double* Mi = A.ptr<
double>(i);
1576 double* MRi = this->R.ptr<
double>(i);
1577 for(
int j = 0; j < this->R.cols; j++)
1580 for(
int i = 0; i < this->T.rows; i++)
1582 double* Mi = A.ptr<
double>(i);
1583 double* MRi = this->T.ptr<
double>(i);
1601 void StereoCamera::crossCheckMatching( cv::BFMatcher &descriptorMatcher,
1602 const Mat& descriptors1,
const Mat& descriptors2,
1603 vector<DMatch>& filteredMatches12,
double radius)
1605 filteredMatches12.clear();
1606 vector<vector<DMatch> > matches12, matches21;
1608 descriptorMatcher.radiusMatch(descriptors1,descriptors2,matches12,(
float)radius);
1609 descriptorMatcher.radiusMatch(descriptors2,descriptors1,matches21,(
float)radius);
1611 for (
size_t m=0; m<matches12.size(); m++)
1613 bool findCrossCheck=
false;
1614 for (
size_t fk=0; fk<matches12[m].size(); fk++)
1616 DMatch forward=matches12[m][fk];
1617 for (
size_t bk=0; bk<matches21[forward.trainIdx].size(); bk++)
1619 DMatch backward=matches21[forward.trainIdx][bk];
1620 if (backward.trainIdx==forward.queryIdx)
1622 filteredMatches12.push_back(forward);
1623 findCrossCheck=
true;
1637 if(this->PointsL.size()<10 || this->PointsR.size()<10) {
1638 cout <<
"No matches found! Run findMatch fist!" << endl;
1643 if(this->Kleft.empty() || this->Kright.empty() || this->R.empty() || this->T.empty()) {
1644 cout <<
"Cameras are empty, run Calibration first" << endl;
1648 if(InliersL.empty()) {
1653 Mat Rot=this->R.clone();
1654 Mat Tras=this->T.clone();
1655 horn(this->Kleft,this->Kright,this->InliersL,this->InliersR,Rot,Tras);
1658 this->R=Rot.clone();
1659 this->Rinit=Rot.clone();
1661 this->T=Tras/norm(Tras)*norm(T);
1662 this->Tinit=Tras/norm(Tras)*norm(Tinit);
1664 this->updatePMatrix();
1670 if (this->imleftund.empty() || this->imrightund.empty())
1677 vector<KeyPoint> keypoints1(InliersL.size());
1678 vector<KeyPoint> keypoints2(InliersL.size());
1679 vector<DMatch> filteredMatches(InliersL.size());
1681 for (
int i=0; i<InliersL.size(); i++)
1683 filteredMatches[i].queryIdx=i;
1684 filteredMatches[i].trainIdx=i;
1686 keypoints1[i]=cv::KeyPoint(InliersL[i],2);
1687 keypoints2[i]=cv::KeyPoint(InliersR[i],2);
1690 cv::drawMatches(this->imleftund,keypoints1,this->imrightund,keypoints2,
1691 filteredMatches,matchImg,Scalar(0,0,255,0),Scalar(0,0,255,0));
1697 void StereoCamera::horn(Mat & K1,Mat & K2, vector<Point2f> & PointsL,vector<Point2f> & PointsR,Mat & Rot,Mat & Tras) {
1698 double prevres = 1E40;
1700 double vanishing = 1E-16;
1701 Tras=Tras/norm(Tras);
1703 normalizePoints(K1,K2,PointsL,PointsR);
1705 Mat B(3,3,CV_64FC1);
1706 Mat C(3,3,CV_64FC1);
1707 Mat D(3,3,CV_64FC1);
1708 Mat cs(3,1,CV_64FC1);
1709 Mat ds(3,1,CV_64FC1);
1710 Mat r1(3,1,CV_64FC1);
1711 Mat r2(3,1,CV_64FC1);
1713 while ( (prevres - res > vanishing) ) {
1724 for(
int i=0; i<(int) PointsL.size(); i++) {
1726 r1.at<
double>(0,0)=PointsL[i].x;
1727 r1.at<
double>(1,0)=PointsL[i].y;
1728 r1.at<
double>(2,0)=1;
1731 r2.at<
double>(0,0)=PointsR[i].x;
1732 r2.at<
double>(1,0)=PointsR[i].y;
1733 r2.at<
double>(2,0)=1;
1739 Mat ci=r1p.cross(r2);
1740 Mat di=r1p.cross(r2.cross(Tras));
1748 cs=cs+ (si.at<
double>(0,0)*ci);
1749 ds=ds+ (si.at<
double>(0,0)*di);
1751 Mat residual=Tras.t()*ci*ci.t()*Tras;
1752 res=res+residual.at<
double>(0,0);
1756 Mat L(7,7,CV_64FC1);
1759 for(
int i=0; i<3; i++)
1760 for(
int j=0; j<3; j++)
1761 L.at<
double>(i,j)=C.at<
double>(i,j);
1763 for(
int i=0; i<3; i++)
1764 for(
int j=3; j<6; j++)
1765 L.at<
double>(i,j)=B.at<
double>(i,j-3);
1767 for(
int i=0; i<3; i++)
1768 L.at<
double>(i,6)=Tras.at<
double>(i,0);
1771 for(
int i=3; i<6; i++)
1772 for(
int j=0; j<3; j++) {
1774 L.at<
double>(i,j)=Bt.at<
double>(i-3,j);
1779 for(
int i=3; i<6; i++)
1780 for(
int j=3; j<6; j++)
1781 L.at<
double>(i,j)=D.at<
double>(i-3,j-3);
1783 for(
int j=0; j<3; j++) {
1785 L.at<
double>(6,j)=Trast.at<
double>(0,j);
1789 Mat Y(7,1,CV_64FC1);
1792 for(
int j=0; j<3; j++)
1793 Y.at<
double>(j,0)=-cs.at<
double>(j,0);
1795 for(
int j=3; j<6; j++)
1796 Y.at<
double>(j,0)=-ds.at<
double>(j-3,0);
1800 Tras=Tras+result(Range(0,3),Range(0,1));
1801 Tras=Tras/norm(Tras);
1803 Mat q(4,1,CV_64FC1);
1805 Mat temp=result(Range(3,6),Range(0,1));
1806 q.at<
double>(0,0)= sqrt(1-(0.25* norm(temp)*norm(temp)));
1807 q.at<
double>(1,0)= 0.5*result.at<
double>(3,0);
1808 q.at<
double>(2,0)= 0.5*result.at<
double>(4,0);
1809 q.at<
double>(3,0)= 0.5*result.at<
double>(5,0);
1812 Mat deltaR(3,3,CV_64FC1);
1819 Mat Id = Mat::eye(3, 3, CV_64F);
1834 double n=q.at<
double>(0,0);
1835 double e1=q.at<
double>(1,0);
1836 double e2=q.at<
double>(2,0);
1837 double e3=q.at<
double>(3,0);
1840 Rot.at<
double>(0,0)= (2*((n*n) + (e1*e1))) - 1;
1841 Rot.at<
double>(0,1)= 2*(e1*e2-n*e3);
1842 Rot.at<
double>(0,2)= 2*(e1*e3+n*e2);
1844 Rot.at<
double>(1,0)= 2*(e1*e2+n*e3);
1845 Rot.at<
double>(1,1)= 2*(n*n+e2*e2)-1;
1846 Rot.at<
double>(1,2)= 2*(e2*e3-n*e1);
1848 Rot.at<
double>(2,0)= 2*(e1*e3-n*e2);
1849 Rot.at<
double>(2,1)= 2*(e2*e3+n*e1);
1850 Rot.at<
double>(2,2)=2*(n*n+e3*e3)-1;
1854 void StereoCamera::normalizePoints(Mat & K1, Mat & K2, vector<Point2f> & PointsL, vector<Point2f> & PointsR) {
1857 Mat Point(3,1,CV_64FC1);
1858 for (
int i=0; i<(int) PointsL.size(); i++) {
1860 Point.at<
double>(0,0)=PointsL[i].x;
1861 Point.at<
double>(1,0)=PointsL[i].y;
1862 Point.at<
double>(2,0)=1;
1864 Mat pnorm=K1.inv()*Point;
1865 pnorm.at<
double>(0,0)=pnorm.at<
double>(0,0)/pnorm.at<
double>(2,0);
1866 pnorm.at<
double>(1,0)=pnorm.at<
double>(1,0)/pnorm.at<
double>(2,0);
1867 pnorm.at<
double>(2,0)=1;
1870 PointsL[i].x=(float) pnorm.at<
double>(0,0);
1871 PointsL[i].y=(float) pnorm.at<
double>(1,0);
1873 Point.at<
double>(0,0)=PointsR[i].x;
1874 Point.at<
double>(1,0)=PointsR[i].y;
1875 Point.at<
double>(2,0)=1;
1877 pnorm=K2.inv()*Point;
1878 pnorm.at<
double>(0,0)=pnorm.at<
double>(0,0)/pnorm.at<
double>(2,0);
1879 pnorm.at<
double>(1,0)=pnorm.at<
double>(1,0)/pnorm.at<
double>(2,0);
1880 pnorm.at<
double>(2,0)=1;
1883 PointsR[i].x=(float) pnorm.at<
double>(0,0);
1884 PointsR[i].y=(float) pnorm.at<
double>(1,0);
1890 void StereoCamera::savePoints(
string pointsLPath,
string pointsRPath, vector<Point2f> PointL, vector<Point2f> PointR) {
1892 myfile.open (pointsLPath.c_str());
1893 for(
int i=0; i<(int) PointL.size(); i++)
1894 myfile << PointL[i].x <<
" " << PointL[i].y <<
"\n";
1897 myfile.open (pointsRPath.c_str());
1898 for(
int i=0; i<(int) PointR.size(); i++)
1899 myfile << PointR[i].x <<
" " << PointR[i].y <<
"\n";
1906 return this->RLrect;
1911 return this->RRrect;
1916 return this->MapperL;
1921 return this->MapperR;
1925 void StereoCamera::printMatrix(Mat &matrix) {
1926 int row=matrix.rows;
1927 int col =matrix.cols;
1929 for(
int i = 0; i < matrix.rows; i++)
1931 const double* Mi = matrix.ptr<
double>(i);
1932 for(
int j = 0; j < matrix.cols; j++)
1933 cout << Mi[j] <<
" ";
1941 lock_guard<mutex> lg(mtx);
1947 if(!this->R.empty() && !this->T.empty())
1949 this->cameraChanged=
true;
1950 buildUndistortRemap();
1955 lock_guard<mutex> lg(mtx);
1957 if(Q.empty() || Disparity16.empty()) {
1958 cout <<
"Run computeDisparity() method first!" << endl;
1966 int u=(int) point1.x;
1967 int v=(
int) point1.y;
1973 if(Mapper.empty()) {
1980 float usign=Mapper.ptr<
float>(v)[2*u];
1981 float vsign=Mapper.ptr<
float>(v)[2*u+1];
1988 if(u<0 || u>=disp16.size().width || v<0 || v>=disp16.size().height) {
1995 CvScalar scal=cvGet2D(&disp16,v,u);
1996 double disparity=scal.val[0]/16.0;
1997 float w= (float) ((
float) disparity*Q.at<
double>(3,2)) + ((float)Q.at<
double>(3,3));
1998 point.x= (float)((
float) (usign+1)*Q.at<
double>(0,0)) + ((
float) Q.at<
double>(0,3));
1999 point.y=(float)((
float) (vsign+1)*Q.at<
double>(1,1)) + ((
float) Q.at<
double>(1,3));
2000 point.z=(float) Q.at<
double>(2,3);
2007 if(point.z>thMeters || point.z<0) {
2013 Mat P(3,1,CV_64FC1);
2014 P.at<
double>(0,0)=point.x;
2015 P.at<
double>(1,0)=point.y;
2016 P.at<
double>(2,0)=point.z;
2019 P=this->getRLrect().t()*P;
2021 point.x=(float) P.at<
double>(0,0);
2022 point.y=(float) P.at<
double>(1,0);
2023 point.z=(float) P.at<
double>(2,0);
2031 lock_guard<mutex> lg(mtx);
2034 H=H.eye(4,4,CV_64FC1);
2036 if(Q.empty() || Disparity16.empty()) {
2037 cout <<
"Run computeDisparity() method first!" << endl;
2045 int u=(int) point1.x;
2046 int v=(
int) point1.y;
2053 if(Mapper.empty()) {
2060 float usign=Mapper.ptr<
float>(v)[2*u];
2061 float vsign=Mapper.ptr<
float>(v)[2*u+1];
2068 if(u<0 || u>=disp16.size().width || v<0 || v>=disp16.size().height) {
2075 CvScalar scal=cvGet2D(&disp16,v,u);
2076 double disparity=scal.val[0]/16.0;
2077 float w= (float) ((
float) disparity*Q.at<
double>(3,2)) + ((float)Q.at<
double>(3,3));
2078 point.x= (float)((
float) (usign+1)*Q.at<
double>(0,0)) + ((
float) Q.at<
double>(0,3));
2079 point.y=(float)((
float) (vsign+1)*Q.at<
double>(1,1)) + ((
float) Q.at<
double>(1,3));
2080 point.z=(float) Q.at<
double>(2,3);
2087 if(point.z>thMeters || point.z<0) {
2095 Mat Tfake = Mat::zeros(0,3,CV_64F);
2096 Mat P(4,1,CV_64FC1);
2097 P.at<
double>(0,0)=point.x;
2098 P.at<
double>(1,0)=point.y;
2099 P.at<
double>(2,0)=point.z;
2100 P.at<
double>(3,0)=1;
2102 Mat Hrect=buildRotTras(RLrectTmp,Tfake);
2105 point.x=(float) ((
float) P.at<
double>(0,0)/P.at<
double>(3,0));
2106 point.y=(float) ((
float) P.at<
double>(1,0)/P.at<
double>(3,0));
2107 point.z=(float) ((
float) P.at<
double>(2,0)/P.at<
double>(3,0));
2115 lock_guard<mutex> lg(mtx);
2118 cout <<
"Run rectifyImages() method first!" << endl;
2127 H=H.eye(4,4,CV_64FC1);
2131 float w= (float) ((
float) d*Q.at<
double>(3,2)) + ((float)Q.at<
double>(3,3));
2132 point.x= (float)((
float) (u)*Q.at<
double>(0,0)) + ((
float) Q.at<
double>(0,3));
2133 point.y=(float)((
float) (v)*Q.at<
double>(1,1)) + ((
float) Q.at<
double>(1,3));
2134 point.z=(float) Q.at<
double>(2,3);
2143 Mat Tfake = Mat::zeros(0,3,CV_64F);
2144 Mat P(4,1,CV_64FC1);
2145 P.at<
double>(0,0)=point.x;
2146 P.at<
double>(1,0)=point.y;
2147 P.at<
double>(2,0)=point.z;
2148 P.at<
double>(3,0)=1;
2150 Mat Hrect=buildRotTras(RLrectTmp,Tfake);
2153 point.x=(float) ((
float) P.at<
double>(0,0)/P.at<
double>(3,0));
2154 point.y=(float) ((
float) P.at<
double>(1,0)/P.at<
double>(3,0));
2155 point.z=(float) ((
float) P.at<
double>(2,0)/P.at<
double>(3,0));
2163 return this->imgLeftRect;
2169 return this->imgRightRect;
2175 vector<Point2f> points2D;
2177 if(this->Kleft.empty() || this->DistL.empty() || this->Kright.empty() || this->DistR.empty()) {
2178 cout <<
" Cameras are not calibrated! Run the Calibration first!" << endl;
2183 H=H.eye(4,4,CV_64FC1);
2185 lock_guard<mutex> lg(mtx);
2186 for (
int i=0; i<points3D.size(); i++)
2189 Point3f point=points3D[i];
2190 Mat P(4,1,CV_64FC1);
2191 P.at<
double>(0,0)=point.x;
2192 P.at<
double>(1,0)=point.y;
2193 P.at<
double>(2,0)=point.z;
2194 P.at<
double>(3,0)=1;
2198 point.x=(float) ((
float) P.at<
double>(0,0)/P.at<
double>(3,0));
2199 point.y=(float) ((
float) P.at<
double>(1,0)/P.at<
double>(3,0));
2200 point.z=(float) ((
float) P.at<
double>(2,0)/P.at<
double>(3,0));
2205 Mat cameraMatrix, distCoeff, rvec, tvec;
2206 rvec=Mat::zeros(3,1,CV_64FC1);
2210 cameraMatrix=this->Kleft;
2211 distCoeff=this->DistL;
2212 Mat R2= Mat::eye(3,3,CV_64FC1);
2214 tvec=Mat::zeros(3,1,CV_64FC1);
2218 cameraMatrix=this->Kright;
2219 distCoeff=this->DistR;
2225 Mat points3Mat(points3D);
2226 projectPoints(points3Mat,rvec,tvec,cameraMatrix,distCoeff,points2D);
2233 Mat worldImg(Disparity16.rows,Disparity16.cols,CV_32FC3);
2236 H=H.eye(4,4,CV_64FC1);
2238 if(Disparity16.empty() || MapperL.empty() || Q.empty())
2240 cout <<
" Run computeDisparity() method first" << endl;
2246 remap(this->Disparity16,dispTemp,this->MapperL,x,cv::INTER_LINEAR);
2247 reprojectImageTo3D(dispTemp, worldImg,this->Q,
true);
2249 for(
int i=0; i<worldImg.rows; i++)
2251 for(
int j=0; j<worldImg.cols; j++)
2254 Mat Tfake = Mat::zeros(0,3,CV_64F);
2255 Mat P(4,1,CV_64FC1);
2256 if((worldImg.data + worldImg.step * i)[j * worldImg.channels() + 2]>100)
2258 P.at<
double>(0,0)=0.0;
2259 P.at<
double>(1,0)=0.0;
2260 P.at<
double>(2,0)=0.0;
2261 P.at<
double>(3,0)=1.0;
2265 P.at<
double>(0,0)=(worldImg.data + worldImg.step * i)[j * worldImg.channels() + 0];
2266 P.at<
double>(1,0)=(worldImg.data + worldImg.step * i)[j * worldImg.channels() + 1];
2267 P.at<
double>(2,0)=(worldImg.data + worldImg.step * i)[j * worldImg.channels() + 2];
2268 P.at<
double>(3,0)=1;
2270 Mat Hrect=buildRotTras(RLrectTmp,Tfake);
2273 (worldImg.data + worldImg.step * i)[j * worldImg.channels() + 0]=(float) ((
float) P.at<
double>(0,0)/P.at<
double>(3,0));
2274 (worldImg.data + worldImg.step * i)[j * worldImg.channels() + 1]=(float) ((
float) P.at<
double>(1,0)/P.at<
double>(3,0));
2275 (worldImg.data + worldImg.step * i)[j * worldImg.channels() + 2]=(float) ((
float) P.at<
double>(2,0)/P.at<
double>(3,0));
2295 void StereoCamera::buildUndistortRemap()
2298 Size img_size = this->imleft.size();
2299 initUndistortRectifyMap(this->Kleft, this->DistL, Mat::eye(3,3,CV_64FC1), newCam, img_size, CV_32FC1,this->mapxL,this->mapyL);
2300 initUndistortRectifyMap(this->Kright, this->DistR, Mat::eye(3,3,CV_64FC1), newCam, img_size, CV_32FC1,this->mapxR,this->mapyR);
2307 Point2f distortedPixel;
2308 Mat MapperX,MapperY;
2320 distortedPixel.x=MapperX.ptr<
float>(v)[u];
2321 distortedPixel.y=MapperY.ptr<
float>(v)[u];
2323 return distortedPixel;
2327 bool StereoCamera::loadStereoParameters(yarp::os::ResourceFinder &rf, Mat &KL, Mat &KR, Mat &DistL, Mat &DistR, Mat &Ro, Mat &T)
2330 Bottle left=rf.findGroup(
"CAMERA_CALIBRATION_LEFT");
2331 if(!left.check(
"fx") || !left.check(
"fy") || !left.check(
"cx") || !left.check(
"cy"))
2334 double fx=left.find(
"fx").asFloat64();
2335 double fy=left.find(
"fy").asFloat64();
2337 double cx=left.find(
"cx").asFloat64();
2338 double cy=left.find(
"cy").asFloat64();
2340 double k1=left.check(
"k1",Value(0)).asFloat64();
2341 double k2=left.check(
"k2",Value(0)).asFloat64();
2343 double p1=left.check(
"p1",Value(0)).asFloat64();
2344 double p2=left.check(
"p2",Value(0)).asFloat64();
2346 DistL=Mat::zeros(1,8,CV_64FC1);
2347 DistL.at<
double>(0,0)=k1;
2348 DistL.at<
double>(0,1)=k2;
2349 DistL.at<
double>(0,2)=p1;
2350 DistL.at<
double>(0,3)=p2;
2353 KL=Mat::eye(3,3,CV_64FC1);
2354 KL.at<
double>(0,0)=fx;
2355 KL.at<
double>(0,2)=cx;
2356 KL.at<
double>(1,1)=fy;
2357 KL.at<
double>(1,2)=cy;
2359 Bottle right=rf.findGroup(
"CAMERA_CALIBRATION_RIGHT");
2360 if(!right.check(
"fx") || !right.check(
"fy") || !right.check(
"cx") || !right.check(
"cy"))
2363 fx=right.find(
"fx").asFloat64();
2364 fy=right.find(
"fy").asFloat64();
2366 cx=right.find(
"cx").asFloat64();
2367 cy=right.find(
"cy").asFloat64();
2369 k1=right.check(
"k1",Value(0)).asFloat64();
2370 k2=right.check(
"k2",Value(0)).asFloat64();
2372 p1=right.check(
"p1",Value(0)).asFloat64();
2373 p2=right.check(
"p2",Value(0)).asFloat64();
2375 DistR=Mat::zeros(1,8,CV_64FC1);
2376 DistR.at<
double>(0,0)=k1;
2377 DistR.at<
double>(0,1)=k2;
2378 DistR.at<
double>(0,2)=p1;
2379 DistR.at<
double>(0,3)=p2;
2382 KR=Mat::eye(3,3,CV_64FC1);
2383 KR.at<
double>(0,0)=fx;
2384 KR.at<
double>(0,2)=cx;
2385 KR.at<
double>(1,1)=fy;
2386 KR.at<
double>(1,2)=cy;
2388 Ro=Mat::zeros(3,3,CV_64FC1);
2389 T=Mat::zeros(3,1,CV_64FC1);
2391 Bottle extrinsics=rf.findGroup(
"STEREO_DISPARITY");
2392 if (Bottle *pXo=extrinsics.find(
"HN").asList()) {
2393 for (
int i=0; i<(pXo->size()-4); i+=4) {
2394 Ro.at<
double>(i/4,0)=pXo->get(i).asFloat64();
2395 Ro.at<
double>(i/4,1)=pXo->get(i+1).asFloat64();
2396 Ro.at<
double>(i/4,2)=pXo->get(i+2).asFloat64();
2397 T.at<
double>(i/4,0)=pXo->get(i+3).asFloat64();
2429 remap(disp,remapped,this->MapperL,x,cv::INTER_LINEAR);
2430 remapped.convertTo(remapped,CV_8U);
2446 std::lock_guard<std::mutex> lock(mtx);
2448 Mat inverseMapL(rows*cols,1,CV_32FC2);
2449 Mat inverseMapR(rows*cols,1,CV_32FC2);
2451 for (
int y=0; y<rows; y++)
2453 for (
int x=0; x<cols; x++)
2455 inverseMapL.ptr<
float>(y*cols+x)[0]=(
float)x;
2456 inverseMapL.ptr<
float>(y*cols+x)[1]=(
float)y;
2457 inverseMapR.ptr<
float>(y*cols+x)[0]=(
float)x;
2458 inverseMapR.ptr<
float>(y*cols+x)[1]=(
float)y;
2462 undistortPoints(inverseMapL,inverseMapL,this->Kleft,this->DistL,this->RLrect,this->PLrect);
2463 undistortPoints(inverseMapR,inverseMapR,this->Kright,this->DistR,this->RRrect,this->PRrect);
2465 Mat mapperL=inverseMapL.reshape(2,rows);
2466 Mat mapperR=inverseMapR.reshape(2,rows);
2467 this->MapperL=mapperL;
2468 this->MapperR=mapperR;
The base class defining a simple camera.
Mat getDistVector()
It returns the 4x1 distortion coefficients.
Mat getCameraMatrix()
It returns the 3x3 camera matrix.
vector< Point2f > projectPoints3D(string camera, vector< Point3f > &points3D, Mat &H)
The method returns the 2D projection of a set of 3D points in the cartesian space to the specified ca...
void initELAS(yarp::os::ResourceFinder &rf)
Initialization of ELAS parameters.
const Mat & getRotation() const
It returns the rotation matrix between the two cameras.
StereoCamera(bool rectify=true)
Default Constructor.
void setRotation(Mat &Rot, int mode=0)
It sets the rotation matrix (if known) between the first and the second camera.
bool essentialDecomposition()
It decomposes the essential matrix in Rotation and Translation between the two views.
const Mat & getImRightUnd() const
It returns the right undistorted image.
void undistortImages()
It undistorts the images.
Point3f metricTriangulation(Point2f &point1, double thMeters=10)
It performs the metric triangulation given the pixel coordinates on the first image.
void hornRelativeOrientations()
It performs the horn relative orientations, all the parameters are assumed initialized in the StereoC...
Point3f triangulation(Point2f &point1, Point2f &point2)
It performs the triangulation using the stored in the internal P1 and P2 3x4 Camera Matrices.
const Mat & getTranslation() const
It returns the translation vector between the two cameras.
Point2f fromRectifiedToOriginal(int u, int v, int camera)
Given the u,v pixel coordinates in the rectified image the method returns the position of the pixel i...
Mat FfromP(Mat &P1, Mat &P2)
The function computes the fundamental matrix starting from known camera matrices.
const Mat & getRRrect() const
It returns the rotation matrix between the original right camera and the rectified right camera.
const Mat & getDisparity16() const
It returns the disparity image.
const Mat & getImLeftUnd() const
It returns the left undistorted image.
Mat computeWorldImage(Mat &H)
The method returns a 3-Channels float image with the world coordinates w.r.t H reference system.
void setIntrinsics(Mat &K1, Mat &K2, Mat &Dist1, Mat &Dist2)
It sets the intrinsic parameters.
const Mat & getDistCoeffRight() const
It returns the 5x1 right distortion coefficients.
void updateMappings()
XXXXXXXXXXXXXXXXXXXX.
Mat drawMatches()
The method returns a 3-Channels 8bit image with the image matches.
const Mat & getKright() const
It returns the 3x3 right camera matrix.
const Mat & getDisparity() const
It returns the disparity image.
Point3f triangulateKnownDisparity(float u, float v, float d, Mat &H)
It performs the metric triangulation given the pixel coordinates on the first image and the disparity...
void computeDisparity(bool best=true, int uniquenessRatio=15, int speckleWindowSize=50, int speckleRange=16, int numberOfDisparities=64, int SADWindowSize=7, int minDisparity=0, int preFilterCap=63, int disp12MaxDiff=0)
It computes the Disparity Map (see stereoDisparity).
void setTranslation(Mat &Tras, int mul=0)
It sets the translation vector (if known) between the first and the second camera.
const Mat & getKleft() const
It returns the 3x3 left camera matrix.
void setExpectedPosition(Mat &Rot, Mat &Tran)
The function set the expected Rotation and Translation parameters for the current image pair.
void saveCalibration(string extrinsicFilePath, string intrinsicFilePath)
It saves the calibration.
const Mat & getQ() const
It returns the 4x4 disparity-to-depth mapping matrix.
const vector< Point2f > & getMatchLeft() const
It returns the pixel coordinates of the matches in the left image.
const Mat & getFundamental() const
It returns the 3x3 fundamental matrix.
void estimateEssential()
It estimates the essential matrix (3x3) E between two views.
const Mat & getRLrect() const
It returns the rotation matrix between the original left camera and the rectified left camera.
const Mat & getImLeft() const
It returns the left (first) image.
const Mat & getMapperR() const
It returns the mapping between the original right camera and the rectified right camera.
const Mat & getImRight() const
It returns the right (second) image.
const vector< Point2f > & getMatchRight() const
It returns the pixel coordinates of the matches in the right image.
cv::Mat remapDisparity(cv::Mat disp)
Remaps the disparity map on the basis of the mapping previously computed.
const Mat & getLRectified() const
The method returns the first rectified image.
void setImages(const Mat &firstImg, const Mat &secondImg)
It stores in memory a couple of images.
void horn(Mat &K1, Mat &K2, vector< Point2f > &Points1, vector< Point2f > &Points2, Mat &Rot, Mat &Tras)
It performs the horn relative orientations algorithm i.e.
const Mat & getMapperL() const
It returns the mapping between the original left camera and the rectified left camera.
void rectifyImages()
The method rectifies the two images: it transform each image plane such that pairs conjugate epipolar...
void setMatches(std::vector< cv::Point2f > &pointsL, std::vector< cv::Point2f > &pointsR)
The function initialize the matches of the current image pair.
cv::Mat findMatch(bool visualize=false, double displacement=20.0, double radius=200.0)
It finds matches between two images.
void chierality(Mat &R1, Mat &R2, Mat &t1, Mat &t2, Mat &R, Mat &t, vector< Point2f > points1, vector< Point2f > points2)
It performs the chierality test: given a couple of rotation matrices, translation vectors and matches...
Point2f getDistortedPixel(int u, int v, int cam=1)
Given the u,v pixel coordinates in the undistorted image the method returns the original position of ...
const Mat & getDistCoeffLeft() const
It returns the 5x1 left distortion coefficients.
const Mat & getRRectified() const
The method returns the second rectified image.