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
00029
00030
00031
00032
00033 #include "InversePerspectiveMapping.hh"
00034
00035 #include "CameraInfoOpt.h"
00036
00037 #include <iostream>
00038 #include <math.h>
00039 #include <assert.h>
00040 #include <list>
00041
00042 using namespace std;
00043 #include <cv.h>
00044 #include <highgui.h>
00045
00046 namespace LaneDetector
00047 {
00048
00049 #define VP_PORTION 0.05
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00079 void mcvGetIPM(const CvMat* inImage, CvMat* outImage,
00080 IPMInfo *ipmInfo, const CameraInfo *cameraInfo,
00081 list<CvPoint> *outPoints)
00082 {
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 if (!(CV_ARE_TYPES_EQ(inImage, outImage) &&
00095 (CV_MAT_TYPE(inImage->type)==CV_MAT_TYPE(FLOAT_MAT_TYPE) ||
00096 (CV_MAT_TYPE(inImage->type)==CV_MAT_TYPE(INT_MAT_TYPE)))))
00097 {
00098 cerr << "Unsupported image types in mcvGetIPM";
00099 exit(1);
00100 }
00101
00102
00103 FLOAT u, v;
00104 v = inImage->height;
00105 u = inImage->width;
00106
00107
00108 FLOAT_POINT2D vp;
00109 vp = mcvGetVanishingPoint(cameraInfo);
00110 vp.y = MAX(0, vp.y);
00111
00112
00113
00114 FLOAT_MAT_ELEM_TYPE eps = ipmInfo->vpPortion * v;
00115 ipmInfo->ipmLeft = MAX(0, ipmInfo->ipmLeft);
00116 ipmInfo->ipmRight = MIN(u-1, ipmInfo->ipmRight);
00117 ipmInfo->ipmTop = MAX(vp.y+eps, ipmInfo->ipmTop);
00118 ipmInfo->ipmBottom = MIN(v-1, ipmInfo->ipmBottom);
00119 FLOAT_MAT_ELEM_TYPE uvLimitsp[] = {vp.x,
00120 ipmInfo->ipmRight, ipmInfo->ipmLeft, vp.x,
00121 ipmInfo->ipmTop, ipmInfo->ipmTop, ipmInfo->ipmTop, ipmInfo->ipmBottom};
00122
00123
00124 CvMat uvLimits = cvMat(2, 4, FLOAT_MAT_TYPE, uvLimitsp);
00125
00126
00127 CvMat * xyLimitsp = cvCreateMat(2, 4, FLOAT_MAT_TYPE);
00128 CvMat xyLimits = *xyLimitsp;
00129 mcvTransformImage2Ground(&uvLimits, &xyLimits,cameraInfo);
00130
00131
00132
00133 CvMat row1, row2;
00134 cvGetRow(&xyLimits, &row1, 0);
00135 cvGetRow(&xyLimits, &row2, 1);
00136 double xfMax, xfMin, yfMax, yfMin;
00137 cvMinMaxLoc(&row1, (double*)&xfMin, (double*)&xfMax, 0, 0, 0);
00138 cvMinMaxLoc(&row2, (double*)&yfMin, (double*)&yfMax, 0, 0, 0);
00139
00140 INT outRow = outImage->height;
00141 INT outCol = outImage->width;
00142
00143 FLOAT_MAT_ELEM_TYPE stepRow = (yfMax-yfMin)/outRow;
00144 FLOAT_MAT_ELEM_TYPE stepCol = (xfMax-xfMin)/outCol;
00145
00146
00147 CvMat *xyGrid = cvCreateMat(2, outRow*outCol, FLOAT_MAT_TYPE);
00148 INT i, j;
00149 FLOAT_MAT_ELEM_TYPE x, y;
00150
00151 for (i=0, y=yfMax-.5*stepRow; i<outRow; i++, y-=stepRow)
00152 for (j=0, x=xfMin+.5*stepCol; j<outCol; j++, x+=stepCol)
00153 {
00154 CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 0, i*outCol+j) = x;
00155 CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 1, i*outCol+j) = y;
00156 }
00157
00158 CvMat *uvGrid = cvCreateMat(2, outRow*outCol, FLOAT_MAT_TYPE);
00159 mcvTransformGround2Image(xyGrid, uvGrid, cameraInfo);
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 FLOAT_MAT_ELEM_TYPE ui, vi;
00174
00175 CvScalar means = cvAvg(inImage);
00176 double mean = means.val[0];
00177
00178 #define MCV_GET_IPM(type) \
00179 for (i=0; i<outRow; i++) \
00180 for (j=0; j<outCol; j++) \
00181 { \
00182 \
00183 ui = CV_MAT_ELEM(*uvGrid, FLOAT_MAT_ELEM_TYPE, 0, i*outCol+j); \
00184 vi = CV_MAT_ELEM(*uvGrid, FLOAT_MAT_ELEM_TYPE, 1, i*outCol+j); \
00185 \
00186 \
00187 if (ui<ipmInfo->ipmLeft || ui>ipmInfo->ipmRight || \
00188 vi<ipmInfo->ipmTop || vi>ipmInfo->ipmBottom) \
00189 { \
00190 CV_MAT_ELEM(*outImage, type, i, j) = (type)mean; \
00191 } \
00192 \
00193 else \
00194 { \
00195 \
00196 if (ipmInfo->ipmInterpolation == 0) \
00197 { \
00198 int x1 = int(ui), x2 = int(ui+1); \
00199 int y1 = int(vi), y2 = int(vi+1); \
00200 float x = ui - x1, y = vi - y1; \
00201 float val = CV_MAT_ELEM(*inImage, type, y1, x1) * (1-x) * (1-y) + \
00202 CV_MAT_ELEM(*inImage, type, y1, x2) * x * (1-y) + \
00203 CV_MAT_ELEM(*inImage, type, y2, x1) * (1-x) * y + \
00204 CV_MAT_ELEM(*inImage, type, y2, x2) * x * y; \
00205 CV_MAT_ELEM(*outImage, type, i, j) = (type)val; \
00206 } \
00207 \
00208 else \
00209 CV_MAT_ELEM(*outImage, type, i, j) = \
00210 CV_MAT_ELEM(*inImage, type, int(vi+.5), int(ui+.5)); \
00211 } \
00212 if (outPoints && \
00213 (ui<ipmInfo->ipmLeft+10 || ui>ipmInfo->ipmRight-10 || \
00214 vi<ipmInfo->ipmTop || vi>ipmInfo->ipmBottom-2) )\
00215 outPoints->push_back(cvPoint(j, i)); \
00216 }
00217 if (CV_MAT_TYPE(inImage->type)==FLOAT_MAT_TYPE)
00218 {
00219 MCV_GET_IPM(FLOAT_MAT_ELEM_TYPE)
00220 }
00221 else
00222 {
00223 MCV_GET_IPM(INT_MAT_ELEM_TYPE)
00224 }
00225
00226 ipmInfo->xLimits[0] = CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 0, 0);
00227 ipmInfo->xLimits[1] =
00228 CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 0, (outRow-1)*outCol+outCol-1);
00229 ipmInfo->yLimits[1] = CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 1, 0);
00230 ipmInfo->yLimits[0] =
00231 CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 1, (outRow-1)*outCol+outCol-1);
00232 ipmInfo->xScale = 1/stepCol;
00233 ipmInfo->yScale = 1/stepRow;
00234 ipmInfo->width = outCol;
00235 ipmInfo->height = outRow;
00236
00237
00238 cvReleaseMat(&xyLimitsp);
00239 cvReleaseMat(&xyGrid);
00240 cvReleaseMat(&uvGrid);
00241 }
00242
00243
00254 void mcvTransformImage2Ground(const CvMat *inPoints,
00255 CvMat *outPoints, const CameraInfo *cameraInfo)
00256 {
00257
00258
00259 CvMat *inPoints4 = cvCreateMat(inPoints->rows+2, inPoints->cols,
00260 cvGetElemType(inPoints));
00261
00262
00263 CvMat inPoints2, inPoints3, inPointsr4, inPointsr3;
00264 cvGetRows(inPoints4, &inPoints2, 0, 2);
00265 cvGetRows(inPoints4, &inPoints3, 0, 3);
00266 cvGetRow(inPoints4, &inPointsr3, 2);
00267 cvGetRow(inPoints4, &inPointsr4, 3);
00268 cvSet(&inPointsr3, cvRealScalar(1));
00269 cvCopy(inPoints, &inPoints2);
00270
00271 float c1 = cos(cameraInfo->pitch);
00272 float s1 = sin(cameraInfo->pitch);
00273 float c2 = cos(cameraInfo->yaw);
00274 float s2 = sin(cameraInfo->yaw);
00275 float matp[] = {
00276 -cameraInfo->cameraHeight*c2/cameraInfo->focalLength.x,
00277 cameraInfo->cameraHeight*s1*s2/cameraInfo->focalLength.y,
00278 (cameraInfo->cameraHeight*c2*cameraInfo->opticalCenter.x/
00279 cameraInfo->focalLength.x)-
00280 (cameraInfo->cameraHeight *s1*s2* cameraInfo->opticalCenter.y/
00281 cameraInfo->focalLength.y) - cameraInfo->cameraHeight *c1*s2,
00282
00283 cameraInfo->cameraHeight *s2 /cameraInfo->focalLength.x,
00284 cameraInfo->cameraHeight *s1*c2 /cameraInfo->focalLength.y,
00285 (-cameraInfo->cameraHeight *s2* cameraInfo->opticalCenter.x
00286 /cameraInfo->focalLength.x)-(cameraInfo->cameraHeight *s1*c2*
00287 cameraInfo->opticalCenter.y /cameraInfo->focalLength.y) -
00288 cameraInfo->cameraHeight *c1*c2,
00289
00290 0,
00291 cameraInfo->cameraHeight *c1 /cameraInfo->focalLength.y,
00292 (-cameraInfo->cameraHeight *c1* cameraInfo->opticalCenter.y /
00293 cameraInfo->focalLength.y) + cameraInfo->cameraHeight *s1,
00294
00295 0,
00296 -c1 /cameraInfo->focalLength.y,
00297 (c1* cameraInfo->opticalCenter.y /cameraInfo->focalLength.y) - s1,
00298 };
00299 CvMat mat = cvMat(4, 3, CV_32FC1, matp);
00300
00301 cvMatMul(&mat, &inPoints3, inPoints4);
00302
00303 for (int i=0; i<inPoints->cols; i++)
00304 {
00305 float div = CV_MAT_ELEM(inPointsr4, float, 0, i);
00306 CV_MAT_ELEM(*inPoints4, float, 0, i) =
00307 CV_MAT_ELEM(*inPoints4, float, 0, i) / div ;
00308 CV_MAT_ELEM(*inPoints4, float, 1, i) =
00309 CV_MAT_ELEM(*inPoints4, float, 1, i) / div;
00310 }
00311
00312 cvCopy(&inPoints2, outPoints);
00313
00314 cvReleaseMat(&inPoints4);
00315 }
00316
00317
00327 void mcvTransformGround2Image(const CvMat *inPoints,
00328 CvMat *outPoints, const CameraInfo *cameraInfo)
00329 {
00330
00331 CvMat *inPoints3 = cvCreateMat(inPoints->rows+1, inPoints->cols,
00332 cvGetElemType(inPoints));
00333
00334
00335 CvMat inPoints2, inPointsr3;
00336 cvGetRows(inPoints3, &inPoints2, 0, 2);
00337 cvGetRow(inPoints3, &inPointsr3, 2);
00338 cvSet(&inPointsr3, cvRealScalar(-cameraInfo->cameraHeight));
00339 cvCopy(inPoints, &inPoints2);
00340
00341 float c1 = cos(cameraInfo->pitch);
00342 float s1 = sin(cameraInfo->pitch);
00343 float c2 = cos(cameraInfo->yaw);
00344 float s2 = sin(cameraInfo->yaw);
00345 float matp[] = {
00346 cameraInfo->focalLength.x * c2 + c1*s2* cameraInfo->opticalCenter.x,
00347 -cameraInfo->focalLength.x * s2 + c1*c2* cameraInfo->opticalCenter.x,
00348 - s1 * cameraInfo->opticalCenter.x,
00349
00350 s2 * (-cameraInfo->focalLength.y * s1 + c1* cameraInfo->opticalCenter.y),
00351 c2 * (-cameraInfo->focalLength.y * s1 + c1* cameraInfo->opticalCenter.y),
00352 -cameraInfo->focalLength.y * c1 - s1* cameraInfo->opticalCenter.y,
00353
00354 c1*s2,
00355 c1*c2,
00356 -s1
00357 };
00358 CvMat mat = cvMat(3, 3, CV_32FC1, matp);
00359
00360 cvMatMul(&mat, inPoints3, inPoints3);
00361
00362 for (int i=0; i<inPoints->cols; i++)
00363 {
00364 float div = CV_MAT_ELEM(inPointsr3, float, 0, i);
00365 CV_MAT_ELEM(*inPoints3, float, 0, i) =
00366 CV_MAT_ELEM(*inPoints3, float, 0, i) / div ;
00367 CV_MAT_ELEM(*inPoints3, float, 1, i) =
00368 CV_MAT_ELEM(*inPoints3, float, 1, i) / div;
00369 }
00370
00371 cvCopy(&inPoints2, outPoints);
00372
00373 cvReleaseMat(&inPoints3);
00374 }
00375
00376
00388 FLOAT_POINT2D mcvGetVanishingPoint(const CameraInfo *cameraInfo)
00389 {
00390
00391 FLOAT_MAT_ELEM_TYPE vpp[] = {sin(cameraInfo->yaw)/cos(cameraInfo->pitch),
00392 cos(cameraInfo->yaw)/cos(cameraInfo->pitch), 0};
00393 CvMat vp = cvMat(3, 1, FLOAT_MAT_TYPE, vpp);
00394
00395
00396
00397
00398 FLOAT_MAT_ELEM_TYPE tyawp[] = {cos(cameraInfo->yaw), -sin(cameraInfo->yaw), 0,
00399 sin(cameraInfo->yaw), cos(cameraInfo->yaw), 0,
00400 0, 0, 1};
00401 CvMat tyaw = cvMat(3, 3, FLOAT_MAT_TYPE, tyawp);
00402
00403 FLOAT_MAT_ELEM_TYPE tpitchp[] = {1, 0, 0,
00404 0, -sin(cameraInfo->pitch), -cos(cameraInfo->pitch),
00405 0, cos(cameraInfo->pitch), -sin(cameraInfo->pitch)};
00406 CvMat transform = cvMat(3, 3, FLOAT_MAT_TYPE, tpitchp);
00407
00408 cvMatMul(&transform, &tyaw, &transform);
00409
00410
00411
00412
00413
00414
00415 FLOAT_MAT_ELEM_TYPE t1p[] = {
00416 cameraInfo->focalLength.x, 0,
00417 cameraInfo->opticalCenter.x,
00418 0, cameraInfo->focalLength.y,
00419 cameraInfo->opticalCenter.y,
00420 0, 0, 1};
00421 CvMat t1 = cvMat(3, 3, FLOAT_MAT_TYPE, t1p);
00422
00423 cvMatMul(&t1, &transform, &transform);
00424
00425 cvMatMul(&transform, &vp, &vp);
00426
00427
00428
00429
00430 FLOAT_POINT2D ret;
00431 ret.x = cvGetReal1D(&vp, 0);
00432 ret.y = cvGetReal1D(&vp, 1);
00433 return ret;
00434 }
00435
00436
00444 void mcvPointImIPM2World(FLOAT_POINT2D *point, const IPMInfo *ipmInfo)
00445 {
00446
00447 point->x /= ipmInfo->xScale;
00448 point->x += ipmInfo->xLimits[0];
00449
00450 point->y /= ipmInfo->yScale;
00451 point->y = ipmInfo->yLimits[1] - point->y;
00452 }
00453
00454
00463 void mcvTransformImIPM2Ground(const CvMat *inMat, CvMat* outMat, const IPMInfo *ipmInfo)
00464 {
00465 CvMat *mat;
00466 mat = outMat;
00467 if(inMat != mat)
00468 {
00469 cvCopy(inMat, mat);
00470 }
00471
00472
00473 CvMat row;
00474 cvGetRow(mat, &row, 0);
00475 cvConvertScale(&row, &row, 1./ipmInfo->xScale, ipmInfo->xLimits[0]);
00476
00477
00478 cvGetRow(mat, &row, 1);
00479 cvConvertScale(&row, &row, -1./ipmInfo->yScale, ipmInfo->yLimits[1]);
00480 }
00481
00491 void mcvTransformImIPM2Im(const CvMat *inMat, CvMat* outMat, const IPMInfo *ipmInfo,
00492 const CameraInfo *cameraInfo)
00493 {
00494
00495 mcvTransformImIPM2Ground(inMat, outMat, ipmInfo);
00496
00497
00498 mcvTransformGround2Image(outMat, outMat, cameraInfo);
00499
00500 }
00501
00502
00510 void mcvInitCameraInfo (char * const fileName, CameraInfo *cameraInfo)
00511 {
00512
00513 CameraInfoParserInfo camInfo;
00514
00515 assert(cameraInfoParser_configfile(fileName, &camInfo, 0, 1, 1)==0);
00516
00517 cameraInfo->focalLength.x = camInfo.focalLengthX_arg;
00518 cameraInfo->focalLength.y = camInfo.focalLengthY_arg;
00519 cameraInfo->opticalCenter.x = camInfo.opticalCenterX_arg;
00520 cameraInfo->opticalCenter.y = camInfo.opticalCenterY_arg;
00521 cameraInfo->cameraHeight = camInfo.cameraHeight_arg;
00522 cameraInfo->pitch = camInfo.pitch_arg * CV_PI/180;
00523 cameraInfo->yaw = camInfo.yaw_arg * CV_PI/180;
00524 cameraInfo->imageWidth = camInfo.imageWidth_arg;
00525 cameraInfo->imageHeight = camInfo.imageHeight_arg;
00526 }
00527
00528
00536 void mcvScaleCameraInfo (CameraInfo *cameraInfo, CvSize size)
00537 {
00538
00539 double scaleX = size.width/cameraInfo->imageWidth;
00540 double scaleY = size.height/cameraInfo->imageHeight;
00541
00542 cameraInfo->imageWidth = size.width;
00543 cameraInfo->imageHeight = size.height;
00544 cameraInfo->focalLength.x *= scaleX;
00545 cameraInfo->focalLength.y *= scaleY;
00546 cameraInfo->opticalCenter.x *= scaleX;
00547 cameraInfo->opticalCenter.y *= scaleY;
00548 }
00549
00550
00559 void mcvGetIPMExtent(const CameraInfo *cameraInfo, IPMInfo *ipmInfo )
00560 {
00561
00562 FLOAT u, v;
00563 v = cameraInfo->imageHeight;
00564 u = cameraInfo->imageWidth;
00565
00566
00567 FLOAT_POINT2D vp;
00568 vp = mcvGetVanishingPoint(cameraInfo);
00569 vp.y = MAX(0, vp.y);
00570
00571
00572 FLOAT_MAT_ELEM_TYPE eps = VP_PORTION*v;
00573 FLOAT_MAT_ELEM_TYPE uvLimitsp[] = {vp.x, u, 0, vp.x,
00574 vp.y+eps, vp.y+eps, vp.y+eps, v};
00575 CvMat uvLimits = cvMat(2, 4, FLOAT_MAT_TYPE, uvLimitsp);
00576
00577
00578 CvMat * xyLimitsp = cvCreateMat(2, 4, FLOAT_MAT_TYPE);
00579 CvMat xyLimits = *xyLimitsp;
00580 mcvTransformImage2Ground(&uvLimits, &xyLimits,cameraInfo);
00581
00582
00583
00584 CvMat row1, row2;
00585 cvGetRow(&xyLimits, &row1, 0);
00586 cvGetRow(&xyLimits, &row2, 1);
00587 double xfMax, xfMin, yfMax, yfMin;
00588 cvMinMaxLoc(&row1, (double*)&xfMin, (double*)&xfMax, 0, 0, 0);
00589 cvMinMaxLoc(&row2, (double*)&yfMin, (double*)&yfMax, 0, 0, 0);
00590
00591
00592 ipmInfo->xLimits[0] = xfMin;
00593 ipmInfo->xLimits[1] = xfMax;
00594 ipmInfo->yLimits[1] = yfMax;
00595 ipmInfo->yLimits[0] = yfMin;
00596
00597 }
00598
00599 }