00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rtabmap/core/util2d.h"
00029
00030 #include <rtabmap/utilite/ULogger.h>
00031 #include <rtabmap/utilite/UMath.h>
00032 #include <rtabmap/utilite/UConversion.h>
00033 #include <rtabmap/utilite/UTimer.h>
00034 #include <rtabmap/utilite/UStl.h>
00035 #include <rtabmap/core/util3d_transforms.h>
00036 #include <rtabmap/core/StereoDense.h>
00037 #include <opencv2/calib3d/calib3d.hpp>
00038 #include <opencv2/imgproc/imgproc.hpp>
00039 #include <opencv2/video/tracking.hpp>
00040 #include <opencv2/highgui/highgui.hpp>
00041 #include <map>
00042
00043 namespace rtabmap
00044 {
00045
00046 namespace util2d
00047 {
00048
00049
00050 float ssd(const cv::Mat & windowLeft, const cv::Mat & windowRight)
00051 {
00052 UASSERT_MSG(windowLeft.type() == CV_8UC1 || windowLeft.type() == CV_32FC1 || windowLeft.type() == CV_16SC2, uFormat("Type=%d", windowLeft.type()).c_str());
00053 UASSERT(windowLeft.type() == windowRight.type());
00054 UASSERT_MSG(windowLeft.rows == windowRight.rows, uFormat("%d vs %d", windowLeft.rows, windowRight.rows).c_str());
00055 UASSERT_MSG(windowLeft.cols == windowRight.cols, uFormat("%d vs %d", windowLeft.cols, windowRight.cols).c_str());
00056
00057 float score = 0.0f;
00058 for(int v=0; v<windowLeft.rows; ++v)
00059 {
00060 for(int u=0; u<windowLeft.cols; ++u)
00061 {
00062 float s = 0.0f;
00063 if(windowLeft.type() == CV_8UC1)
00064 {
00065 s = float(windowLeft.at<unsigned char>(v,u))-float(windowRight.at<unsigned char>(v,u));
00066 }
00067 else if(windowLeft.type() == CV_32FC1)
00068 {
00069 s = windowLeft.at<float>(v,u)-windowRight.at<float>(v,u);
00070 }
00071 else if(windowLeft.type() == CV_16SC2)
00072 {
00073 float sL = float(windowLeft.at<cv::Vec2s>(v,u)[0])*0.5f+float(windowLeft.at<cv::Vec2s>(v,u)[1])*0.5f;
00074 float sR = float(windowRight.at<cv::Vec2s>(v,u)[0])*0.5f+float(windowRight.at<cv::Vec2s>(v,u)[1])*0.5f;
00075 s = sL - sR;
00076 }
00077
00078 score += s*s;
00079 }
00080 }
00081 return score;
00082 }
00083
00084
00085 float sad(const cv::Mat & windowLeft, const cv::Mat & windowRight)
00086 {
00087 UASSERT_MSG(windowLeft.type() == CV_8UC1 || windowLeft.type() == CV_32FC1 || windowLeft.type() == CV_16SC2, uFormat("Type=%d", windowLeft.type()).c_str());
00088 UASSERT(windowLeft.type() == windowRight.type());
00089 UASSERT_MSG(windowLeft.rows == windowRight.rows, uFormat("%d vs %d", windowLeft.rows, windowRight.rows).c_str());
00090 UASSERT_MSG(windowLeft.cols == windowRight.cols, uFormat("%d vs %d", windowLeft.cols, windowRight.cols).c_str());
00091
00092 float score = 0.0f;
00093 for(int v=0; v<windowLeft.rows; ++v)
00094 {
00095 for(int u=0; u<windowLeft.cols; ++u)
00096 {
00097 if(windowLeft.type() == CV_8UC1)
00098 {
00099 score += fabs(float(windowLeft.at<unsigned char>(v,u))-float(windowRight.at<unsigned char>(v,u)));
00100 }
00101 else if(windowLeft.type() == CV_32FC1)
00102 {
00103 score += fabs(windowLeft.at<float>(v,u)-windowRight.at<float>(v,u));
00104 }
00105 else if(windowLeft.type() == CV_16SC2)
00106 {
00107 float sL = float(windowLeft.at<cv::Vec2s>(v,u)[0])*0.5f+float(windowLeft.at<cv::Vec2s>(v,u)[1])*0.5f;
00108 float sR = float(windowRight.at<cv::Vec2s>(v,u)[0])*0.5f+float(windowRight.at<cv::Vec2s>(v,u)[1])*0.5f;
00109 score += fabs(sL - sR);
00110 }
00111 }
00112 }
00113 return score;
00114 }
00115
00116 std::vector<cv::Point2f> calcStereoCorrespondences(
00117 const cv::Mat & leftImage,
00118 const cv::Mat & rightImage,
00119 const std::vector<cv::Point2f> & leftCorners,
00120 std::vector<unsigned char> & status,
00121 cv::Size winSize,
00122 int maxLevel,
00123 int iterations,
00124 int minDisparity,
00125 int maxDisparity,
00126 bool ssdApproach)
00127 {
00128 UDEBUG("winSize=(%d,%d)", winSize.width, winSize.height);
00129 UDEBUG("maxLevel=%d", maxLevel);
00130 UDEBUG("minDisparity=%d", minDisparity);
00131 UDEBUG("maxDisparity=%d", maxDisparity);
00132 UDEBUG("iterations=%d", iterations);
00133 UDEBUG("ssdApproach=%d", ssdApproach?1:0);
00134
00135
00136 if(winSize.width%2 == 0)
00137 {
00138 winSize.width+=1;
00139 }
00140 if(winSize.height%2 == 0)
00141 {
00142 winSize.height+=1;
00143 }
00144
00145 cv::Size halfWin((winSize.width-1)/2, (winSize.height-1)/2);
00146
00147 UTimer timer;
00148 double pyramidTime = 0.0;
00149 double disparityTime = 0.0;
00150 double subpixelTime = 0.0;
00151
00152 std::vector<cv::Point2f> rightCorners(leftCorners.size());
00153 std::vector<cv::Mat> leftPyramid, rightPyramid;
00154 maxLevel = cv::buildOpticalFlowPyramid( leftImage, leftPyramid, winSize, maxLevel, false);
00155 maxLevel = cv::buildOpticalFlowPyramid( rightImage, rightPyramid, winSize, maxLevel, false);
00156 pyramidTime = timer.ticks();
00157
00158 status = std::vector<unsigned char>(leftCorners.size(), 0);
00159 int totalIterations = 0;
00160 int noSubPixel = 0;
00161 int added = 0;
00162 for(unsigned int i=0; i<leftCorners.size(); ++i)
00163 {
00164 int oi=0;
00165 float bestScore = -1.0f;
00166 int bestScoreIndex = -1;
00167 int tmpMinDisparity = minDisparity;
00168 int tmpMaxDisparity = maxDisparity;
00169
00170 int iterations = 0;
00171 for(int level=maxLevel; level>=0; --level)
00172 {
00173 UASSERT(level < (int)leftPyramid.size());
00174
00175 cv::Point2i center(int(leftCorners[i].x/float(1<<level)), int(leftCorners[i].y/float(1<<level)));
00176
00177 oi=0;
00178 bestScore = -1.0f;
00179 bestScoreIndex = -1;
00180 int localMaxDisparity = -tmpMaxDisparity / (1<<level);
00181 int localMinDisparity = -tmpMinDisparity / (1<<level);
00182
00183 if(center.x-halfWin.width-(level==0?1:0) >=0 && center.x+halfWin.width+(level==0?1:0) < leftPyramid[level].cols &&
00184 center.y-halfWin.height >=0 && center.y+halfWin.height < leftPyramid[level].rows)
00185 {
00186 cv::Mat windowLeft(leftPyramid[level],
00187 cv::Range(center.y-halfWin.height,center.y+halfWin.height+1),
00188 cv::Range(center.x-halfWin.width,center.x+halfWin.width+1));
00189 int minCol = center.x+localMaxDisparity-halfWin.width-1;
00190 if(minCol < 0)
00191 {
00192 localMaxDisparity -= minCol;
00193 }
00194
00195 int maxCol = center.x+localMinDisparity+halfWin.width+1;
00196 if(maxCol >= leftPyramid[level].cols)
00197 {
00198 localMinDisparity += maxCol-leftPyramid[level].cols-1;
00199 }
00200
00201 if(localMinDisparity < localMaxDisparity)
00202 {
00203 localMaxDisparity = localMinDisparity;
00204 }
00205 int length = localMinDisparity-localMaxDisparity+1;
00206 std::vector<float> scores = std::vector<float>(length, 0.0f);
00207
00208 for(int d=localMinDisparity; d>localMaxDisparity; --d)
00209 {
00210 ++iterations;
00211 cv::Mat windowRight(rightPyramid[level],
00212 cv::Range(center.y-halfWin.height,center.y+halfWin.height+1),
00213 cv::Range(center.x+d-halfWin.width,center.x+d+halfWin.width+1));
00214 scores[oi] = ssdApproach?ssd(windowLeft, windowRight):sad(windowLeft, windowRight);
00215 if(scores[oi] > 0 && (bestScore < 0.0f || scores[oi] < bestScore))
00216 {
00217 bestScoreIndex = oi;
00218 bestScore = scores[oi];
00219 }
00220 ++oi;
00221 }
00222
00223 if(bestScoreIndex>=0)
00224 {
00225 if(level>0)
00226 {
00227 tmpMaxDisparity = tmpMinDisparity+(bestScoreIndex+1)*(1<<level);
00228 tmpMaxDisparity+=tmpMaxDisparity%level;
00229 if(tmpMaxDisparity > maxDisparity)
00230 {
00231 tmpMaxDisparity = maxDisparity;
00232 }
00233 tmpMinDisparity = tmpMinDisparity+(bestScoreIndex-1)*(1<<level);
00234 tmpMinDisparity -= tmpMinDisparity%level;
00235 if(tmpMinDisparity < minDisparity)
00236 {
00237 tmpMinDisparity = minDisparity;
00238 }
00239 }
00240 }
00241 }
00242 }
00243 disparityTime+=timer.ticks();
00244 totalIterations+=iterations;
00245
00246 if(bestScoreIndex>=0)
00247 {
00248
00249 int d = -(tmpMinDisparity+bestScoreIndex);
00250
00251 cv::Mat windowLeft(winSize, CV_32FC1);
00252 cv::Mat windowRight(winSize, CV_32FC1);
00253 cv::getRectSubPix(leftPyramid[0],
00254 winSize,
00255 leftCorners[i],
00256 windowLeft,
00257 windowLeft.type());
00258 if(leftCorners[i].x != float(int(leftCorners[i].x)))
00259 {
00260
00261 cv::getRectSubPix(rightPyramid[0],
00262 winSize,
00263 cv::Point2f(leftCorners[i].x+float(d), leftCorners[i].y),
00264 windowRight,
00265 windowRight.type());
00266 bestScore = ssdApproach?ssd(windowLeft, windowRight):sad(windowLeft, windowRight);
00267 }
00268
00269 float xc = leftCorners[i].x+float(d);
00270 float vc = bestScore;
00271 float step = 0.5f;
00272 std::map<float, float> cache;
00273 bool reject = false;
00274 for(int it=0; it<iterations; ++it)
00275 {
00276 float x1 = xc-step;
00277 float x2 = xc+step;
00278 float v1 = uValue(cache, x1, 0.0f);
00279 float v2 = uValue(cache, x2, 0.0f);
00280 if(v1 == 0.0f)
00281 {
00282 cv::getRectSubPix(rightPyramid[0],
00283 winSize,
00284 cv::Point2f(x1, leftCorners[i].y),
00285 windowRight,
00286 windowRight.type());
00287 v1 = ssdApproach?ssd(windowLeft, windowRight):sad(windowLeft, windowRight);
00288 }
00289 if(v2 == 0.0f)
00290 {
00291 cv::getRectSubPix(rightPyramid[0],
00292 winSize,
00293 cv::Point2f(x2, leftCorners[i].y),
00294 windowRight,
00295 windowRight.type());
00296 v2 = ssdApproach?ssd(windowLeft, windowRight):sad(windowLeft, windowRight);
00297 }
00298
00299 float previousXc = xc;
00300 float previousVc = vc;
00301
00302 xc = v1<vc&&v1<v2?x1:v2<vc&&v2<v1?x2:xc;
00303 vc = v1<vc&&v1<v2?v1:v2<vc&&v2<v1?v2:vc;
00304
00305 if(previousXc == xc)
00306 {
00307 step /= 2.0f;
00308 }
00309 else
00310 {
00311 cache.insert(std::make_pair(previousXc, previousVc));
00312 }
00313
00314 if(xc < leftCorners[i].x+float(d)-1.0f || xc > leftCorners[i].x+float(d)+1.0f)
00315 {
00316 reject = true;
00317 break;
00318 }
00319 }
00320
00321 rightCorners[i] = cv::Point2f(xc, leftCorners[i].y);
00322 status[i] = reject?0:1;
00323 if(!reject)
00324 {
00325 if(leftCorners[i].x+float(d) != xc)
00326 {
00327 ++noSubPixel;
00328 }
00329 ++added;
00330 }
00331 }
00332 subpixelTime+=timer.ticks();
00333 }
00334 UDEBUG("SubPixel=%d/%d added (total=%d)", noSubPixel, added, (int)status.size());
00335 UDEBUG("totalIterations=%d", totalIterations);
00336 UDEBUG("Time pyramid = %f s", pyramidTime);
00337 UDEBUG("Time disparity = %f s", disparityTime);
00338 UDEBUG("Time sub-pixel = %f s", subpixelTime);
00339
00340 return rightCorners;
00341 }
00342
00343 typedef float acctype;
00344 typedef float itemtype;
00345 #define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 void calcOpticalFlowPyrLKStereo( cv::InputArray _prevImg, cv::InputArray _nextImg,
00359 cv::InputArray _prevPts, cv::InputOutputArray _nextPts,
00360 cv::OutputArray _status, cv::OutputArray _err,
00361 cv::Size winSize, int maxLevel,
00362 cv::TermCriteria criteria,
00363 int flags, double minEigThreshold )
00364 {
00365 cv::Mat prevPtsMat = _prevPts.getMat();
00366 const int derivDepth = cv::DataType<short>::depth;
00367
00368 CV_Assert( maxLevel >= 0 && winSize.width > 2 && winSize.height > 2 );
00369
00370 int level=0, i, npoints;
00371 CV_Assert( (npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0 );
00372
00373 if( npoints == 0 )
00374 {
00375 _nextPts.release();
00376 _status.release();
00377 _err.release();
00378 return;
00379 }
00380
00381 if( !(flags & cv::OPTFLOW_USE_INITIAL_FLOW) )
00382 _nextPts.create(prevPtsMat.size(), prevPtsMat.type(), -1, true);
00383
00384 cv::Mat nextPtsMat = _nextPts.getMat();
00385 CV_Assert( nextPtsMat.checkVector(2, CV_32F, true) == npoints );
00386
00387 const cv::Point2f* prevPts = prevPtsMat.ptr<cv::Point2f>();
00388 cv::Point2f* nextPts = nextPtsMat.ptr<cv::Point2f>();
00389
00390 _status.create((int)npoints, 1, CV_8U, -1, true);
00391 cv::Mat statusMat = _status.getMat(), errMat;
00392 CV_Assert( statusMat.isContinuous() );
00393 uchar* status = statusMat.ptr();
00394 float* err = 0;
00395
00396 for( i = 0; i < npoints; i++ )
00397 status[i] = true;
00398
00399 if( _err.needed() )
00400 {
00401 _err.create((int)npoints, 1, CV_32F, -1, true);
00402 errMat = _err.getMat();
00403 CV_Assert( errMat.isContinuous() );
00404 err = errMat.ptr<float>();
00405 }
00406
00407 std::vector<cv::Mat> prevPyr, nextPyr;
00408 int levels1 = -1;
00409 int lvlStep1 = 1;
00410 int levels2 = -1;
00411 int lvlStep2 = 1;
00412
00413
00414 if(_prevImg.kind() != cv::_InputArray::STD_VECTOR_MAT)
00415 {
00416
00417 maxLevel = cv::buildOpticalFlowPyramid(_prevImg, prevPyr, winSize, maxLevel, true);
00418 }
00419 else if(_prevImg.kind() == cv::_InputArray::STD_VECTOR_MAT)
00420 {
00421 _prevImg.getMatVector(prevPyr);
00422 }
00423
00424 levels1 = int(prevPyr.size()) - 1;
00425 CV_Assert(levels1 >= 0);
00426
00427 if (levels1 % 2 == 1 && prevPyr[0].channels() * 2 == prevPyr[1].channels() && prevPyr[1].depth() == derivDepth)
00428 {
00429 lvlStep1 = 2;
00430 levels1 /= 2;
00431 }
00432
00433
00434 if(levels1 > 0)
00435 {
00436 cv::Size fullSize;
00437 cv::Point ofs;
00438 prevPyr[lvlStep1].locateROI(fullSize, ofs);
00439 CV_Assert(ofs.x >= winSize.width && ofs.y >= winSize.height
00440 && ofs.x + prevPyr[lvlStep1].cols + winSize.width <= fullSize.width
00441 && ofs.y + prevPyr[lvlStep1].rows + winSize.height <= fullSize.height);
00442 }
00443
00444 if(levels1 < maxLevel)
00445 maxLevel = levels1;
00446
00447 if(_nextImg.kind() != cv::_InputArray::STD_VECTOR_MAT)
00448 {
00449
00450 maxLevel = cv::buildOpticalFlowPyramid(_nextImg, nextPyr, winSize, maxLevel, false);
00451 }
00452 else if(_nextImg.kind() == cv::_InputArray::STD_VECTOR_MAT)
00453 {
00454 _nextImg.getMatVector(nextPyr);
00455 }
00456
00457 levels2 = int(nextPyr.size()) - 1;
00458 CV_Assert(levels2 >= 0);
00459
00460 if (levels2 % 2 == 1 && nextPyr[0].channels() * 2 == nextPyr[1].channels() && nextPyr[1].depth() == derivDepth)
00461 {
00462 lvlStep2 = 2;
00463 levels2 /= 2;
00464 }
00465
00466
00467 if(levels2 > 0)
00468 {
00469 cv::Size fullSize;
00470 cv::Point ofs;
00471 nextPyr[lvlStep2].locateROI(fullSize, ofs);
00472 CV_Assert(ofs.x >= winSize.width && ofs.y >= winSize.height
00473 && ofs.x + nextPyr[lvlStep2].cols + winSize.width <= fullSize.width
00474 && ofs.y + nextPyr[lvlStep2].rows + winSize.height <= fullSize.height);
00475 }
00476
00477 if(levels2 < maxLevel)
00478 maxLevel = levels2;
00479
00480 if( (criteria.type & cv::TermCriteria::COUNT) == 0 )
00481 criteria.maxCount = 30;
00482 else
00483 criteria.maxCount = std::min(std::max(criteria.maxCount, 0), 100);
00484 if( (criteria.type & cv::TermCriteria::EPS) == 0 )
00485 criteria.epsilon = 0.01;
00486 else
00487 criteria.epsilon = std::min(std::max(criteria.epsilon, 0.), 10.);
00488 criteria.epsilon *= criteria.epsilon;
00489
00490
00491 for( level = maxLevel; level >= 0; level-- )
00492 {
00493 cv::Mat derivI = prevPyr[level * lvlStep1 + 1];
00494
00495 CV_Assert(prevPyr[level * lvlStep1].size() == nextPyr[level * lvlStep2].size());
00496 CV_Assert(prevPyr[level * lvlStep1].type() == nextPyr[level * lvlStep2].type());
00497
00498 const cv::Mat & prevImg = prevPyr[level * lvlStep1];
00499 const cv::Mat & prevDeriv = derivI;
00500 const cv::Mat & nextImg = nextPyr[level * lvlStep2];
00501
00502
00503 {
00504 cv::Point2f halfWin((winSize.width-1)*0.5f, (winSize.height-1)*0.5f);
00505 const cv::Mat& I = prevImg;
00506 const cv::Mat& J = nextImg;
00507 const cv::Mat& derivI = prevDeriv;
00508
00509 int j, cn = I.channels(), cn2 = cn*2;
00510 cv::AutoBuffer<short> _buf(winSize.area()*(cn + cn2));
00511 int derivDepth = cv::DataType<short>::depth;
00512
00513 cv::Mat IWinBuf(winSize, CV_MAKETYPE(derivDepth, cn), (short*)_buf);
00514 cv::Mat derivIWinBuf(winSize, CV_MAKETYPE(derivDepth, cn2), (short*)_buf + winSize.area()*cn);
00515
00516 for( int ptidx = 0; ptidx < npoints; ptidx++ )
00517 {
00518 cv::Point2f prevPt = prevPts[ptidx]*(float)(1./(1 << level));
00519 cv::Point2f nextPt;
00520 if( level == maxLevel )
00521 {
00522 if( flags & cv::OPTFLOW_USE_INITIAL_FLOW )
00523 nextPt = nextPts[ptidx]*(float)(1./(1 << level));
00524 else
00525 nextPt = prevPt;
00526 }
00527 else
00528 nextPt = nextPts[ptidx]*2.f;
00529 nextPts[ptidx] = nextPt;
00530
00531 cv::Point2i iprevPt, inextPt;
00532 prevPt -= halfWin;
00533 iprevPt.x = cvFloor(prevPt.x);
00534 iprevPt.y = cvFloor(prevPt.y);
00535
00536 if( iprevPt.x < -winSize.width || iprevPt.x >= derivI.cols ||
00537 iprevPt.y < -winSize.height || iprevPt.y >= derivI.rows )
00538 {
00539 if( level == 0 )
00540 {
00541 if( status )
00542 status[ptidx] = false;
00543 if( err )
00544 err[ptidx] = 0;
00545 }
00546 continue;
00547 }
00548
00549 float a = prevPt.x - iprevPt.x;
00550 float b = prevPt.y - iprevPt.y;
00551 const int W_BITS = 14, W_BITS1 = 14;
00552 const float FLT_SCALE = 1.f/(1 << 20);
00553 int iw00 = cvRound((1.f - a)*(1.f - b)*(1 << W_BITS));
00554 int iw01 = cvRound(a*(1.f - b)*(1 << W_BITS));
00555 int iw10 = cvRound((1.f - a)*b*(1 << W_BITS));
00556 int iw11 = (1 << W_BITS) - iw00 - iw01 - iw10;
00557
00558 int dstep = (int)(derivI.step/derivI.elemSize1());
00559 int stepI = (int)(I.step/I.elemSize1());
00560 int stepJ = (int)(J.step/J.elemSize1());
00561 acctype iA11 = 0, iA12 = 0, iA22 = 0;
00562 float A11, A12, A22;
00563
00564
00565 int x, y;
00566 for( y = 0; y < winSize.height; y++ )
00567 {
00568 const uchar* src = I.ptr() + (y + iprevPt.y)*stepI + iprevPt.x*cn;
00569 const short* dsrc = derivI.ptr<short>() + (y + iprevPt.y)*dstep + iprevPt.x*cn2;
00570
00571 short* Iptr = IWinBuf.ptr<short>(y);
00572 short* dIptr = derivIWinBuf.ptr<short>(y);
00573
00574 x = 0;
00575
00576 for( ; x < winSize.width*cn; x++, dsrc += 2, dIptr += 2 )
00577 {
00578 int ival = CV_DESCALE(src[x]*iw00 + src[x+cn]*iw01 +
00579 src[x+stepI]*iw10 + src[x+stepI+cn]*iw11, W_BITS1-5);
00580 int ixval = CV_DESCALE(dsrc[0]*iw00 + dsrc[cn2]*iw01 +
00581 dsrc[dstep]*iw10 + dsrc[dstep+cn2]*iw11, W_BITS1);
00582 int iyval = CV_DESCALE(dsrc[1]*iw00 + dsrc[cn2+1]*iw01 + dsrc[dstep+1]*iw10 +
00583 dsrc[dstep+cn2+1]*iw11, W_BITS1);
00584
00585 Iptr[x] = (short)ival;
00586 dIptr[0] = (short)ixval;
00587 dIptr[1] = (short)iyval;
00588
00589 iA11 += (itemtype)(ixval*ixval);
00590 iA12 += (itemtype)(ixval*iyval);
00591 iA22 += (itemtype)(iyval*iyval);
00592 }
00593 }
00594
00595 A11 = iA11*FLT_SCALE;
00596 A12 = iA12*FLT_SCALE;
00597 A22 = iA22*FLT_SCALE;
00598
00599 float D = A11*A22 - A12*A12;
00600 float minEig = (A22 + A11 - std::sqrt((A11-A22)*(A11-A22) +
00601 4.f*A12*A12))/(2*winSize.width*winSize.height);
00602
00603 if( err && (flags & cv::OPTFLOW_LK_GET_MIN_EIGENVALS) != 0 )
00604 err[ptidx] = (float)minEig;
00605
00606 if( minEig < minEigThreshold || D < FLT_EPSILON )
00607 {
00608 if( level == 0 && status )
00609 status[ptidx] = false;
00610 continue;
00611 }
00612
00613 D = 1.f/D;
00614
00615 nextPt -= halfWin;
00616 cv::Point2f prevDelta;
00617
00618 for( j = 0; j < criteria.maxCount; j++ )
00619 {
00620 inextPt.x = cvFloor(nextPt.x);
00621 inextPt.y = cvFloor(nextPt.y);
00622
00623 if( inextPt.x < -winSize.width || inextPt.x >= J.cols ||
00624 inextPt.y < -winSize.height || inextPt.y >= J.rows )
00625 {
00626 if( level == 0 && status )
00627 status[ptidx] = false;
00628 break;
00629 }
00630
00631 a = nextPt.x - inextPt.x;
00632 b = nextPt.y - inextPt.y;
00633 iw00 = cvRound((1.f - a)*(1.f - b)*(1 << W_BITS));
00634 iw01 = cvRound(a*(1.f - b)*(1 << W_BITS));
00635 iw10 = cvRound((1.f - a)*b*(1 << W_BITS));
00636 iw11 = (1 << W_BITS) - iw00 - iw01 - iw10;
00637 acctype ib1 = 0, ib2 = 0;
00638 float b1, b2;
00639
00640 for( y = 0; y < winSize.height; y++ )
00641 {
00642 const uchar* Jptr = J.ptr() + (y + inextPt.y)*stepJ + inextPt.x*cn;
00643 const short* Iptr = IWinBuf.ptr<short>(y);
00644 const short* dIptr = derivIWinBuf.ptr<short>(y);
00645
00646 x = 0;
00647
00648 for( ; x < winSize.width*cn; x++, dIptr += 2 )
00649 {
00650 int diff = CV_DESCALE(Jptr[x]*iw00 + Jptr[x+cn]*iw01 +
00651 Jptr[x+stepJ]*iw10 + Jptr[x+stepJ+cn]*iw11,
00652 W_BITS1-5) - Iptr[x];
00653 ib1 += (itemtype)(diff*dIptr[0]);
00654 ib2 += (itemtype)(diff*dIptr[1]);
00655 }
00656 }
00657
00658 b1 = ib1*FLT_SCALE;
00659 b2 = ib2*FLT_SCALE;
00660
00661 cv::Point2f delta( (float)((A12*b2 - A22*b1) * D),
00662 0);
00663
00664
00665 nextPt += delta;
00666 nextPts[ptidx] = nextPt + halfWin;
00667
00668 if( delta.ddot(delta) <= criteria.epsilon )
00669 break;
00670
00671 if( j > 0 && std::abs(delta.x + prevDelta.x) < 0.01 &&
00672 std::abs(delta.y + prevDelta.y) < 0.01 )
00673 {
00674 nextPts[ptidx] -= delta*0.5f;
00675 break;
00676 }
00677 prevDelta = delta;
00678 }
00679
00680 if( status[ptidx] && err && level == 0 && (flags & cv::OPTFLOW_LK_GET_MIN_EIGENVALS) == 0 )
00681 {
00682 cv::Point2f nextPoint = nextPts[ptidx] - halfWin;
00683 cv::Point inextPoint;
00684
00685 inextPoint.x = cvFloor(nextPoint.x);
00686 inextPoint.y = cvFloor(nextPoint.y);
00687
00688 if( inextPoint.x < -winSize.width || inextPoint.x >= J.cols ||
00689 inextPoint.y < -winSize.height || inextPoint.y >= J.rows )
00690 {
00691 if( status )
00692 status[ptidx] = false;
00693 continue;
00694 }
00695
00696 float aa = nextPoint.x - inextPoint.x;
00697 float bb = nextPoint.y - inextPoint.y;
00698 iw00 = cvRound((1.f - aa)*(1.f - bb)*(1 << W_BITS));
00699 iw01 = cvRound(aa*(1.f - bb)*(1 << W_BITS));
00700 iw10 = cvRound((1.f - aa)*bb*(1 << W_BITS));
00701 iw11 = (1 << W_BITS) - iw00 - iw01 - iw10;
00702 float errval = 0.f;
00703
00704 for( y = 0; y < winSize.height; y++ )
00705 {
00706 const uchar* Jptr = J.ptr() + (y + inextPoint.y)*stepJ + inextPoint.x*cn;
00707 const short* Iptr = IWinBuf.ptr<short>(y);
00708
00709 for( x = 0; x < winSize.width*cn; x++ )
00710 {
00711 int diff = CV_DESCALE(Jptr[x]*iw00 + Jptr[x+cn]*iw01 +
00712 Jptr[x+stepJ]*iw10 + Jptr[x+stepJ+cn]*iw11,
00713 W_BITS1-5) - Iptr[x];
00714 errval += std::abs((float)diff);
00715 }
00716 }
00717 err[ptidx] = errval * 1.f/(32*winSize.width*cn*winSize.height);
00718 }
00719 }
00720 }
00721
00722 }
00723 }
00724
00725 cv::Mat disparityFromStereoImages(
00726 const cv::Mat & leftImage,
00727 const cv::Mat & rightImage,
00728 const ParametersMap & parameters)
00729 {
00730 UASSERT(!leftImage.empty() && !rightImage.empty());
00731 UASSERT(leftImage.cols == rightImage.cols && leftImage.rows == rightImage.rows);
00732 UASSERT((leftImage.type() == CV_8UC1 || leftImage.type() == CV_8UC3) && rightImage.type() == CV_8UC1);
00733
00734 cv::Mat leftMono;
00735 if(leftImage.channels() == 3)
00736 {
00737 cv::cvtColor(leftImage, leftMono, CV_BGR2GRAY);
00738 }
00739 else
00740 {
00741 leftMono = leftImage;
00742 }
00743 cv::Mat disparity;
00744
00745 StereoBM stereo(parameters);
00746 return stereo.computeDisparity(leftMono, rightImage);
00747 }
00748
00749 cv::Mat depthFromDisparity(const cv::Mat & disparity,
00750 float fx, float baseline,
00751 int type)
00752 {
00753 UASSERT(!disparity.empty() && (disparity.type() == CV_32FC1 || disparity.type() == CV_16SC1));
00754 UASSERT(type == CV_32FC1 || type == CV_16UC1);
00755 cv::Mat depth = cv::Mat::zeros(disparity.rows, disparity.cols, type);
00756 int countOverMax = 0;
00757 for (int i = 0; i < disparity.rows; i++)
00758 {
00759 for (int j = 0; j < disparity.cols; j++)
00760 {
00761 float disparity_value = disparity.type() == CV_16SC1?float(disparity.at<short>(i,j))/16.0f:disparity.at<float>(i,j);
00762 if (disparity_value > 0.0f)
00763 {
00764
00765 float d = baseline * fx / disparity_value;
00766 if(d>0)
00767 {
00768 if(depth.type() == CV_32FC1)
00769 {
00770 depth.at<float>(i,j) = d;
00771 }
00772 else
00773 {
00774 if(d*1000.0f <= (float)USHRT_MAX)
00775 {
00776 depth.at<unsigned short>(i,j) = (unsigned short)(d*1000.0f);
00777 }
00778 else
00779 {
00780 ++countOverMax;
00781 }
00782 }
00783 }
00784 }
00785 }
00786 }
00787 if(countOverMax)
00788 {
00789 UWARN("Depth conversion error, %d depth values ignored because they are over the maximum depth allowed (65535 mm).", countOverMax);
00790 }
00791 return depth;
00792 }
00793
00794 cv::Mat depthFromStereoImages(
00795 const cv::Mat & leftImage,
00796 const cv::Mat & rightImage,
00797 const std::vector<cv::Point2f> & leftCorners,
00798 float fx,
00799 float baseline,
00800 int flowWinSize,
00801 int flowMaxLevel,
00802 int flowIterations,
00803 double flowEps)
00804 {
00805 UASSERT(!leftImage.empty() && !rightImage.empty() &&
00806 leftImage.type() == CV_8UC1 && rightImage.type() == CV_8UC1 &&
00807 leftImage.cols == rightImage.cols &&
00808 leftImage.rows == rightImage.rows);
00809 UASSERT(fx > 0.0f && baseline > 0.0f);
00810
00811
00812 std::vector<unsigned char> status;
00813 std::vector<float> err;
00814 std::vector<cv::Point2f> rightCorners;
00815 UDEBUG("cv::calcOpticalFlowPyrLK() begin");
00816 cv::calcOpticalFlowPyrLK(
00817 leftImage,
00818 rightImage,
00819 leftCorners,
00820 rightCorners,
00821 status,
00822 err,
00823 cv::Size(flowWinSize, flowWinSize), flowMaxLevel,
00824 cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, flowIterations, flowEps),
00825 cv::OPTFLOW_LK_GET_MIN_EIGENVALS, 1e-4);
00826 UDEBUG("cv::calcOpticalFlowPyrLK() end");
00827
00828 return depthFromStereoCorrespondences(leftImage, leftCorners, rightCorners, status, fx, baseline);
00829 }
00830
00831 cv::Mat disparityFromStereoCorrespondences(
00832 const cv::Size & disparitySize,
00833 const std::vector<cv::Point2f> & leftCorners,
00834 const std::vector<cv::Point2f> & rightCorners,
00835 const std::vector<unsigned char> & mask)
00836 {
00837 UASSERT(leftCorners.size() == rightCorners.size());
00838 UASSERT(mask.size() == 0 || mask.size() == leftCorners.size());
00839 cv::Mat disparity = cv::Mat::zeros(disparitySize, CV_32FC1);
00840 for(unsigned int i=0; i<leftCorners.size(); ++i)
00841 {
00842 if(mask.empty() || mask[i])
00843 {
00844 cv::Point2i dispPt(int(leftCorners[i].y+0.5f), int(leftCorners[i].x+0.5f));
00845 UASSERT(dispPt.x >= 0 && dispPt.x < disparitySize.width);
00846 UASSERT(dispPt.y >= 0 && dispPt.y < disparitySize.height);
00847 disparity.at<float>(dispPt.y, dispPt.x) = leftCorners[i].x - rightCorners[i].x;
00848 }
00849 }
00850 return disparity;
00851 }
00852
00853 cv::Mat depthFromStereoCorrespondences(
00854 const cv::Mat & leftImage,
00855 const std::vector<cv::Point2f> & leftCorners,
00856 const std::vector<cv::Point2f> & rightCorners,
00857 const std::vector<unsigned char> & mask,
00858 float fx, float baseline)
00859 {
00860 UASSERT(!leftImage.empty() && leftCorners.size() == rightCorners.size());
00861 UASSERT(mask.size() == 0 || mask.size() == leftCorners.size());
00862 cv::Mat depth = cv::Mat::zeros(leftImage.rows, leftImage.cols, CV_32FC1);
00863 for(unsigned int i=0; i<leftCorners.size(); ++i)
00864 {
00865 if(mask.size() == 0 || mask[i])
00866 {
00867 float disparity = leftCorners[i].x - rightCorners[i].x;
00868 if(disparity > 0.0f)
00869 {
00870 float d = baseline * fx / disparity;
00871 depth.at<float>(int(leftCorners[i].y+0.5f), int(leftCorners[i].x+0.5f)) = d;
00872 }
00873 }
00874 }
00875 return depth;
00876 }
00877
00878 cv::Mat cvtDepthFromFloat(const cv::Mat & depth32F)
00879 {
00880 UASSERT(depth32F.empty() || depth32F.type() == CV_32FC1);
00881 cv::Mat depth16U;
00882 if(!depth32F.empty())
00883 {
00884 depth16U = cv::Mat(depth32F.rows, depth32F.cols, CV_16UC1);
00885 int countOverMax = 0;
00886 for(int i=0; i<depth32F.rows; ++i)
00887 {
00888 for(int j=0; j<depth32F.cols; ++j)
00889 {
00890 float depth = (depth32F.at<float>(i,j)*1000.0f);
00891 unsigned short depthMM = 0;
00892 if(depth > 0 && depth <= (float)USHRT_MAX)
00893 {
00894 depthMM = (unsigned short)depth;
00895 }
00896 else if(depth > (float)USHRT_MAX)
00897 {
00898 ++countOverMax;
00899 }
00900 depth16U.at<unsigned short>(i, j) = depthMM;
00901 }
00902 }
00903 if(countOverMax)
00904 {
00905 UWARN("Depth conversion error, %d depth values ignored because "
00906 "they are over the maximum depth allowed (65535 mm). Is the depth "
00907 "image really in meters? 32 bits images should be in meters, "
00908 "and 16 bits should be in mm.", countOverMax);
00909 }
00910 }
00911 return depth16U;
00912 }
00913
00914 cv::Mat cvtDepthToFloat(const cv::Mat & depth16U)
00915 {
00916 UASSERT(depth16U.empty() || depth16U.type() == CV_16UC1);
00917 cv::Mat depth32F;
00918 if(!depth16U.empty())
00919 {
00920 depth32F = cv::Mat(depth16U.rows, depth16U.cols, CV_32FC1);
00921 for(int i=0; i<depth16U.rows; ++i)
00922 {
00923 for(int j=0; j<depth16U.cols; ++j)
00924 {
00925 float depth = float(depth16U.at<unsigned short>(i,j))/1000.0f;
00926 depth32F.at<float>(i, j) = depth;
00927 }
00928 }
00929 }
00930 return depth32F;
00931 }
00932
00933 float getDepth(
00934 const cv::Mat & depthImage,
00935 float x, float y,
00936 bool smoothing,
00937 float maxZError,
00938 bool estWithNeighborsIfNull)
00939 {
00940 UASSERT(!depthImage.empty());
00941 UASSERT(depthImage.type() == CV_16UC1 || depthImage.type() == CV_32FC1);
00942
00943 int u = int(x+0.5f);
00944 int v = int(y+0.5f);
00945 if(u == depthImage.cols && x<float(depthImage.cols))
00946 {
00947 u = depthImage.cols - 1;
00948 }
00949 if(v == depthImage.rows && y<float(depthImage.rows))
00950 {
00951 v = depthImage.rows - 1;
00952 }
00953
00954 if(!(u >=0 && u<depthImage.cols && v >=0 && v<depthImage.rows))
00955 {
00956 UDEBUG("!(x >=0 && x<depthImage.cols && y >=0 && y<depthImage.rows) cond failed! returning bad point. (x=%f (u=%d), y=%f (v=%d), cols=%d, rows=%d)",
00957 x,u,y,v,depthImage.cols, depthImage.rows);
00958 return 0;
00959 }
00960
00961 bool isInMM = depthImage.type() == CV_16UC1;
00962
00963
00964
00965
00966
00967
00968
00969 int u_start = std::max(u-1, 0);
00970 int v_start = std::max(v-1, 0);
00971 int u_end = std::min(u+1, depthImage.cols-1);
00972 int v_end = std::min(v+1, depthImage.rows-1);
00973
00974 float depth = 0.0f;
00975 if(isInMM)
00976 {
00977 if(depthImage.at<unsigned short>(v,u) > 0 &&
00978 depthImage.at<unsigned short>(v,u) < std::numeric_limits<unsigned short>::max())
00979 {
00980 depth = float(depthImage.at<unsigned short>(v,u))*0.001f;
00981 }
00982 }
00983 else
00984 {
00985 depth = depthImage.at<float>(v,u);
00986 }
00987
00988 if((depth==0.0f || !uIsFinite(depth)) && estWithNeighborsIfNull)
00989 {
00990
00991 float tmp = 0.0f;
00992 int count = 0;
00993 for(int uu = u_start; uu <= u_end; ++uu)
00994 {
00995 for(int vv = v_start; vv <= v_end; ++vv)
00996 {
00997 if((uu == u && vv!=v) || (uu != u && vv==v))
00998 {
00999 float d = 0.0f;
01000 if(isInMM)
01001 {
01002 if(depthImage.at<unsigned short>(vv,uu) > 0 &&
01003 depthImage.at<unsigned short>(vv,uu) < std::numeric_limits<unsigned short>::max())
01004 {
01005 d = float(depthImage.at<unsigned short>(vv,uu))*0.001f;
01006 }
01007 }
01008 else
01009 {
01010 d = depthImage.at<float>(vv,uu);
01011 }
01012 if(d!=0.0f && uIsFinite(d))
01013 {
01014 if(tmp == 0.0f)
01015 {
01016 tmp = d;
01017 ++count;
01018 }
01019 else if(fabs(d - tmp) < maxZError)
01020 {
01021 tmp+=d;
01022 ++count;
01023 }
01024 }
01025 }
01026 }
01027 }
01028 if(count > 1)
01029 {
01030 depth = tmp/float(count);
01031 }
01032 }
01033
01034 if(depth!=0.0f && uIsFinite(depth))
01035 {
01036 if(smoothing)
01037 {
01038 float sumWeights = 0.0f;
01039 float sumDepths = 0.0f;
01040 for(int uu = u_start; uu <= u_end; ++uu)
01041 {
01042 for(int vv = v_start; vv <= v_end; ++vv)
01043 {
01044 if(!(uu == u && vv == v))
01045 {
01046 float d = 0.0f;
01047 if(isInMM)
01048 {
01049 if(depthImage.at<unsigned short>(vv,uu) > 0 &&
01050 depthImage.at<unsigned short>(vv,uu) < std::numeric_limits<unsigned short>::max())
01051 {
01052 d = float(depthImage.at<unsigned short>(vv,uu))*0.001f;
01053 }
01054 }
01055 else
01056 {
01057 d = depthImage.at<float>(vv,uu);
01058 }
01059
01060
01061 if(d != 0.0f && uIsFinite(d) && fabs(d - depth) < maxZError)
01062 {
01063 if(uu == u || vv == v)
01064 {
01065 sumWeights+=2.0f;
01066 d*=2.0f;
01067 }
01068 else
01069 {
01070 sumWeights+=1.0f;
01071 }
01072 sumDepths += d;
01073 }
01074 }
01075 }
01076 }
01077
01078 depth *= 4.0f;
01079 sumWeights += 4.0f;
01080
01081
01082 depth = (depth+sumDepths)/sumWeights;
01083 }
01084 }
01085 else
01086 {
01087 depth = 0;
01088 }
01089 return depth;
01090 }
01091
01092 cv::Mat decimate(const cv::Mat & image, int decimation)
01093 {
01094 UASSERT(decimation >= 1);
01095 cv::Mat out;
01096 if(!image.empty())
01097 {
01098 if(decimation > 1)
01099 {
01100 if((image.type() == CV_32FC1 || image.type()==CV_16UC1))
01101 {
01102 UASSERT_MSG(image.rows % decimation == 0 && image.cols % decimation == 0, "Decimation of depth images should be exact!");
01103
01104 out = cv::Mat(image.rows/decimation, image.cols/decimation, image.type());
01105 if(image.type() == CV_32FC1)
01106 {
01107 for(int j=0; j<out.rows; ++j)
01108 {
01109 for(int i=0; i<out.cols; ++i)
01110 {
01111 out.at<float>(j, i) = image.at<float>(j*decimation, i*decimation);
01112 }
01113 }
01114 }
01115 else
01116 {
01117 for(int j=0; j<out.rows; ++j)
01118 {
01119 for(int i=0; i<out.cols; ++i)
01120 {
01121 out.at<unsigned short>(j, i) = image.at<unsigned short>(j*decimation, i*decimation);
01122 }
01123 }
01124 }
01125 }
01126 else
01127 {
01128 cv::resize(image, out, cv::Size(), 1.0f/float(decimation), 1.0f/float(decimation), cv::INTER_AREA);
01129 }
01130 }
01131 else
01132 {
01133 out = image;
01134 }
01135 }
01136 return out;
01137 }
01138
01139 cv::Mat interpolate(const cv::Mat & image, int factor, float depthErrorRatio)
01140 {
01141 UASSERT(factor >= 1);
01142 cv::Mat out;
01143 if(!image.empty())
01144 {
01145 if(factor > 1)
01146 {
01147 if((image.type() == CV_32FC1 || image.type()==CV_16UC1))
01148 {
01149 UASSERT(depthErrorRatio>0.0f);
01150 out = cv::Mat::zeros(image.rows*factor, image.cols*factor, image.type());
01151 for(int j=0; j<out.rows; j+=factor)
01152 {
01153 for(int i=0; i<out.cols; i+=factor)
01154 {
01155 if(i>0 && j>0)
01156 {
01157 float dTopLeft;
01158 float dTopRight;
01159 float dBottomLeft;
01160 float dBottomRight;
01161 if(image.type() == CV_32FC1)
01162 {
01163 dTopLeft = image.at<float>(j/factor-1, i/factor-1);
01164 dTopRight = image.at<float>(j/factor-1, i/factor);
01165 dBottomLeft = image.at<float>(j/factor, i/factor-1);
01166 dBottomRight = image.at<float>(j/factor, i/factor);
01167 }
01168 else
01169 {
01170 dTopLeft = image.at<unsigned short>(j/factor-1, i/factor-1);
01171 dTopRight = image.at<unsigned short>(j/factor-1, i/factor);
01172 dBottomLeft = image.at<unsigned short>(j/factor, i/factor-1);
01173 dBottomRight = image.at<unsigned short>(j/factor, i/factor);
01174 }
01175
01176 if(dTopLeft>0 && dTopRight>0 && dBottomLeft>0 && dBottomRight > 0)
01177 {
01178 float depthError = depthErrorRatio*(dTopLeft+dTopRight+dBottomLeft+dBottomRight)/4.0f;
01179 if(fabs(dTopLeft-dTopRight) <= depthError &&
01180 fabs(dTopLeft-dBottomLeft) <= depthError &&
01181 fabs(dTopLeft-dBottomRight) <= depthError)
01182 {
01183
01184
01185 float slopeTop = (dTopRight-dTopLeft)/float(factor);
01186 float slopeBottom = (dBottomRight-dBottomLeft)/float(factor);
01187 if(image.type() == CV_32FC1)
01188 {
01189 for(int z=i-factor; z<=i; ++z)
01190 {
01191 out.at<float>(j-factor, z) = dTopLeft+(slopeTop*float(z-(i-factor)));
01192 out.at<float>(j, z) = dBottomLeft+(slopeBottom*float(z-(i-factor)));
01193 }
01194 }
01195 else
01196 {
01197 for(int z=i-factor; z<=i; ++z)
01198 {
01199 out.at<unsigned short>(j-factor, z) = (unsigned short)(dTopLeft+(slopeTop*float(z-(i-factor))));
01200 out.at<unsigned short>(j, z) = (unsigned short)(dBottomLeft+(slopeBottom*float(z-(i-factor))));
01201 }
01202 }
01203
01204
01205 if(image.type() == CV_32FC1)
01206 {
01207 for(int z=i-factor; z<=i; ++z)
01208 {
01209 float top = out.at<float>(j-factor, z);
01210 float bottom = out.at<float>(j, z);
01211 float slope = (bottom-top)/float(factor);
01212 for(int d=j-factor+1; d<j; ++d)
01213 {
01214 out.at<float>(d, z) = top+(slope*float(d-(j-factor)));
01215 }
01216 }
01217 }
01218 else
01219 {
01220 for(int z=i-factor; z<=i; ++z)
01221 {
01222 float top = out.at<unsigned short>(j-factor, z);
01223 float bottom = out.at<unsigned short>(j, z);
01224 float slope = (bottom-top)/float(factor);
01225 for(int d=j-factor+1; d<j; ++d)
01226 {
01227 out.at<unsigned short>(d, z) = (unsigned short)(top+(slope*float(d-(j-factor))));
01228 }
01229 }
01230 }
01231 }
01232 }
01233 }
01234 }
01235 }
01236 }
01237 else
01238 {
01239 cv::resize(image, out, cv::Size(), float(factor), float(factor));
01240 }
01241 }
01242 else
01243 {
01244 out = image;
01245 }
01246 }
01247 return out;
01248 }
01249
01250
01251 cv::Mat registerDepth(
01252 const cv::Mat & depth,
01253 const cv::Mat & depthK,
01254 const cv::Mat & colorK,
01255 const rtabmap::Transform & transform)
01256 {
01257 UASSERT(!transform.isNull());
01258 UASSERT(!depth.empty());
01259 UASSERT(depth.type() == CV_16UC1 || depth.type() == CV_32FC1);
01260 UASSERT(depthK.type() == CV_64FC1 && depthK.cols == 3 && depthK.cols == 3);
01261 UASSERT(colorK.type() == CV_64FC1 && colorK.cols == 3 && colorK.cols == 3);
01262
01263 float fx = depthK.at<double>(0,0);
01264 float fy = depthK.at<double>(1,1);
01265 float cx = depthK.at<double>(0,2);
01266 float cy = depthK.at<double>(1,2);
01267
01268 float rfx = colorK.at<double>(0,0);
01269 float rfy = colorK.at<double>(1,1);
01270 float rcx = colorK.at<double>(0,2);
01271 float rcy = colorK.at<double>(1,2);
01272
01273 Eigen::Affine3f proj = transform.toEigen3f();
01274 Eigen::Vector4f P4,P3;
01275 P4[3] = 1;
01276 cv::Mat registered = cv::Mat::zeros(depth.rows, depth.cols, depth.type());
01277
01278 bool depthInMM = depth.type() == CV_16UC1;
01279 for(int y=0; y<depth.rows; ++y)
01280 {
01281 for(int x=0; x<depth.cols; ++x)
01282 {
01283
01284 float dz = depthInMM?float(depth.at<unsigned short>(y,x))*0.001f:depth.at<float>(y,x);
01285 if(dz>=0.0f)
01286 {
01287
01288 P4[0] = (x - cx) * dz / fx;
01289 P4[1] = (y - cy) * dz / fy;
01290 P4[2] = dz;
01291
01292 P3 = proj * P4;
01293 float z = P3[2];
01294 float invZ = 1.0f/z;
01295 int dx = (rfx*P3[0])*invZ + rcx;
01296 int dy = (rfy*P3[1])*invZ + rcy;
01297
01298 if(uIsInBounds(dx, 0, registered.cols) && uIsInBounds(dy, 0, registered.rows))
01299 {
01300 if(depthInMM)
01301 {
01302 unsigned short z16 = z * 1000;
01303 unsigned short &zReg = registered.at<unsigned short>(dy, dx);
01304 if(zReg == 0 || z16 < zReg)
01305 {
01306 zReg = z16;
01307 }
01308 }
01309 else
01310 {
01311 float &zReg = registered.at<float>(dy, dx);
01312 if(zReg == 0 || z < zReg)
01313 {
01314 zReg = z;
01315 }
01316 }
01317 }
01318 }
01319 }
01320 }
01321 return registered;
01322 }
01323
01324 cv::Mat fillDepthHoles(const cv::Mat & registeredDepth, int maximumHoleSize, float errorRatio)
01325 {
01326 UASSERT(registeredDepth.type() == CV_16UC1);
01327 UASSERT(maximumHoleSize > 0);
01328 cv::Mat output = registeredDepth.clone();
01329 for(int y=0; y<registeredDepth.rows-2; ++y)
01330 {
01331 for(int x=0; x<registeredDepth.cols-2; ++x)
01332 {
01333 float a = registeredDepth.at<unsigned short>(y, x);
01334 float bRight = registeredDepth.at<unsigned short>(y, x+1);
01335 float bDown = registeredDepth.at<unsigned short>(y+1, x);
01336
01337 if(a > 0.0f && (bRight == 0.0f || bDown == 0.0f))
01338 {
01339 bool horizontalSet = bRight != 0.0f;
01340 bool verticalSet = bDown != 0.0f;
01341 int stepX = 0;
01342 for(int h=1; h<=maximumHoleSize && (!horizontalSet || !verticalSet); ++h)
01343 {
01344
01345 if(!horizontalSet)
01346 {
01347 if(x+1+h >= registeredDepth.cols)
01348 {
01349 horizontalSet = true;
01350 }
01351 else
01352 {
01353 float c = registeredDepth.at<unsigned short>(y, x+1+h);
01354 if(c == 0)
01355 {
01356
01357 }
01358 else
01359 {
01360
01361 float depthError = errorRatio*float(a+c)/2.0f;
01362 if(fabs(a-c) <= depthError)
01363 {
01364
01365 float slope = (c-a)/float(h+1);
01366 for(int z=x+1; z<x+1+h; ++z)
01367 {
01368 if(output.at<unsigned short>(y, z) == 0)
01369 {
01370 output.at<unsigned short>(y, z) = (unsigned short)(a+(slope*float(z-x)));
01371 }
01372 else
01373 {
01374
01375 output.at<unsigned short>(y, z) = (output.at<unsigned short>(y, z)+(unsigned short)(a+(slope*float(z-x))))/2;
01376 }
01377 }
01378 }
01379 horizontalSet = true;
01380 stepX = h;
01381 }
01382 }
01383 }
01384
01385
01386 if(!verticalSet)
01387 {
01388 if(y+1+h >= registeredDepth.rows)
01389 {
01390 verticalSet = true;
01391 }
01392 else
01393 {
01394 float c = registeredDepth.at<unsigned short>(y+1+h, x);
01395 if(c == 0)
01396 {
01397
01398 }
01399 else
01400 {
01401
01402 float depthError = errorRatio*float(a+c)/2.0f;
01403 if(fabs(a-c) <= depthError)
01404 {
01405
01406 float slope = (c-a)/float(h+1);
01407 for(int z=y+1; z<y+1+h; ++z)
01408 {
01409 if(output.at<unsigned short>(z, x) == 0)
01410 {
01411 output.at<unsigned short>(z, x) = (unsigned short)(a+(slope*float(z-y)));
01412 }
01413 else
01414 {
01415
01416 output.at<unsigned short>(z, x) = (output.at<unsigned short>(z, x)+(unsigned short)(a+(slope*float(z-y))))/2;
01417 }
01418 }
01419 }
01420 verticalSet = true;
01421 }
01422 }
01423 }
01424 }
01425 x+=stepX;
01426 }
01427 }
01428 }
01429 return output;
01430 }
01431
01432 void fillRegisteredDepthHoles(cv::Mat & registeredDepth, bool vertical, bool horizontal, bool fillDoubleHoles)
01433 {
01434 UASSERT(registeredDepth.type() == CV_16UC1);
01435 int margin = fillDoubleHoles?2:1;
01436 for(int x=1; x<registeredDepth.cols-margin; ++x)
01437 {
01438 for(int y=1; y<registeredDepth.rows-margin; ++y)
01439 {
01440 unsigned short & b = registeredDepth.at<unsigned short>(y, x);
01441 bool set = false;
01442 if(vertical)
01443 {
01444 const unsigned short & a = registeredDepth.at<unsigned short>(y-1, x);
01445 unsigned short & c = registeredDepth.at<unsigned short>(y+1, x);
01446 if(a && c)
01447 {
01448 unsigned short error = 0.01*((a+c)/2);
01449 if(((b == 0 && a && c) || (b > a+error && b > c+error)) &&
01450 (a>c?a-c<=error:c-a<=error))
01451 {
01452 b = (a+c)/2;
01453 set = true;
01454 if(!horizontal)
01455 {
01456 ++y;
01457 }
01458 }
01459 }
01460 if(!set && fillDoubleHoles)
01461 {
01462 const unsigned short & d = registeredDepth.at<unsigned short>(y+2, x);
01463 if(a && d && (b==0 || c==0))
01464 {
01465 unsigned short error = 0.01*((a+d)/2);
01466 if(((b == 0 && a && d) || (b > a+error && b > d+error)) &&
01467 ((c == 0 && a && d) || (c > a+error && c > d+error)) &&
01468 (a>d?a-d<=error:d-a<=error))
01469 {
01470 if(a>d)
01471 {
01472 unsigned short tmp = (a-d)/4;
01473 b = d + tmp;
01474 c = d + 3*tmp;
01475 }
01476 else
01477 {
01478 unsigned short tmp = (d-a)/4;
01479 b = a + tmp;
01480 c = a + 3*tmp;
01481 }
01482 set = true;
01483 if(!horizontal)
01484 {
01485 y+=2;
01486 }
01487 }
01488 }
01489 }
01490 }
01491 if(!set && horizontal)
01492 {
01493 const unsigned short & a = registeredDepth.at<unsigned short>(y, x-1);
01494 unsigned short & c = registeredDepth.at<unsigned short>(y, x+1);
01495 if(a && c)
01496 {
01497 unsigned short error = 0.01*((a+c)/2);
01498 if(((b == 0 && a && c) || (b > a+error && b > c+error)) &&
01499 (a>c?a-c<=error:c-a<=error))
01500 {
01501 b = (a+c)/2;
01502 set = true;
01503 }
01504 }
01505 if(!set && fillDoubleHoles)
01506 {
01507 const unsigned short & d = registeredDepth.at<unsigned short>(y, x+2);
01508 if(a && d && (b==0 || c==0))
01509 {
01510 unsigned short error = 0.01*((a+d)/2);
01511 if(((b == 0 && a && d) || (b > a+error && b > d+error)) &&
01512 ((c == 0 && a && d) || (c > a+error && c > d+error)) &&
01513 (a>d?a-d<=error:d-a<=error))
01514 {
01515 if(a>d)
01516 {
01517 unsigned short tmp = (a-d)/4;
01518 b = d + tmp;
01519 c = d + 3*tmp;
01520 }
01521 else
01522 {
01523 unsigned short tmp = (d-a)/4;
01524 b = a + tmp;
01525 c = a + 3*tmp;
01526 }
01527 }
01528 }
01529 }
01530 }
01531 }
01532 }
01533 }
01534
01535 }
01536
01537 }