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
00034 #include "LaneDetector.hh"
00035 #include "mcv.hh"
00036 #include "InversePerspectiveMapping.hh"
00037 #include "LaneDetectorOpt.h"
00038 #include "ranker.h"
00039
00040 #include <iostream>
00041 #include <vector>
00042 #include <list>
00043 #include <algorithm>
00044 #include <math.h>
00045
00046 using namespace std;
00047
00048 #include <cv.h>
00049 #include <highgui.h>
00050 using namespace std;
00051 namespace LaneDetector
00052 {
00053
00054 int DEBUG_LINES = 0;
00055
00072 void mcvFilterLines(const CvMat *inImage, CvMat *outImage,
00073 unsigned char wx, unsigned char wy, FLOAT sigmax,
00074 FLOAT sigmay, LineType lineType)
00075 {
00076
00077
00078
00079
00080
00081
00082 CvMat fx;
00083 CvMat fy;
00084
00085 switch (lineType)
00086 {
00087 case LINE_HORIZONTAL:
00088 {
00089
00090 FLOAT_MAT_ELEM_TYPE derivp[] = {-2.384186e-07, -4.768372e-06, -4.482269e-05, -2.622604e-04, -1.064777e-03, -3.157616e-03, -6.976128e-03, -1.136112e-02, -1.270652e-02, -6.776810e-03, 6.776810e-03, 2.156258e-02, 2.803135e-02, 2.156258e-02, 6.776810e-03, -6.776810e-03, -1.270652e-02, -1.136112e-02, -6.976128e-03, -3.157616e-03, -1.064777e-03, -2.622604e-04, -4.482269e-05, -4.768372e-06, -2.384186e-07};
00091 int derivLen = 25;
00092 FLOAT_MAT_ELEM_TYPE smoothp[] = {2.384186e-07, 5.245209e-06, 5.507469e-05, 3.671646e-04, 1.744032e-03, 6.278515e-03, 1.778913e-02, 4.066086e-02, 7.623911e-02, 1.185942e-01, 1.541724e-01, 1.681881e-01, 1.541724e-01, 1.185942e-01, 7.623911e-02, 4.066086e-02, 1.778913e-02, 6.278515e-03, 1.744032e-03, 3.671646e-04, 5.507469e-05, 5.245209e-06, 2.384186e-07};
00093 int smoothLen = 23;
00094
00095 fx = cvMat(1, smoothLen, FLOAT_MAT_TYPE, smoothp);
00096 fy = cvMat(derivLen, 1, FLOAT_MAT_TYPE, derivp);
00097 }
00098 break;
00099
00100 case LINE_VERTICAL:
00101 {
00102
00103 FLOAT_MAT_ELEM_TYPE derivp[] =
00104
00105 {1.000000e-16, 1.280000e-14, 7.696000e-13, 2.886400e-11, 7.562360e-10, 1.468714e-08, 2.189405e-07, 2.558828e-06, 2.374101e-05, 1.759328e-04, 1.042202e-03, 4.915650e-03, 1.829620e-02, 5.297748e-02, 1.169560e-01, 1.918578e-01, 2.275044e-01, 1.918578e-01, 1.169560e-01, 5.297748e-02, 1.829620e-02, 4.915650e-03, 1.042202e-03, 1.759328e-04, 2.374101e-05, 2.558828e-06, 2.189405e-07, 1.468714e-08, 7.562360e-10, 2.886400e-11, 7.696000e-13, 1.280000e-14, 1.000000e-16};
00106 int derivLen = 33;
00107 FLOAT_MAT_ELEM_TYPE smoothp[] = {-1.000000e-03, -2.200000e-02, -1.480000e-01, -1.940000e-01, 7.300000e-01, -1.940000e-01, -1.480000e-01, -2.200000e-02, -1.000000e-03};
00108
00109 int smoothLen = 9;
00110
00111 fy = cvMat(1, smoothLen, FLOAT_MAT_TYPE, smoothp);
00112 fx = cvMat(derivLen, 1, FLOAT_MAT_TYPE, derivp);
00113 }
00114 break;
00115 }
00116
00117 if(DEBUG_LINES) {
00118
00119 }
00120
00121 #warning "still check subtracting mean from image"
00122
00123 CvScalar mean = cvAvg(inImage);
00124 cvSubS(inImage, mean, outImage);
00125
00126
00127
00128 cvFilter2D(outImage, outImage, &fx);
00129 cvFilter2D(outImage, outImage, &fy);
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 }
00176
00186 void mcvGetGaussianKernel(CvMat *kernel, unsigned char w, FLOAT sigma)
00187 {
00188
00189 sigma *= sigma;
00190
00191
00192 for (double i=-w; i<=w; i++)
00193 CV_MAT_ELEM(*kernel, FLOAT_MAT_ELEM_TYPE, int(i+w), 0) =
00194 (FLOAT_MAT_ELEM_TYPE) exp(-(.5/sigma)*(i*i));
00195 }
00196
00206 void mcvGet2DerivativeGaussianKernel(CvMat *kernel,
00207 unsigned char w, FLOAT sigma)
00208 {
00209
00210 sigma *= sigma;
00211
00212
00213 for (double i=-w; i<=w; i++)
00214 CV_MAT_ELEM(*kernel, FLOAT_MAT_ELEM_TYPE, int(i+w), 0) =
00215 (FLOAT_MAT_ELEM_TYPE)
00216 (exp(-.5*i*i)/sigma - (i*i)*exp(-(.5/sigma)*i*i)/(sigma*sigma));
00217 }
00218
00219
00234 void mcvGetHVLines(const CvMat *inImage, vector <Line> *lines,
00235 vector <FLOAT> *lineScores, LineType lineType,
00236 FLOAT linePixelWidth, bool binarize, bool localMaxima,
00237 FLOAT detectionThreshold, bool smoothScores)
00238 {
00239 CvMat * image = cvCloneMat(inImage);
00240
00241 if (binarize)
00242 {
00243
00244 image = cvCreateMat(inImage->rows, inImage->cols, INT_MAT_TYPE);
00245 cvThreshold(inImage, image, 0, 1, CV_THRESH_BINARY);
00246 }
00247
00248
00249
00250 CvMat sumLines, *sumLinesp;
00251 int maxLineLoc = 0;
00252 switch (lineType)
00253 {
00254 case LINE_HORIZONTAL:
00255 sumLinesp = cvCreateMat(image->height, 1, FLOAT_MAT_TYPE);
00256 cvReduce(image, sumLinesp, 1, CV_REDUCE_SUM);
00257 cvReshape(sumLinesp, &sumLines, 0, 0);
00258
00259 maxLineLoc = image->height-1;
00260 break;
00261 case LINE_VERTICAL:
00262 sumLinesp = cvCreateMat(1, image->width, FLOAT_MAT_TYPE);
00263 cvReduce(image, sumLinesp, 0, CV_REDUCE_SUM);
00264 cvReshape(sumLinesp, &sumLines, 0, image->width);
00265
00266 maxLineLoc = image->width-1;
00267 break;
00268 }
00269
00270
00271
00272
00273 float smoothp[] = {
00274 0.000003726653172, 0.000040065297393, 0.000335462627903, 0.002187491118183,
00275 0.011108996538242, 0.043936933623407, 0.135335283236613, 0.324652467358350,
00276 0.606530659712633, 0.882496902584595, 1.000000000000000, 0.882496902584595,
00277 0.606530659712633, 0.324652467358350, 0.135335283236613, 0.043936933623407,
00278 0.011108996538242, 0.002187491118183, 0.000335462627903, 0.000040065297393,
00279 0.000003726653172};
00280
00281 int smoothWidth = 21;
00282 CvMat smooth = cvMat(1, smoothWidth, CV_32FC1, smoothp);
00283 if (smoothScores)
00284 cvFilter2D(&sumLines, &sumLines, &smooth);
00285
00286
00287
00288
00289
00290 vector <int> sumLinesMaxLoc;
00291 vector <double> sumLinesMax;
00292 int maxLoc; double max;
00293
00294 #define MAX_IGNORE 0 //(int(smoothWidth/2.)+1)
00295 #define LOCAL_MAX_IGNORE (int(MAX_IGNORE/4))
00296 mcvGetVectorMax(&sumLines, &max, &maxLoc, MAX_IGNORE);
00297
00298
00299 if (localMaxima)
00300 {
00301
00302 for(int i=1+LOCAL_MAX_IGNORE; i<sumLines.rows-1-LOCAL_MAX_IGNORE; i++)
00303 {
00304
00305 FLOAT val = CV_MAT_ELEM(sumLines, FLOAT_MAT_ELEM_TYPE, i, 0);
00306
00307 if( (val > CV_MAT_ELEM(sumLines, FLOAT_MAT_ELEM_TYPE, i-1, 0))
00308 && (val > CV_MAT_ELEM(sumLines, FLOAT_MAT_ELEM_TYPE, i+1, 0))
00309
00310 && (val >= detectionThreshold) )
00311 {
00312
00313 vector<double>::iterator j;
00314 vector<int>::iterator k;
00315
00316 for(j=sumLinesMax.begin(), k=sumLinesMaxLoc.begin();
00317 j != sumLinesMax.end() && val<= *j; j++,k++);
00318
00319 sumLinesMax.insert(j, val);
00320 sumLinesMaxLoc.insert(k, i);
00321 }
00322 }
00323 }
00324
00325
00326 if(sumLinesMax.size()==0 && max>detectionThreshold)
00327 {
00328
00329 sumLinesMaxLoc.push_back(maxLoc);
00330 sumLinesMax.push_back(max);
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 for (int i=0; i<(int)sumLinesMax.size(); i++)
00361 {
00362
00363 double maxLocAcc = mcvGetLocalMaxSubPixel(
00364 CV_MAT_ELEM(sumLines, FLOAT_MAT_ELEM_TYPE, MAX(sumLinesMaxLoc[i]-1,0), 0),
00365 CV_MAT_ELEM(sumLines, FLOAT_MAT_ELEM_TYPE, sumLinesMaxLoc[i], 0),
00366 CV_MAT_ELEM(sumLines, FLOAT_MAT_ELEM_TYPE,
00367 MIN(sumLinesMaxLoc[i]+1,maxLineLoc), 0) );
00368 maxLocAcc += sumLinesMaxLoc[i];
00369 maxLocAcc = MIN(MAX(0, maxLocAcc), maxLineLoc);
00370
00371
00372
00373
00374
00375 Line line;
00376 switch (lineType)
00377 {
00378 case LINE_HORIZONTAL:
00379 line.startPoint.x = 0.5;
00380 line.startPoint.y = (FLOAT)maxLocAcc + .5;
00381 line.endPoint.x = inImage->width-.5;
00382 line.endPoint.y = line.startPoint.y;
00383 break;
00384 case LINE_VERTICAL:
00385 line.startPoint.x = (FLOAT)maxLocAcc + .5;
00386 line.startPoint.y = .5;
00387 line.endPoint.x = line.startPoint.x;
00388 line.endPoint.y = inImage->height-.5;
00389 break;
00390 }
00391 (*lines).push_back(line);
00392 if (lineScores)
00393 (*lineScores).push_back(sumLinesMax[i]);
00394 }
00395
00396 if(DEBUG_LINES)
00397 {
00398 CvMat *im, *im2 = cvCloneMat(image);
00399 if (binarize)
00400 cvConvertScale(im2, im2, 255, 0);
00401
00402 if (binarize)
00403 im = cvCreateMat(image->rows, image->cols, CV_8UC3);
00404 else
00405 im = cvCreateMat(image->rows, image->cols, CV_32FC3);
00406 mcvScaleMat(im2, im2);
00407 cvCvtColor(im2, im, CV_GRAY2RGB);
00408 for (unsigned int i=0; i<lines->size(); i++)
00409 {
00410 Line line = (*lines)[i];
00411 mcvIntersectLineWithBB(&line, cvSize(image->cols, image->rows), &line);
00412 if (binarize)
00413 mcvDrawLine(im, line, CV_RGB(255,0,0), 1);
00414 else
00415 mcvDrawLine(im, line, CV_RGB(1,0,0), 1);
00416 }
00417
00418 char str[256];
00419 switch (lineType)
00420 {
00421 case LINE_HORIZONTAL:
00422 sprintf(str, "%s", "Horizontal Lines");
00423 break;
00424 case LINE_VERTICAL:
00425 sprintf(str, "%s", "Vertical Lines");
00426 break;
00427 }
00428 SHOW_IMAGE(im, str, 10);
00429 cvReleaseMat(&im);
00430 cvReleaseMat(&im2);
00431 }
00432
00433
00434 cvReleaseMat(&sumLinesp);
00435
00436 sumLinesMax.clear();
00437 sumLinesMaxLoc.clear();
00438 cvReleaseMat(&image);
00439 }
00440
00441
00463 void mcvGetHoughTransformLines(const CvMat *inImage, vector <Line> *lines,
00464 vector <FLOAT> *lineScores,
00465 FLOAT rMin, FLOAT rMax, FLOAT rStep,
00466 FLOAT thetaMin, FLOAT thetaMax,
00467 FLOAT thetaStep, bool binarize, bool localMaxima,
00468 FLOAT detectionThreshold, bool smoothScores,
00469 bool group, FLOAT groupThreshold)
00470 {
00471 CvMat *image;
00472
00473
00474 if (!binarize)
00475 {
00476 image = cvCloneMat(inImage); assert(image!=0);
00477
00478 }
00479
00480 else
00481 {
00482 image = cvCreateMat(inImage->rows, inImage->cols, INT_MAT_TYPE);
00483 cvThreshold(inImage, image, 0, 1, CV_THRESH_BINARY);
00484
00485
00486
00487
00488
00489
00490 }
00491
00492 if(DEBUG_LINES)
00493 {
00494 SHOW_IMAGE(image, "Hough thresholded image", 10);
00495 }
00496
00497
00498 int rBins = int((rMax-rMin)/rStep);
00499 int thetaBins = int((thetaMax-thetaMin)/thetaStep);
00500 CvMat *houghSpace = cvCreateMat(rBins, thetaBins, CV_MAT_TYPE(image->type));
00501 assert(houghSpace!=0);
00502
00503 cvSet(houghSpace, cvRealScalar(0));
00504
00505
00506 FLOAT *rs = new FLOAT[rBins];
00507 FLOAT *thetas = new FLOAT[thetaBins];
00508 FLOAT r, theta;
00509 int ri, thetai;
00510 for (r=rMin+rStep/2, ri=0 ; ri<rBins; ri++,r+=rStep)
00511 rs[ri] = r;
00512 for (theta=thetaMin, thetai=0 ; thetai<thetaBins; thetai++,
00513 theta+=thetaStep)
00514 thetas[thetai] = theta;
00515
00516
00517 int nzCount = cvCountNonZero(image);
00518 CvMat *nzPoints = cvCreateMat(nzCount, 2, CV_32SC1);
00519 int idx = 0;
00520 for (int i=0; i<image->width; i++)
00521 for (int j=0; j<image->height; j++)
00522 if ( cvGetReal2D(image, j, i) )
00523 {
00524 CV_MAT_ELEM(*nzPoints, int, idx, 0) = i;
00525 CV_MAT_ELEM(*nzPoints, int, idx, 1) = j;
00526 idx++;
00527 }
00528
00529
00530
00531
00532
00533
00534
00535 int i, k;
00536 for (i=0; i<nzCount; i++)
00537 for (k=0; k<thetaBins; k++)
00538 {
00539
00540 theta = thetas[k];
00541 float rval = CV_MAT_ELEM(*nzPoints, int, i, 0) * cos(theta) +
00542 CV_MAT_ELEM(*nzPoints, int, i, 1) * sin(theta);
00543 int r = (int)( ( rval - rMin) / rStep);
00544
00545
00546
00547
00548 if (r>=0 && r<rBins)
00549 {
00550 if(binarize)
00551 CV_MAT_ELEM(*houghSpace, INT_MAT_ELEM_TYPE, r, k)++;
00552
00553 }
00554 else
00555 {
00556 CV_MAT_ELEM(*houghSpace, FLOAT_MAT_ELEM_TYPE, r, k)+=
00557 CV_MAT_ELEM(*image, FLOAT_MAT_ELEM_TYPE,
00558 CV_MAT_ELEM(*nzPoints, int, i, 1),
00559 CV_MAT_ELEM(*nzPoints, int, i, 0));
00560 }
00561 }
00562
00563
00564 cvReleaseMat(&nzPoints);
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 if (smoothScores)
00618 cvSmooth(houghSpace, houghSpace, CV_GAUSSIAN, 3);
00619
00620
00621 vector <double> maxLineScores;
00622 vector <CvPoint> maxLineLocs;
00623 if (localMaxima)
00624 {
00625
00626 mcvGetMatLocalMax(houghSpace, maxLineScores, maxLineLocs, detectionThreshold);
00627 }
00628 else
00629 {
00630
00631 mcvGetMatMax(houghSpace, maxLineScores, maxLineLocs, detectionThreshold);
00632 }
00633
00634
00635 double maxLineScore;
00636 CvPoint maxLineLoc;
00637 cvMinMaxLoc(houghSpace, 0, &maxLineScore, 0, &maxLineLoc);
00638 if (maxLineScores.size()==0 && maxLineScore>=detectionThreshold)
00639 {
00640 maxLineScores.push_back(maxLineScore);
00641 maxLineLocs.push_back(maxLineLoc);
00642 }
00643
00644
00645 if(DEBUG_LINES)
00646 {
00647
00648
00649 {
00650 CvMat *im, *im2 = cvCloneMat(image);
00651 if (binarize)
00652 cvConvertScale(im2, im2, 255, 0);
00653
00654 if (binarize)
00655 im = cvCreateMat(image->rows, image->cols, CV_8UC3);
00656 else
00657 im = cvCreateMat(image->rows, image->cols, CV_32FC3);
00658 cvCvtColor(im2, im, CV_GRAY2RGB);
00659 for (int i=0; i<(int)maxLineScores.size(); i++)
00660 {
00661 Line line;
00662 assert(maxLineLocs[i].x>=0 && maxLineLocs[i].x<thetaBins);
00663 assert(maxLineLocs[i].y>=0 && maxLineLocs[i].y<rBins);
00664 mcvIntersectLineRThetaWithBB(rs[maxLineLocs[i].y], thetas[maxLineLocs[i].x],
00665 cvSize(image->cols, image->rows), &line);
00666 if (binarize)
00667 mcvDrawLine(im, line, CV_RGB(255,0,0), 1);
00668 else
00669 mcvDrawLine(im, line, CV_RGB(1,0,0), 1);
00670 }
00671 SHOW_IMAGE(im, "Hough before grouping", 10);
00672 cvReleaseMat(&im);
00673 cvReleaseMat(&im2);
00674
00675
00676
00677
00678
00679
00680 }
00681 }
00682
00683
00684 if (group && maxLineScores.size()>1)
00685 {
00686
00687 bool stop = false;
00688 while (!stop)
00689 {
00690
00691 float minDist = groupThreshold+5, dist = 0.;
00692 vector<CvPoint>::iterator iloc, jloc,
00693 minIloc=maxLineLocs.begin(), minJloc=minIloc+1;
00694 vector<double>::iterator iscore, jscore, minIscore, minJscore;
00695
00696 for (iloc=maxLineLocs.begin(), iscore=maxLineScores.begin();
00697 iloc!=maxLineLocs.end(); iloc++, iscore++)
00698 for (jscore=iscore+1, jloc=iloc+1; jscore!=maxLineScores.end();
00699 jloc++, jscore++)
00700 {
00701
00702 float t1 = thetas[iloc->x]<0 ? thetas[iloc->x] : thetas[iloc->x]+CV_PI;
00703 float t2 = thetas[jloc->x]<0 ? thetas[jloc->x] : thetas[jloc->x]+CV_PI;
00704
00705 dist = fabs(rs[iloc->y]-rs[jloc->y]) +
00706 0.1 * fabs(t1 - t2);
00707
00708 if (dist<minDist)
00709 {
00710 minDist = dist;
00711 minIloc = iloc; minIscore = iscore;
00712 minJloc = jloc; minJscore = jscore;
00713 }
00714 }
00715
00716 if (minDist >= groupThreshold)
00717 stop = true;
00718 else
00719 {
00720
00721
00722
00723
00724
00725
00726
00727
00728 double x = (minIloc->x * *minIscore + minJloc->x * *minJscore) /
00729 (*minIscore + *minJscore);
00730 double y = (minIloc->y * *minIscore + minJloc->y * *minJscore) /
00731 (*minIscore + *minJscore);
00732
00733 minIloc->x = (int)x;
00734 minIloc->y = (int)y;
00735 *minIscore = (*minJscore + *minIscore)/2;
00736
00737 maxLineLocs.erase(minJloc);
00738 maxLineScores.erase(minJscore);
00739
00740
00741
00742
00743
00744
00745
00746
00747 for (iscore=maxLineScores.begin(), iloc=maxLineLocs.begin();
00748 iscore!=maxLineScores.end() && *minIscore <= *iscore;
00749 iscore++, iloc++);
00750
00751 if (iscore!=minIscore )
00752 {
00753
00754 maxLineScores.insert(iscore, *minIscore);
00755 maxLineLocs.insert(iloc, *minIloc);
00756
00757 maxLineScores.erase(minIscore);
00758 maxLineLocs.erase(minIloc);
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776 }
00777
00778
00779
00780
00781 }
00782 }
00783 }
00784
00785 if(DEBUG_LINES)
00786 {
00787 CvMat *im, *im2 = cvCloneMat(image);
00788 if (binarize)
00789 cvConvertScale(im2, im2, 255, 0);
00790 if (binarize)
00791 im = cvCreateMat(image->rows, image->cols, CV_8UC3);
00792 else
00793 im = cvCreateMat(image->rows, image->cols, CV_32FC3);
00794 cvCvtColor(im2, im, CV_GRAY2RGB);
00795 for (int i=0; i<(int)maxLineScores.size(); i++)
00796 {
00797 Line line;
00798 assert(maxLineLocs[i].x>=0 && maxLineLocs[i].x<thetaBins);
00799 assert(maxLineLocs[i].y>=0 && maxLineLocs[i].y<rBins);
00800 mcvIntersectLineRThetaWithBB(rs[maxLineLocs[i].y],
00801 thetas[maxLineLocs[i].x],
00802 cvSize(image->cols, image->rows), &line);
00803 if (binarize)
00804 mcvDrawLine(im, line, CV_RGB(255,0,0), 1);
00805 else
00806 mcvDrawLine(im, line, CV_RGB(1,0,0), 1);
00807 }
00808 SHOW_IMAGE(im, "Hough after grouping", 10);
00809 cvReleaseMat(&im);
00810 cvReleaseMat(&im2);
00811
00812
00813 CvMat *houghSpaceClr;
00814 if(binarize)
00815 houghSpaceClr = cvCreateMat(houghSpace->height, houghSpace->width,
00816 CV_8UC3);
00817 else
00818 houghSpaceClr = cvCreateMat(houghSpace->height, houghSpace->width,
00819 CV_32FC3);
00820 mcvScaleMat(houghSpace, houghSpace);
00821 cvCvtColor(houghSpace, houghSpaceClr, CV_GRAY2RGB);
00822 for (int i=0; i<(int)maxLineLocs.size(); i++)
00823 cvCircle(houghSpaceClr, cvPoint(maxLineLocs[i].x, maxLineLocs[i].y),
00824 1, CV_RGB(1, 0, 0), -1);
00825
00826
00827
00828
00829
00830
00831 SHOW_IMAGE(houghSpaceClr, "Hough Space", 10);
00832 cvReleaseMat(&houghSpaceClr);
00833
00834 }
00835
00836
00837 for(int i=0; i<int(maxLineScores.size()); i++)
00838 {
00839
00840 if (maxLineScores[i]>=detectionThreshold)
00841 {
00842
00843
00844
00845 Line line;
00846 assert(maxLineLocs[i].x>=0 && maxLineLocs[i].x<thetaBins);
00847 assert(maxLineLocs[i].y>=0 && maxLineLocs[i].y<rBins);
00848 mcvIntersectLineRThetaWithBB(rs[maxLineLocs[i].y],
00849 thetas[maxLineLocs[i].x],
00850 cvSize(image->cols, image->rows), &line);
00851
00852
00853 lines->push_back(line);
00854 if (lineScores)
00855 (*lineScores).push_back(maxLineScores[i]);
00856
00857 }
00858
00859 else
00860 {
00861
00862 break;
00863 }
00864 }
00865
00866
00867 cvReleaseMat(&image);
00868 cvReleaseMat(&houghSpace);
00869
00870 delete [] rs;
00871 delete [] thetas;
00872 maxLineScores.clear();
00873 maxLineLocs.clear();
00874 }
00875
00876
00877
00883 void mcvBinarizeImage(CvMat *inImage)
00884 {
00885
00886 if (CV_MAT_TYPE(inImage->type)==FLOAT_MAT_TYPE)
00887 {
00888 for (int i=0; i<inImage->height; i++)
00889 for (int j=0; j<inImage->width; j++)
00890 if (CV_MAT_ELEM(*inImage, FLOAT_MAT_ELEM_TYPE, i, j) != 0.f)
00891 CV_MAT_ELEM(*inImage, FLOAT_MAT_ELEM_TYPE, i, j)=1;
00892 }
00893 else if (CV_MAT_TYPE(inImage->type)==INT_MAT_TYPE)
00894 {
00895 for (int i=0; i<inImage->height; i++)
00896 for (int j=0; j<inImage->width; j++)
00897 if (CV_MAT_ELEM(*inImage, INT_MAT_ELEM_TYPE, i, j) != 0)
00898 CV_MAT_ELEM(*inImage, INT_MAT_ELEM_TYPE, i, j)=1;
00899 }
00900 else
00901 {
00902 cerr << "Unsupported type in mcvBinarizeImage\n";
00903 exit(1);
00904 }
00905 }
00906
00907
00916 #define MCV_VECTOR_MAX(type) \
00917 \
00918 if (inVector->height==1) \
00919 { \
00920 \
00921 tmax = (double) CV_MAT_ELEM(*inVector, type, 0, inVector->width-1); \
00922 tmaxLoc = inVector->width-1; \
00923 \
00924 for (int i=inVector->width-1-ignore; i>=0+ignore; i--) \
00925 { \
00926 if (tmax<CV_MAT_ELEM(*inVector, type, 0, i)) \
00927 { \
00928 tmax = CV_MAT_ELEM(*inVector, type, 0, i); \
00929 tmaxLoc = i; \
00930 } \
00931 } \
00932 } \
00933 \
00934 else \
00935 { \
00936 \
00937 tmax = (double) CV_MAT_ELEM(*inVector, type, inVector->height-1, 0); \
00938 tmaxLoc = inVector->height-1; \
00939 \
00940 for (int i=inVector->height-1-ignore; i>=0+ignore; i--) \
00941 { \
00942 if (tmax<CV_MAT_ELEM(*inVector, type, i, 0)) \
00943 { \
00944 tmax = (double) CV_MAT_ELEM(*inVector, type, i, 0); \
00945 tmaxLoc = i; \
00946 } \
00947 } \
00948 } \
00949
00950 void mcvGetVectorMax(const CvMat *inVector, double *max, int *maxLoc, int ignore)
00951 {
00952 double tmax;
00953 int tmaxLoc;
00954
00955 if (CV_MAT_TYPE(inVector->type)==FLOAT_MAT_TYPE)
00956 {
00957 MCV_VECTOR_MAX(FLOAT_MAT_ELEM_TYPE)
00958 }
00959 else if (CV_MAT_TYPE(inVector->type)==INT_MAT_TYPE)
00960 {
00961 MCV_VECTOR_MAX(INT_MAT_ELEM_TYPE)
00962 }
00963 else
00964 {
00965 cerr << "Unsupported type in mcvGetVectorMax\n";
00966 exit(1);
00967 }
00968
00969
00970 if (max)
00971 *max = tmax;
00972 if (maxLoc)
00973 *maxLoc = tmaxLoc;
00974 }
00975
00976
00977
00988 void mcvGetMatLocalMax(const CvMat *inMat, vector<double> &localMaxima,
00989 vector<CvPoint> &localMaximaLoc, double threshold)
00990 {
00991
00992 double val;
00993
00994 #define MCV_MAT_LOCAL_MAX(type) \
00995 \
00996 \
00997 for(int i=1; i<inMat->rows-1; i++) \
00998 for (int j=1; j<inMat->cols-1; j++) \
00999 { \
01000 \
01001 val = CV_MAT_ELEM(*inMat, type, i, j); \
01002 \
01003 if( val > CV_MAT_ELEM(*inMat, type, i-1, j-1) && \
01004 val > CV_MAT_ELEM(*inMat, type, i-1, j) && \
01005 val > CV_MAT_ELEM(*inMat, type, i-1, j+1) && \
01006 val > CV_MAT_ELEM(*inMat, type, i, j-1) && \
01007 val > CV_MAT_ELEM(*inMat, type, i, j+1) && \
01008 val > CV_MAT_ELEM(*inMat, type, i+1, j-1) && \
01009 val > CV_MAT_ELEM(*inMat, type, i+1, j) && \
01010 val > CV_MAT_ELEM(*inMat, type, i+1, j+1) && \
01011 val >= threshold) \
01012 { \
01013 \
01014 \
01015 \
01016 vector<double>::iterator k; \
01017 vector<CvPoint>::iterator l; \
01018 \
01019 for(k=localMaxima.begin(), l=localMaximaLoc.begin(); \
01020 k != localMaxima.end() && val<= *k; k++,l++); \
01021 \
01022 localMaxima.insert(k, val); \
01023 localMaximaLoc.insert(l, cvPoint(j, i)); \
01024 } \
01025 }
01026
01027
01028 if (CV_MAT_TYPE(inMat->type)==FLOAT_MAT_TYPE)
01029 {
01030 MCV_MAT_LOCAL_MAX(FLOAT_MAT_ELEM_TYPE)
01031 }
01032 else if (CV_MAT_TYPE(inMat->type)==INT_MAT_TYPE)
01033 {
01034 MCV_MAT_LOCAL_MAX(INT_MAT_ELEM_TYPE)
01035 }
01036 else
01037 {
01038 cerr << "Unsupported type in mcvGetMatLocalMax\n";
01039 exit(1);
01040 }
01041 }
01042
01053 void mcvGetMatMax(const CvMat *inMat, vector<double> &maxima,
01054 vector<CvPoint> &maximaLoc, double threshold)
01055 {
01056
01057 double val;
01058
01059 #define MCV_MAT_MAX(type) \
01060 \
01061 \
01062 for(int i=1; i<inMat->rows-1; i++) \
01063 for (int j=1; j<inMat->cols-1; j++) \
01064 { \
01065 \
01066 val = CV_MAT_ELEM(*inMat, type, i, j); \
01067 \
01068 if (val >= threshold) \
01069 { \
01070 \
01071 \
01072 \
01073 vector<double>::iterator k; \
01074 vector<CvPoint>::iterator l; \
01075 \
01076 for(k=maxima.begin(), l=maximaLoc.begin(); \
01077 k != maxima.end() && val<= *k; k++,l++); \
01078 \
01079 maxima.insert(k, val); \
01080 maximaLoc.insert(l, cvPoint(j, i)); \
01081 } \
01082 }
01083
01084
01085 if (CV_MAT_TYPE(inMat->type)==FLOAT_MAT_TYPE)
01086 {
01087 MCV_MAT_MAX(FLOAT_MAT_ELEM_TYPE)
01088 }
01089 else if (CV_MAT_TYPE(inMat->type)==INT_MAT_TYPE)
01090 {
01091 MCV_MAT_MAX(INT_MAT_ELEM_TYPE)
01092 }
01093 else
01094 {
01095 cerr << "Unsupported type in mcvGetMatMax\n";
01096 exit(1);
01097 }
01098 }
01099
01100
01108 #define MCV_VECTOR_LOCAL_MAX(type) \
01109 \
01110 \
01111 if(inVec->height == 1) \
01112 { \
01113 for(int i=1; i<inVec->width-1; i++) \
01114 { \
01115 \
01116 val = CV_MAT_ELEM(*inVec, type, 0, i); \
01117 \
01118 if( val > CV_MAT_ELEM(*inVec, type, 0, i-1) && \
01119 val > CV_MAT_ELEM(*inVec, type, 0, i+1) ) \
01120 { \
01121 \
01122 \
01123 \
01124 vector<double>::iterator k; \
01125 vector<int>::iterator l; \
01126 \
01127 for(k=localMaxima.begin(), l=localMaximaLoc.begin(); \
01128 k != localMaxima.end() && val<= *k; k++,l++); \
01129 \
01130 localMaxima.insert(k, val); \
01131 localMaximaLoc.insert(l, i); \
01132 } \
01133 } \
01134 } \
01135 else \
01136 { \
01137 for(int i=1; i<inVec->height-1; i++) \
01138 { \
01139 \
01140 val = CV_MAT_ELEM(*inVec, type, i, 0); \
01141 \
01142 if( val > CV_MAT_ELEM(*inVec, type, i-1, 0) && \
01143 val > CV_MAT_ELEM(*inVec, type, i+1, 0) ) \
01144 { \
01145 \
01146 \
01147 \
01148 vector<double>::iterator k; \
01149 vector<int>::iterator l; \
01150 \
01151 for(k=localMaxima.begin(), l=localMaximaLoc.begin(); \
01152 k != localMaxima.end() && val<= *k; k++,l++); \
01153 \
01154 localMaxima.insert(k, val); \
01155 localMaximaLoc.insert(l, i); \
01156 } \
01157 } \
01158 }
01159
01160 void mcvGetVectorLocalMax(const CvMat *inVec, vector<double> &localMaxima,
01161 vector<int> &localMaximaLoc)
01162 {
01163
01164 double val;
01165
01166
01167 if (CV_MAT_TYPE(inVec->type)==FLOAT_MAT_TYPE)
01168 {
01169 MCV_VECTOR_LOCAL_MAX(FLOAT_MAT_ELEM_TYPE)
01170 }
01171 else if (CV_MAT_TYPE(inVec->type)==INT_MAT_TYPE)
01172 {
01173 MCV_VECTOR_LOCAL_MAX(INT_MAT_ELEM_TYPE)
01174 }
01175 else
01176 {
01177 cerr << "Unsupported type in mcvGetVectorLocalMax\n";
01178 exit(1);
01179 }
01180 }
01181
01182
01190 FLOAT mcvGetQuantile(const CvMat *mat, FLOAT qtile)
01191 {
01192
01193 CvMat rowMat;
01194 cvReshape(mat, &rowMat, 0, 1);
01195
01196
01197 FLOAT qval;
01198 qval = quantile((FLOAT*) rowMat.data.ptr, rowMat.width, qtile);
01199
01200 return qval;
01201 }
01202
01203
01213 void mcvThresholdLower(const CvMat *inMat, CvMat *outMat, FLOAT threshold)
01214 {
01215
01216 #define MCV_THRESHOLD_LOWER(type) \
01217 for (int i=0; i<inMat->height; i++) \
01218 for (int j=0; j<inMat->width; j++) \
01219 if ( CV_MAT_ELEM(*inMat, type, i, j)<threshold) \
01220 CV_MAT_ELEM(*outMat, type, i, j)=(type) 0; \
01221
01222
01223 if (inMat != outMat)
01224 cvCopy(inMat, outMat);
01225
01226
01227 if (CV_MAT_TYPE(inMat->type)==FLOAT_MAT_TYPE)
01228 {
01229 MCV_THRESHOLD_LOWER(FLOAT_MAT_ELEM_TYPE)
01230 }
01231 else if (CV_MAT_TYPE(inMat->type)==INT_MAT_TYPE)
01232 {
01233 MCV_THRESHOLD_LOWER(INT_MAT_ELEM_TYPE)
01234 }
01235 else
01236 {
01237 cerr << "Unsupported type in mcvGetVectorMax\n";
01238 exit(1);
01239 }
01240 }
01241
01255 void mcvGetStopLines(const CvMat *inImage, vector<Line> *stopLines,
01256 vector<FLOAT> *lineScores, const CameraInfo *cameraInfo,
01257 LaneDetectorConf *stopLineConf)
01258
01259 {
01260 cout<<"ENTER - mcvGetStopLines"<<endl;
01261
01262 CvSize inSize = cvSize(inImage->width, inImage->height);
01263
01264
01265 CvMat *image = cvCloneMat(inImage);
01266
01267
01268 IPMInfo ipmInfo;
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287 CvSize ipmSize = cvSize((int)stopLineConf->ipmWidth,
01288 (int)stopLineConf->ipmHeight);
01289 CvMat * ipm;
01290 ipm = cvCreateMat(ipmSize.height, ipmSize.width, inImage->type);
01291
01292 ipmInfo.vpPortion = stopLineConf->ipmVpPortion;
01293 ipmInfo.ipmLeft = stopLineConf->ipmLeft;
01294 ipmInfo.ipmRight = stopLineConf->ipmRight;
01295 ipmInfo.ipmTop = stopLineConf->ipmTop;
01296 ipmInfo.ipmBottom = stopLineConf->ipmBottom;
01297 ipmInfo.ipmInterpolation = stopLineConf->ipmInterpolation;
01298 list<CvPoint> outPixels;
01299 list<CvPoint>::iterator outPixelsi;
01300 cout<<"-> ERROR <-"<<endl;
01301 mcvGetIPM(image, ipm, &ipmInfo, cameraInfo, &outPixels);
01302
01303
01304
01305
01306
01307 CvMat *dbIpmImage;
01308 if(DEBUG_LINES) {
01309 dbIpmImage = cvCreateMat(ipm->height, ipm->width, ipm->type);
01310 cvCopy(ipm, dbIpmImage);
01311 }
01312
01313
01314
01315 FLOAT stopLinePixelWidth = stopLineConf->lineWidth * ipmInfo.xScale;
01316
01317 FLOAT stopLinePixelHeight = stopLineConf->lineHeight * ipmInfo.yScale;
01318
01319
01320
01321 FLOAT sigmax = stopLinePixelWidth;
01322 FLOAT sigmay = stopLinePixelHeight;
01323
01324 if(DEBUG_LINES) {
01325
01326
01327 }
01328
01329
01330 mcvFilterLines(ipm, ipm, stopLineConf->kernelWidth,
01331 stopLineConf->kernelHeight, sigmax, sigmay,
01332 LINE_HORIZONTAL);
01333
01334
01335 for(outPixelsi=outPixels.begin(); outPixelsi!=outPixels.end(); outPixelsi++)
01336 CV_MAT_ELEM(*ipm, float, (*outPixelsi).y, (*outPixelsi).x) = 0;
01337 outPixels.clear();
01338
01339
01340 mcvThresholdLower(ipm, ipm, 0);
01341
01342
01343 FLOAT qtileThreshold = mcvGetQuantile(ipm, stopLineConf->lowerQuantile);
01344 mcvThresholdLower(ipm, ipm, qtileThreshold);
01345
01346
01347 CvMat *dbIpmImageThresholded;
01348 if(DEBUG_LINES) {
01349 dbIpmImageThresholded = cvCreateMat(ipm->height, ipm->width, ipm->type);
01350 cvCopy(ipm, dbIpmImageThresholded);
01351 }
01352
01353
01354
01355
01356 switch(stopLineConf->groupingType)
01357 {
01358
01359 case GROUPING_TYPE_HV_LINES:
01360
01361
01362 mcvGetHVLines(ipm, stopLines, lineScores, LINE_HORIZONTAL,
01363 stopLinePixelHeight, stopLineConf->binarize,
01364 stopLineConf->localMaxima, stopLineConf->detectionThreshold,
01365 stopLineConf->smoothScores);
01366 break;
01367
01368
01369 case GROUPING_TYPE_HOUGH_LINES:
01370
01371
01372
01373 mcvGetHoughTransformLines(ipm, stopLines, lineScores,
01374 stopLineConf->rMin, stopLineConf->rMax,
01375 stopLineConf->rStep, stopLineConf->thetaMin,
01376 stopLineConf->thetaMax, stopLineConf->thetaStep,
01377 stopLineConf->binarize, stopLineConf->localMaxima,
01378 stopLineConf->detectionThreshold,
01379 stopLineConf->smoothScores, stopLineConf->group,
01380 stopLineConf->groupThreshold);
01381 break;
01382 }
01383
01384
01385 if (stopLineConf->ransac)
01386 {
01387 mcvGetRansacLines(ipm, *stopLines, *lineScores, stopLineConf, LINE_HORIZONTAL);
01388 }
01389
01390 if(stopLineConf->getEndPoints)
01391 {
01392
01393 for(int i=0; i<(int)stopLines->size(); i++)
01394 mcvGetLineExtent(ipm, (*stopLines)[i], (*stopLines)[i]);
01395 }
01396
01397 vector <Line> dbIpmStopLines;
01398 if(DEBUG_LINES) {
01399 dbIpmStopLines = *stopLines;
01400
01401
01402
01403
01404
01405
01406 }
01407
01408
01409 if (stopLines->size()!=0)
01410 {
01411
01412 for (unsigned int i=0; i<stopLines->size(); i++)
01413 {
01414 Line *line;
01415 line = &(*stopLines)[i];
01416
01417 mcvPointImIPM2World(&(line->startPoint), &ipmInfo);
01418 mcvPointImIPM2World(&(line->endPoint), &ipmInfo);
01419 }
01420
01421
01422
01423 Line dummy = {{1.,1.},{2.,2.}};
01424 stopLines->insert(stopLines->begin(), dummy);
01425
01426 CvMat *mat = cvCreateMat(2, 2*stopLines->size(), FLOAT_MAT_TYPE);
01427 mcvLines2Mat(stopLines, mat);
01428 stopLines->clear();
01429 mcvTransformGround2Image(mat, mat, cameraInfo);
01430
01431 mcvMat2Lines(mat, stopLines);
01432
01433 stopLines->erase(stopLines->begin());
01434
01435 cvReleaseMat(&mat);
01436
01437
01438 for (unsigned int i=0; i<stopLines->size(); i++)
01439 {
01440
01441 mcvIntersectLineWithBB(&(*stopLines)[i], inSize, &(*stopLines)[i]);
01442
01443
01444
01445 }
01446
01447
01448 }
01449
01450
01451 if(DEBUG_LINES)
01452 {
01453
01454 SHOW_IMAGE(dbIpmImage, "IPM image", 10);
01455
01456 SHOW_IMAGE(dbIpmImageThresholded, "Stoplines thresholded IPM image", 10);
01457
01458
01459 for (int i=0; i<1 && dbIpmStopLines.size()>0; i++)
01460 {
01461 mcvDrawLine(dbIpmImage, dbIpmStopLines[i], CV_RGB(0,0,0), 3);
01462 }
01463 SHOW_IMAGE(dbIpmImage, "Stoplines IPM with lines", 10);
01464
01465
01466
01467
01468
01469 for (int i=0; i<1 && stopLines->size()>0; i++)
01470 {
01471
01472
01473 mcvDrawLine(image, (*stopLines)[i], CV_RGB(255,0,0), 3);
01474 }
01475 SHOW_IMAGE(image, "Detected Stoplines", 10);
01476
01477 cvReleaseMat(&dbIpmImage);
01478 cvReleaseMat(&dbIpmImageThresholded);
01479 dbIpmStopLines.clear();
01480 }
01481
01482
01483 cvReleaseMat(&ipm);
01484 cvReleaseMat(&image);
01485
01486 }
01487
01503 void mcvGetLanes(const CvMat *inImage, const CvMat* clrImage,
01504 vector<Line> *lanes, vector<FLOAT> *lineScores,
01505 vector<Spline> *splines, vector<float> *splineScores,
01506 CameraInfo *cameraInfo, LaneDetectorConf *stopLineConf,
01507 LineState* state)
01508 {
01509
01510
01511
01512
01513
01514
01515
01516 CvSize inSize = cvSize(inImage->width, inImage->height);
01517
01518
01519 CvMat *image = cvCloneMat(inImage);
01520
01521
01522
01523 IPMInfo ipmInfo;
01524
01525
01526 LineState newState;
01527 if(!state) state = &newState;
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546 CvSize ipmSize = cvSize((int)stopLineConf->ipmWidth,(int)stopLineConf->ipmHeight);
01547
01548
01549
01550 CvMat * ipm;
01551
01552
01553
01554 ipm = cvCreateMat(ipmSize.height, ipmSize.width, inImage->type);
01555
01556
01557 ipmInfo.vpPortion = stopLineConf->ipmVpPortion;
01558 ipmInfo.ipmLeft = stopLineConf->ipmLeft;
01559 ipmInfo.ipmRight = stopLineConf->ipmRight;
01560 ipmInfo.ipmTop = stopLineConf->ipmTop;
01561 ipmInfo.ipmBottom = stopLineConf->ipmBottom;
01562 ipmInfo.ipmInterpolation = stopLineConf->ipmInterpolation;
01563 list<CvPoint> outPixels;
01564 list<CvPoint>::iterator outPixelsi;
01565 mcvGetIPM(image, ipm, &ipmInfo, cameraInfo, &outPixels);
01566
01567
01568 SHOW_IMAGE(ipm, "IPM antes do tophat", 20);
01569
01570 IplConvKernel* element = cvCreateStructuringElementEx( 4,6,0,0,CV_SHAPE_RECT);
01571
01572 CvMat * temp = cvCreateMat(ipmSize.height, ipmSize.width, inImage->type);
01573
01574
01575 cvMorphologyEx( ipm , ipm, temp ,element,CV_MOP_TOPHAT,2);
01576 cvReleaseMat(&temp);
01577
01578
01579
01580
01581
01582
01583 #warning "Check: Smoothing IPM image"
01584
01585
01586
01587
01588
01589
01590
01591
01592 CvMat* rawipm = cvCloneMat(ipm);
01593
01594
01595
01596
01597
01598 CvMat *dbIpmImage;
01599
01600
01601 dbIpmImage = cvCreateMat(ipm->height, ipm->width, ipm->type);
01602 cvCopy(ipm, dbIpmImage);
01603
01604 SHOW_IMAGE(dbIpmImage, "IPM image", 20);
01605
01606
01607
01608 FLOAT stopLinePixelWidth = stopLineConf->lineWidth *
01609 ipmInfo.xScale;
01610
01611 FLOAT stopLinePixelHeight = stopLineConf->lineHeight *
01612 ipmInfo.yScale;
01613
01614
01615
01616 FLOAT sigmax = stopLinePixelWidth;
01617 FLOAT sigmay = stopLinePixelHeight;
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631 mcvFilterLines(ipm, ipm, stopLineConf->kernelWidth,
01632 stopLineConf->kernelHeight, sigmax, sigmay,
01633 LINE_VERTICAL);
01634
01635
01636
01637
01638
01639 for(outPixelsi=outPixels.begin(); outPixelsi!=outPixels.end(); outPixelsi++)
01640 {
01641 CV_MAT_ELEM(*ipm, float, (*outPixelsi).y, (*outPixelsi).x) = 0;
01642
01643 }
01644 outPixels.clear();
01645
01646 #warning "Check this clearing of IPM image for 2 lanes"
01647 if (stopLineConf->ipmWindowClear)
01648 {
01649
01650
01651 CvRect mask = cvRect(stopLineConf->ipmWindowLeft, 0,
01652 stopLineConf->ipmWindowRight -
01653 stopLineConf->ipmWindowLeft + 1,
01654 ipm->height);
01655 mcvSetMat(ipm, mask, 0);
01656 }
01657
01658
01659 if (DEBUG_LINES) {
01660 SHOW_IMAGE(ipm, "Lane unthresholded filtered", 10);
01661 }
01662
01663
01664
01665
01666 CvMat *fipm = cvCloneMat(ipm);
01667
01668
01669
01670 #warning "clean negative parts in filtered image"
01671 mcvThresholdLower(ipm, ipm, 0);
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683 vector <Line> dbIpmStopLines;
01684 vector<Spline> dbIpmSplines;
01685
01686
01687 int stripHeight = ipm->height / stopLineConf->numStrips;
01688 for (int i=0; i<stopLineConf->numStrips; i++)
01689 {
01690
01691 CvRect mask;
01692 mask = cvRect(0, i*stripHeight, ipm->width,
01693 stripHeight);
01694
01695
01696
01697 CvMat *subimage = cvCloneMat(ipm);
01698
01699 mcvSetMat(subimage, mask, 0);
01700
01701
01702 FLOAT qtileThreshold = mcvGetQuantile(subimage, stopLineConf->lowerQuantile);
01703 mcvThresholdLower(subimage, subimage, qtileThreshold);
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713 vector<Line> subimageLines;
01714 vector<Spline> subimageSplines;
01715 vector<float> subimageLineScores, subimageSplineScores;
01716
01717
01718
01719
01720 if(DEBUG_LINES) {
01721 CvMat *dbIpmImageThresholded;
01722 dbIpmImageThresholded = cvCreateMat(ipm->height, ipm->width, ipm->type);
01723 cvCopy(subimage, dbIpmImageThresholded);
01724 char str[256];
01725 sprintf(str, "Lanes #%d thresholded IPM", i);
01726
01727 SHOW_IMAGE(dbIpmImageThresholded, str, 10);
01728 cvReleaseMat(&dbIpmImageThresholded);
01729 }
01730
01731
01732 mcvGetLines(subimage, LINE_VERTICAL, subimageLines, subimageLineScores,
01733 subimageSplines, subimageSplineScores, stopLineConf,
01734 state);
01735
01736
01737
01738
01739 for (unsigned int k=0; k<subimageLines.size(); k++)
01740 {
01741 lanes->push_back(subimageLines[k]);
01742 lineScores->push_back(subimageLineScores[k]);
01743 }
01744 for (unsigned int k=0; k<subimageSplines.size(); k++)
01745 {
01746 splines->push_back(subimageSplines[k]);
01747 splineScores->push_back(subimageSplineScores[k]);
01748 }
01749
01750
01751 if(DEBUG_LINES) {
01752 for (unsigned int k=0; k<lanes->size(); k++)
01753 dbIpmStopLines.push_back((*lanes)[k]);
01754 for (unsigned int k=0; k<splines->size(); k++)
01755 dbIpmSplines.push_back((*splines)[k]);
01756
01757 CvMat *dbIpmImageThresholded;
01758 dbIpmImageThresholded = cvCreateMat(ipm->height, ipm->width, ipm->type);
01759 cvCopy(subimage, dbIpmImageThresholded);
01760 char str[256];
01761 sprintf(str, "Lanes #%d thresholded IPM", i);
01762
01763 SHOW_IMAGE(dbIpmImageThresholded, str, 10);
01764 cvReleaseMat(&dbIpmImageThresholded);
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774 }
01775
01776
01777 cvReleaseMat(&subimage);
01778 }
01779
01780
01781 mcvPostprocessLines(image, clrImage, fipm, ipm, *lanes, *lineScores,
01782 *splines, *splineScores,
01783 stopLineConf, state, ipmInfo, *cameraInfo);
01784
01785 if (DEBUG_LINES) {
01786 dbIpmSplines = state->ipmSplines;
01787 }
01788
01789
01790 if(DEBUG_LINES) {
01791 char str[256];
01792
01793
01794 if (stopLineConf->ransacLine || !stopLineConf->ransacSpline)
01795 for (int i=0; i<(int)dbIpmStopLines.size(); i++)
01796 mcvDrawLine(dbIpmImage, dbIpmStopLines[i], CV_RGB(0,0,0), 1);
01797 if (stopLineConf->ransacSpline)
01798 for (int i=0; i<(int)dbIpmSplines.size(); i++)
01799 mcvDrawSpline(dbIpmImage, dbIpmSplines[i], CV_RGB(0,0,0), 1);
01800
01801 SHOW_IMAGE(dbIpmImage, "Lanes IPM with lines", 10);
01802
01803 CvMat *imageClr = cvCreateMat(inImage->height, inImage->width, CV_32FC3);
01804 cvCvtColor(image, imageClr, CV_GRAY2RGB);
01805
01806
01807 if (stopLineConf->ransacLine || !stopLineConf->ransacSpline)
01808 for (int i=0; i<(int)lanes->size(); i++)
01809 mcvDrawLine(imageClr, (*lanes)[i], CV_RGB(255,0,0), 1);
01810 if (stopLineConf->ransacSpline)
01811 for (int i=0; i<(int)splines->size(); i++)
01812 {
01813 mcvDrawSpline(imageClr, (*splines)[i], CV_RGB(255,0,0), 1);
01814 sprintf(str, "%.2f", (*splineScores)[i]);
01815 mcvDrawText(imageClr, str,
01816 cvPointFrom32f((*splines)[i].points[(*splines)[i].degree]),
01817 .5, CV_RGB(0, 0, 255));
01818 }
01819
01820 SHOW_IMAGE(imageClr, "Detected lanes", 0);
01821
01822 cvReleaseMat(&dbIpmImage);
01823
01824 cvReleaseMat(&imageClr);
01825 dbIpmStopLines.clear();
01826 dbIpmSplines.clear();
01827 }
01828
01829
01830 cvReleaseMat(&ipm);
01831 cvReleaseMat(&image);
01832 cvReleaseMat(&fipm);
01833 cvReleaseMat(&rawipm);
01834
01835 }
01836
01837
01855 void mcvPostprocessLines(const CvMat* image, const CvMat* clrImage,
01856 const CvMat* rawipm, const CvMat* fipm,
01857 vector<Line> &lines, vector<float> &lineScores,
01858 vector<Spline> &splines, vector<float> &splineScores,
01859 LaneDetectorConf *lineConf, LineState *state,
01860 IPMInfo &ipmInfo, CameraInfo &cameraInfo)
01861 {
01862 CvSize inSize = cvSize(image->width-1, image->height-1);
01863
01864
01865 vector<Spline> keepSplines;
01866 vector<float> keepSplineScores;
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877 if (lineConf->ransacLine || !lineConf->ransacSpline)
01878 {
01879 mcvLinesImIPM2Im(lines, ipmInfo, cameraInfo, inSize);
01880 }
01881
01882 if (lineConf->ransacSpline)
01883 {
01884
01885 for(int i=0; i<(int)splines.size(); i++)
01886 {
01887
01888 int splineStatus = lineConf->checkIPMSplines ?
01889 mcvCheckSpline(splines[i],
01890 lineConf->checkIPMSplinesCurvenessThreshold,
01891 lineConf->checkIPMSplinesLengthThreshold,
01892 lineConf->checkIPMSplinesThetaDiffThreshold,
01893 lineConf->checkIPMSplinesThetaThreshold)
01894 : 0;
01895
01896
01897 if (!(((splineStatus & CurvedSpline) && (splineStatus & CurvedSplineTheta))
01898 || splineStatus & HorizontalSpline))
01899 {
01900
01901 CvMat *points = mcvEvalBezierSpline(splines[i], .1);
01902
01903
01904 CvMat* p = mcvExtendPoints(rawipm, points,
01905 lineConf->extendIPMAngleThreshold,
01906 lineConf->extendIPMMeanDirAngleThreshold,
01907 lineConf->extendIPMLinePixelsTangent,
01908 lineConf->extendIPMLinePixelsNormal,
01909 lineConf->extendIPMContThreshold,
01910 lineConf->extendIPMDeviationThreshold,
01911 cvRect(0, lineConf->extendIPMRectTop,
01912 rawipm->width-1,
01913 lineConf->extendIPMRectBottom-lineConf->extendIPMRectTop),
01914 false);
01915
01916 Spline spline = mcvFitBezierSpline(p, lineConf->ransacSplineDegree);
01917
01918
01919 #warning "Check this later: extension in IPM. Check threshold value"
01920
01921
01922
01923
01924
01925
01926
01927 float score = mcvGetSplineScore(fipm, splines[i],
01928 lineConf->splineScoreStep,
01929 lineConf->splineScoreJitter,
01930 lineConf->splineScoreLengthRatio,
01931 lineConf->splineScoreAngleRatio);
01932
01933 splineScores[i] = score;
01934
01935
01936 if (splineScores[i] >= lineConf->finalSplineScoreThreshold)
01937 {
01938 keepSplines.push_back(spline);
01939 keepSplineScores.push_back(splineScores[i]);
01940 }
01941
01942 cvReleaseMat(&points);
01943 cvReleaseMat(&p);
01944 }
01945 }
01946
01947
01948 splines.clear();
01949 splineScores.clear();
01950 splines = keepSplines;
01951 splineScores = keepSplineScores;
01952 keepSplines.clear();
01953 keepSplineScores.clear();
01954
01955
01956
01957
01958
01959
01960
01961 state->ipmSplines.clear();
01962 state->ipmSplines = splines;
01963
01964
01965 mcvSplinesImIPM2Im(splines, ipmInfo, cameraInfo, inSize);
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981 for(int i=0; i<(int)splines.size(); i++)
01982 {
01983
01984 int splineStatus = lineConf->checkSplines ?
01985 mcvCheckSpline(splines[i],
01986 lineConf->checkSplinesCurvenessThreshold,
01987 lineConf->checkSplinesLengthThreshold,
01988 lineConf->checkSplinesThetaDiffThreshold,
01989 lineConf->checkSplinesThetaThreshold)
01990 : 0;
01991
01992 if (splineStatus & (ShortSpline|CurvedSpline))
01993 {
01994 for (unsigned int j=0; j<lines.size(); j++)
01995 {
01996
01997 Spline sp = mcvLineXY2Spline(lines[j], lineConf->ransacSplineDegree);
01998
01999 if (mcvCheckMergeSplines(splines[i], sp, .4, 50, .4, 50, 50))
02000 {
02001
02002 splines[i] = sp;
02003 splineStatus = 0;
02004 break;
02005 }
02006 }
02007
02008 }
02009 if (!(splineStatus & (CurvedSpline|CurvedSplineTheta)))
02010 {
02011
02012 CvMat *points = mcvEvalBezierSpline(splines[i], .05);
02013
02014
02015
02016
02017
02018
02019 mcvLocalizePoints(image, points, points, lineConf->localizeNumLinePixels,
02020 lineConf->localizeAngleThreshold);
02021
02022
02023 CvMat* clrPoints = points;
02024
02025
02026 CvMat* p = mcvExtendPoints(image, points,
02027 lineConf->extendAngleThreshold,
02028 lineConf->extendMeanDirAngleThreshold,
02029 lineConf->extendLinePixelsTangent,
02030 lineConf->extendLinePixelsNormal,
02031 lineConf->extendContThreshold,
02032 lineConf->extendDeviationThreshold,
02033 cvRect(0, lineConf->extendRectTop,
02034 image->width,
02035 lineConf->extendRectBottom-lineConf->extendRectTop));
02036
02037
02038 Spline spline = mcvFitBezierSpline(p, lineConf->ransacSplineDegree);
02039
02040 clrPoints = p;
02041
02042
02043 if (lineConf->checkSplines &&
02044 (mcvCheckSpline(spline,
02045 lineConf->checkSplinesCurvenessThreshold,
02046 lineConf->checkSplinesLengthThreshold,
02047 lineConf->checkSplinesThetaDiffThreshold,
02048 lineConf->checkSplinesThetaThreshold)
02049 & CurvedSpline))
02050 {
02051
02052 spline = mcvFitBezierSpline(points, lineConf->ransacSplineDegree);
02053 clrPoints = points;
02054
02055
02056 if (mcvCheckSpline(spline,
02057 lineConf->checkSplinesCurvenessThreshold,
02058 lineConf->checkSplinesLengthThreshold,
02059 lineConf->checkSplinesThetaDiffThreshold,
02060 lineConf->checkSplinesThetaThreshold)
02061 & CurvedSpline)
02062
02063 spline = splines[i];
02064 }
02065
02066
02067
02068 LineColor clr = lineConf->checkColor ?
02069 mcvGetPointsColor(clrImage, clrPoints,
02070 lineConf->checkColorWindow,
02071 lineConf->checkColorNumYellowMin,
02072 lineConf->checkColorRGMin,
02073 lineConf->checkColorRGMax,
02074 lineConf->checkColorGBMin,
02075 lineConf->checkColorRBMin,
02076 lineConf->checkColorRBF,
02077 lineConf->checkColorRBFThreshold)
02078 : LINE_COLOR_WHITE;
02079
02080
02081 cvReleaseMat(&points);
02082 cvReleaseMat(&p);
02083
02084
02085 spline.color = clr;
02086 keepSplines.push_back(spline);
02087 keepSplineScores.push_back(splineScores[i]);
02088 }
02089 }
02090
02091
02092 splines.clear();
02093 splineScores.clear();
02094 splines = keepSplines;
02095 splineScores = keepSplineScores;
02096 keepSplines.clear();
02097 keepSplineScores.clear();
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108 }
02109
02110
02111 }
02112
02113
02114
02128 void mcvGetLines(const CvMat* image, LineType lineType,
02129 vector<Line> &lines, vector<float> &lineScores,
02130 vector<Spline> &splines, vector<float> &splineScores,
02131 LaneDetectorConf *lineConf, LineState *state)
02132 {
02133
02134
02135 switch(lineConf->groupingType)
02136 {
02137
02138 case GROUPING_TYPE_HV_LINES:
02139
02140
02141 mcvGetHVLines(image, &lines, &lineScores, lineType,
02142 6,
02143 lineConf->binarize, lineConf->localMaxima,
02144 lineConf->detectionThreshold,
02145 lineConf->smoothScores);
02146 break;
02147
02148
02149 case GROUPING_TYPE_HOUGH_LINES:
02150
02151
02152
02153 mcvGetHoughTransformLines(image, &lines, &lineScores,
02154 lineConf->rMin, lineConf->rMax,
02155 lineConf->rStep, lineConf->thetaMin,
02156 lineConf->thetaMax, lineConf->thetaStep,
02157 lineConf->binarize, lineConf->localMaxima,
02158 lineConf->detectionThreshold,
02159 lineConf->smoothScores,
02160 lineConf->group, lineConf->groupThreshold);
02161
02162 break;
02163 }
02164
02165
02166
02167
02168
02169
02170 if (lineConf->checkLaneWidth)
02171 mcvCheckLaneWidth(lines, lineScores,
02172 lineConf->checkLaneWidthMean,
02173 lineConf->checkLaneWidthStd);
02174
02175
02176 if (lineConf->ransac)
02177 {
02178
02179 if (lineConf->ransacLine)
02180 mcvGetRansacLines(image, lines, lineScores, lineConf, lineType);
02181
02182
02183 if (lineConf->ransacSpline)
02184 mcvGetRansacSplines(image, lines, lineScores,
02185 lineConf, lineType, splines, splineScores, state);
02186 }
02187
02188
02189
02190 state->ipmBoxes.clear();
02191 mcvGetSplinesBoundingBoxes(splines, lineType,
02192 cvSize(image->width, image->height),
02193 state->ipmBoxes);
02194 }
02195
02208 int mcvCheckSpline(const Spline &spline, float curvenessThreshold,
02209 float lengthThreshold, float thetaDiffThreshold,
02210 float thetaThreshold)
02211 {
02212
02213
02214 float theta, r, meanTheta, meanR, length, curveness;
02215 mcvGetSplineFeatures(spline, 0, &theta, &r, &length,
02216 &meanTheta, &meanR, &curveness);
02217 float thetaDiff = fabs(meanTheta - theta);
02218
02219
02220
02221
02222
02223
02224
02225
02226 char check = 0;
02227 if (curveness<curvenessThreshold)
02228 check |= CurvedSpline;
02229 if (thetaDiff > thetaDiffThreshold)
02230 check |= CurvedSplineTheta;
02231 if (length<lengthThreshold)
02232 check |= ShortSpline;
02233 if (meanTheta<thetaThreshold)
02234 check |= HorizontalSpline;
02235
02236
02237 if(DEBUG_LINES) {
02238
02239 fprintf(stderr, "thetaDiffThreshold=%f\n", thetaDiffThreshold);
02240 fprintf(stderr, "%s: curveness=%f, length=%f, thetaDiff=%f, meanTheta=%f, theta=%f\n",
02241 check & (ShortSpline|CurvedSpline|HorizontalSpline)
02242 ? "YES" : "NO ", curveness, length, thetaDiff, meanTheta, theta);
02243 fprintf(stderr, "\t%s\t%s\t%s\t%s\n",
02244 check&CurvedSpline? "curved" : "not curved",
02245 check&CurvedSplineTheta? "curved theta" : "not curved theta",
02246 check&ShortSpline? "short" : "not short",
02247 check&HorizontalSpline? "horiz" : "not horiz");
02248
02249 CvMat* im = cvCreateMat(480, 640, CV_8UC3);
02250 cvSet(im, cvRealScalar(0.));
02251
02252 mcvDrawSpline(im, spline, CV_RGB(255, 0, 0), 1);
02253 SHOW_IMAGE(im, "Check Splines", 10);
02254
02255 cvReleaseMat(&im);
02256 }
02257
02258 return check;
02259 }
02260
02269 int mcvCheckPoints(const CvMat* points)
02270 {
02271
02272
02273 float theta, r, meanTheta, meanR, curveness;
02274 mcvGetPointsFeatures(points, 0, &theta, &r, 0,
02275 &meanTheta, &meanR, &curveness);
02276 float thetaDiff = fabs(meanTheta - theta);
02277
02278 float curvenessThreshold = .8;
02279 float thetaDiffThreshold = .3;
02280
02281 int check = 0;
02282 if (curveness<curvenessThreshold)
02283 check |= CurvedSpline;
02284 if (thetaDiff > thetaDiffThreshold)
02285 check |= CurvedSplineTheta;
02286
02287 if(DEBUG_LINES) {
02288
02289 fprintf(stderr, "%s: curveness=%f, thetaDiff=%f, meanTheta=%f\n",
02290 check & (ShortSpline|CurvedSpline|HorizontalSpline)
02291 ? "YES" : "NO ", curveness, thetaDiff, meanTheta);
02292
02293 CvMat* im = cvCreateMat(480, 640, CV_8UC3);
02294 cvSet(im, cvRealScalar(0.));
02295
02296 for (int i=0; i<points->height-1; i++)
02297 {
02298 Line line;
02299 line.startPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, i, 0),
02300 CV_MAT_ELEM(*points, float, i, 1));
02301 line.endPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, i+1, 0),
02302 CV_MAT_ELEM(*points, float, i+1, 1));
02303 mcvDrawLine(im, line, CV_RGB(255, 0, 0), 1);
02304 }
02305 SHOW_IMAGE(im, "Check Points", 0);
02306
02307 cvReleaseMat(&im);
02308 }
02309
02310 return check;
02311 }
02312
02313
02324 void mcvLines2Mat(const vector<Line> *lines, CvMat *mat)
02325 {
02326
02327
02328
02329
02330 int j;
02331 for (int i=0; i<(int)lines->size(); i++)
02332 {
02333 j = 2*i;
02334 CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 0, j) = (*lines)[i].startPoint.x;
02335 CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 1, j) = (*lines)[i].startPoint.y;
02336 CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 0, j+1) = (*lines)[i].endPoint.x;
02337 CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 1, j+1) = (*lines)[i].endPoint.y;
02338 }
02339 }
02340
02341
02351 void mcvMat2Lines(const CvMat *mat, vector<Line> *lines)
02352 {
02353
02354 Line line;
02355
02356 for (int i=0; i<int(mat->width/2); i++)
02357 {
02358 int j = 2*i;
02359
02360 line.startPoint.x = CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 0, j);
02361 line.startPoint.y = CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 1, j);
02362 line.endPoint.x = CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 0, j+1);
02363 line.endPoint.y = CV_MAT_ELEM(*mat, FLOAT_MAT_ELEM_TYPE, 1, j+1);
02364
02365 lines->push_back(line);
02366 }
02367 }
02368
02369
02370
02378 void mcvIntersectLineWithBB(const Line *inLine, const CvSize bbox,
02379 Line *outLine)
02380 {
02381
02382 outLine->startPoint.x = inLine->startPoint.x;
02383 outLine->startPoint.y = inLine->startPoint.y;
02384 outLine->endPoint.x = inLine->endPoint.x;
02385 outLine->endPoint.y = inLine->endPoint.y;
02386
02387
02388 bool startInside, endInside;
02389 startInside = mcvIsPointInside(inLine->startPoint, bbox);
02390 endInside = mcvIsPointInside(inLine->endPoint, bbox);
02391
02392
02393 if (!(startInside && endInside))
02394 {
02395
02396 FLOAT deltax, deltay;
02397 deltax = inLine->endPoint.x - inLine->startPoint.x;
02398 deltay = inLine->endPoint.y - inLine->startPoint.y;
02399
02400 FLOAT t[4]={2,2,2,2};
02401 FLOAT xup, xdown, yleft, yright;
02402
02403
02404 if (deltay==0)
02405 {
02406 xup = xdown = bbox.width+2;
02407 }
02408 else
02409 {
02410 t[0] = -inLine->startPoint.y/deltay;
02411 xup = inLine->startPoint.x + t[0]*deltax;
02412 t[1] = (bbox.height-inLine->startPoint.y)/deltay;
02413 xdown = inLine->startPoint.x + t[1]*deltax;
02414 }
02415
02416
02417 if (deltax==0)
02418 {
02419 yleft = yright = bbox.height+2;
02420 }
02421 else
02422 {
02423 t[2] = -inLine->startPoint.x/deltax;
02424 yleft = inLine->startPoint.y + t[2]*deltay;
02425 t[3] = (bbox.width-inLine->startPoint.x)/deltax;
02426 yright = inLine->startPoint.y + t[3]*deltay;
02427 }
02428
02429
02430 FLOAT_POINT2D pts[4] = {{xup, 0},{xdown,bbox.height},
02431 {0, yleft},{bbox.width, yright}};
02432
02433
02434 int i;
02435 if (!startInside)
02436 {
02437 bool cont=true;
02438 for (i=0; i<4 && cont; i++)
02439 {
02440 if (t[i]>=0 && t[i]<=1 && mcvIsPointInside(pts[i],bbox) &&
02441 !(pts[i].x == outLine->endPoint.x &&
02442 pts[i].y == outLine->endPoint.y) )
02443 {
02444 outLine->startPoint.x = pts[i].x;
02445 outLine->startPoint.y = pts[i].y;
02446 t[i] = 2;
02447 cont = false;
02448 }
02449 }
02450
02451 if(cont)
02452 {
02453
02454 for (i=0; i<4 && cont; i++)
02455 {
02456 if (t[i]>=0 && t[i]<=1 && mcvIsPointInside(pts[i],bbox))
02457 {
02458 outLine->startPoint.x = pts[i].x;
02459 outLine->startPoint.y = pts[i].y;
02460 t[i] = 2;
02461 cont = false;
02462 }
02463 }
02464 }
02465 }
02466 if (!endInside)
02467 {
02468 bool cont=true;
02469 for (i=0; i<4 && cont; i++)
02470 {
02471 if (t[i]>=0 && t[i]<=1 && mcvIsPointInside(pts[i],bbox) &&
02472 !(pts[i].x == outLine->startPoint.x &&
02473 pts[i].y == outLine->startPoint.y) )
02474 {
02475 outLine->endPoint.x = pts[i].x;
02476 outLine->endPoint.y = pts[i].y;
02477 t[i] = 2;
02478 cont = false;
02479 }
02480 }
02481
02482 if(cont)
02483 {
02484
02485 for (i=0; i<4 && cont; i++)
02486 {
02487 if (t[i]>=0 && t[i]<=1 && mcvIsPointInside(pts[i],bbox))
02488 {
02489 outLine->endPoint.x = pts[i].x;
02490 outLine->endPoint.y = pts[i].y;
02491 t[i] = 2;
02492 cont = false;
02493 }
02494 }
02495 }
02496 }
02497 }
02498 }
02499
02500
02511 void mcvIntersectLineRThetaWithBB(FLOAT r, FLOAT theta, const CvSize bbox,
02512 Line *outLine)
02513 {
02514
02515 double xup, xdown, yleft, yright;
02516
02517
02518 if (cos(theta)==0)
02519 {
02520 xup = xdown = bbox.width+2;
02521 }
02522 else
02523 {
02524 xup = r / cos(theta);
02525 xdown = (r-bbox.height*sin(theta))/cos(theta);
02526 }
02527
02528
02529 if (sin(theta)==0)
02530 {
02531 yleft = yright = bbox.height+2;
02532 }
02533 else
02534 {
02535 yleft = r/sin(theta);
02536 yright = (r-bbox.width*cos(theta))/sin(theta);
02537 }
02538
02539
02540 FLOAT_POINT2D pts[4] = {{xup, 0},{xdown,bbox.height},
02541 {0, yleft},{bbox.width, yright}};
02542
02543
02544 int i;
02545 for (i=0; i<4; i++)
02546 {
02547
02548 if(mcvIsPointInside(pts[i], bbox))
02549 {
02550 outLine->startPoint.x = pts[i].x;
02551 outLine->startPoint.y = pts[i].y;
02552
02553 break;
02554 }
02555 }
02556
02557 for (i++; i<4; i++)
02558 {
02559
02560 if(mcvIsPointInside(pts[i], bbox))
02561 {
02562 outLine->endPoint.x = pts[i].x;
02563 outLine->endPoint.y = pts[i].y;
02564
02565 break;
02566 }
02567 }
02568 }
02569
02570
02579 bool mcvIsPointInside(FLOAT_POINT2D point, CvSize bbox)
02580 {
02581 return (point.x>=0 && point.x<=bbox.width
02582 && point.y>=0 && point.y<=bbox.height) ? true : false;
02583 }
02584
02585
02597 void mcvIntersectLineRThetaWithRect(FLOAT r, FLOAT theta, const Line &rect,
02598 Line &outLine)
02599 {
02600
02601 double xup, xdown, yleft, yright;
02602
02603
02604 if (cos(theta)==0)
02605 {
02606 xup = xdown = rect.endPoint.x+2;
02607 }
02608 else
02609 {
02610 xup = (r-rect.startPoint.y*sin(theta)) / cos(theta);
02611 xdown = (r-rect.endPoint.y*sin(theta)) / cos(theta);
02612 }
02613
02614
02615 if (sin(theta)==0)
02616 {
02617 yleft = yright = rect.endPoint.y+2;
02618 }
02619 else
02620 {
02621 yleft = (r-rect.startPoint.x*cos(theta)) / sin(theta);
02622 yright = (r-rect.endPoint.x*cos(theta)) / sin(theta);
02623 }
02624
02625
02626 FLOAT_POINT2D pts[4] = {{xup, rect.startPoint.y},{xdown,rect.endPoint.y},
02627 {rect.startPoint.x, yleft},{rect.endPoint.x, yright}};
02628
02629
02630 int i;
02631 for (i=0; i<4; i++)
02632 {
02633
02634 if(mcvIsPointInside(pts[i], rect))
02635 {
02636 outLine.startPoint.x = pts[i].x;
02637 outLine.startPoint.y = pts[i].y;
02638
02639 break;
02640 }
02641 }
02642
02643 for (i++; i<4; i++)
02644 {
02645
02646 if(mcvIsPointInside(pts[i], rect))
02647 {
02648 outLine.endPoint.x = pts[i].x;
02649 outLine.endPoint.y = pts[i].y;
02650
02651 break;
02652 }
02653 }
02654 }
02655
02656
02663 bool mcvIsPointInside(FLOAT_POINT2D &point, const Line &rect)
02664 {
02665 return (point.x>=rect.startPoint.x && point.x<=rect.endPoint.x
02666 && point.y>=rect.startPoint.y && point.y<=rect.endPoint.y) ? true : false;
02667 }
02668
02675 bool mcvIsPointInside(FLOAT_POINT2D &point, const CvRect &rect)
02676 {
02677 return (point.x>=rect.x && point.x<=(rect.x+rect.width)
02678 && point.y>=rect.y && point.y<=(rect.y+rect.height)) ? true : false;
02679 }
02680
02687 void mcvMatInt2Float(const CvMat *inMat, CvMat *outMat)
02688 {
02689 for (int i=0; i<inMat->height; i++)
02690 for (int j=0; j<inMat->width; j++)
02691 CV_MAT_ELEM(*outMat, FLOAT_MAT_ELEM_TYPE, i, j) =
02692 (FLOAT_MAT_ELEM_TYPE) CV_MAT_ELEM(*inMat, INT_MAT_ELEM_TYPE,
02693 i, j)/255;
02694 }
02695
02696
02705 void mcvDrawLine(CvMat *image, Line line, CvScalar color, int width)
02706 {
02707 cvLine(image, cvPoint((int)line.startPoint.x,(int)line.startPoint.y),
02708 cvPoint((int)line.endPoint.x,(int)line.endPoint.y),
02709 color, width);
02710 }
02711
02719 void mcvInitLaneDetectorConf(char * const fileName,
02720 LaneDetectorConf *stopLineConf)
02721 {
02722
02723 LaneDetectorParserInfo stopLineParserInfo;
02724
02725 assert(LaneDetectorParser_configfile(fileName, &stopLineParserInfo, 0, 1, 1)==0);
02726
02727 stopLineConf->ipmWidth = stopLineParserInfo.ipmWidth_arg;
02728 stopLineConf->ipmHeight = stopLineParserInfo.ipmHeight_arg;
02729 stopLineConf->ipmLeft = stopLineParserInfo.ipmLeft_arg;
02730 stopLineConf->ipmRight = stopLineParserInfo.ipmRight_arg;
02731 stopLineConf->ipmBottom = stopLineParserInfo.ipmBottom_arg;
02732 stopLineConf->ipmTop = stopLineParserInfo.ipmTop_arg;
02733 stopLineConf->ipmInterpolation = stopLineParserInfo.ipmInterpolation_arg;
02734
02735 stopLineConf->lineWidth = stopLineParserInfo.lineWidth_arg;
02736 stopLineConf->lineHeight = stopLineParserInfo.lineHeight_arg;
02737 stopLineConf->kernelWidth = stopLineParserInfo.kernelWidth_arg;
02738 stopLineConf->kernelHeight = stopLineParserInfo.kernelHeight_arg;
02739 stopLineConf->lowerQuantile =
02740 stopLineParserInfo.lowerQuantile_arg;
02741 stopLineConf->localMaxima =
02742 stopLineParserInfo.localMaxima_arg;
02743 stopLineConf->groupingType = stopLineParserInfo.groupingType_arg;
02744 stopLineConf->binarize = stopLineParserInfo.binarize_arg;
02745 stopLineConf->detectionThreshold =
02746 stopLineParserInfo.detectionThreshold_arg;
02747 stopLineConf->smoothScores =
02748 stopLineParserInfo.smoothScores_arg;
02749 stopLineConf->rMin = stopLineParserInfo.rMin_arg;
02750 stopLineConf->rMax = stopLineParserInfo.rMax_arg;
02751 stopLineConf->rStep = stopLineParserInfo.rStep_arg;
02752 stopLineConf->thetaMin = stopLineParserInfo.thetaMin_arg * CV_PI/180;
02753 stopLineConf->thetaMax = stopLineParserInfo.thetaMax_arg * CV_PI/180;
02754 stopLineConf->thetaStep = stopLineParserInfo.thetaStep_arg * CV_PI/180;
02755 stopLineConf->ipmVpPortion = stopLineParserInfo.ipmVpPortion_arg;
02756 stopLineConf->getEndPoints = stopLineParserInfo.getEndPoints_arg;
02757 stopLineConf->group = stopLineParserInfo.group_arg;
02758 stopLineConf->groupThreshold = stopLineParserInfo.groupThreshold_arg;
02759 stopLineConf->ransac = stopLineParserInfo.ransac_arg;
02760
02761 stopLineConf->ransacLineNumSamples = stopLineParserInfo.ransacLineNumSamples_arg;
02762 stopLineConf->ransacLineNumIterations = stopLineParserInfo.ransacLineNumIterations_arg;
02763 stopLineConf->ransacLineNumGoodFit = stopLineParserInfo.ransacLineNumGoodFit_arg;
02764 stopLineConf->ransacLineThreshold = stopLineParserInfo.ransacLineThreshold_arg;
02765 stopLineConf->ransacLineScoreThreshold = stopLineParserInfo.ransacLineScoreThreshold_arg;
02766 stopLineConf->ransacLineBinarize = stopLineParserInfo.ransacLineBinarize_arg;
02767 stopLineConf->ransacLineWindow = stopLineParserInfo.ransacLineWindow_arg;
02768
02769 stopLineConf->ransacSplineNumSamples = stopLineParserInfo.ransacSplineNumSamples_arg;
02770 stopLineConf->ransacSplineNumIterations = stopLineParserInfo.ransacSplineNumIterations_arg;
02771 stopLineConf->ransacSplineNumGoodFit = stopLineParserInfo.ransacSplineNumGoodFit_arg;
02772 stopLineConf->ransacSplineThreshold = stopLineParserInfo.ransacSplineThreshold_arg;
02773 stopLineConf->ransacSplineScoreThreshold = stopLineParserInfo.ransacSplineScoreThreshold_arg;
02774 stopLineConf->ransacSplineBinarize = stopLineParserInfo.ransacSplineBinarize_arg;
02775 stopLineConf->ransacSplineWindow = stopLineParserInfo.ransacSplineWindow_arg;
02776
02777 stopLineConf->ransacSplineDegree = stopLineParserInfo.ransacSplineDegree_arg;
02778
02779 stopLineConf->ransacSpline = stopLineParserInfo.ransacSpline_arg;
02780 stopLineConf->ransacLine = stopLineParserInfo.ransacLine_arg;
02781 stopLineConf->ransacSplineStep = stopLineParserInfo.ransacSplineStep_arg;
02782
02783 stopLineConf->overlapThreshold = stopLineParserInfo.overlapThreshold_arg;
02784
02785 stopLineConf->localizeAngleThreshold = stopLineParserInfo.localizeAngleThreshold_arg;
02786 stopLineConf->localizeNumLinePixels = stopLineParserInfo.localizeNumLinePixels_arg;
02787
02788 stopLineConf->extendAngleThreshold = stopLineParserInfo.extendAngleThreshold_arg;
02789 stopLineConf->extendMeanDirAngleThreshold = stopLineParserInfo.extendMeanDirAngleThreshold_arg;
02790 stopLineConf->extendLinePixelsTangent = stopLineParserInfo.extendLinePixelsTangent_arg;
02791 stopLineConf->extendLinePixelsNormal = stopLineParserInfo.extendLinePixelsNormal_arg;
02792 stopLineConf->extendContThreshold = stopLineParserInfo.extendContThreshold_arg;
02793 stopLineConf->extendDeviationThreshold = stopLineParserInfo.extendDeviationThreshold_arg;
02794 stopLineConf->extendRectTop = stopLineParserInfo.extendRectTop_arg;
02795 stopLineConf->extendRectBottom = stopLineParserInfo.extendRectBottom_arg;
02796
02797 stopLineConf->extendIPMAngleThreshold = stopLineParserInfo.extendIPMAngleThreshold_arg;
02798 stopLineConf->extendIPMMeanDirAngleThreshold = stopLineParserInfo.extendIPMMeanDirAngleThreshold_arg;
02799 stopLineConf->extendIPMLinePixelsTangent = stopLineParserInfo.extendIPMLinePixelsTangent_arg;
02800 stopLineConf->extendIPMLinePixelsNormal = stopLineParserInfo.extendIPMLinePixelsNormal_arg;
02801 stopLineConf->extendIPMContThreshold = stopLineParserInfo.extendIPMContThreshold_arg;
02802 stopLineConf->extendIPMDeviationThreshold = stopLineParserInfo.extendIPMDeviationThreshold_arg;
02803 stopLineConf->extendIPMRectTop = stopLineParserInfo.extendIPMRectTop_arg;
02804 stopLineConf->extendIPMRectBottom = stopLineParserInfo.extendIPMRectBottom_arg;
02805
02806 stopLineConf->splineScoreJitter = stopLineParserInfo.splineScoreJitter_arg;
02807 stopLineConf->splineScoreLengthRatio = stopLineParserInfo.splineScoreLengthRatio_arg;
02808 stopLineConf->splineScoreAngleRatio = stopLineParserInfo.splineScoreAngleRatio_arg;
02809 stopLineConf->splineScoreStep = stopLineParserInfo.splineScoreStep_arg;
02810
02811 stopLineConf->splineTrackingNumAbsentFrames = stopLineParserInfo.splineTrackingNumAbsentFrames_arg;
02812 stopLineConf->splineTrackingNumSeenFrames = stopLineParserInfo.splineTrackingNumSeenFrames_arg;
02813
02814 stopLineConf->mergeSplineThetaThreshold = stopLineParserInfo.mergeSplineThetaThreshold_arg;
02815 stopLineConf->mergeSplineRThreshold = stopLineParserInfo.mergeSplineRThreshold_arg;
02816 stopLineConf->mergeSplineMeanThetaThreshold = stopLineParserInfo.mergeSplineMeanThetaThreshold_arg;
02817 stopLineConf->mergeSplineMeanRThreshold = stopLineParserInfo.mergeSplineMeanRThreshold_arg;
02818 stopLineConf->mergeSplineCentroidThreshold = stopLineParserInfo.mergeSplineCentroidThreshold_arg;
02819
02820 stopLineConf->lineTrackingNumAbsentFrames = stopLineParserInfo.lineTrackingNumAbsentFrames_arg;
02821 stopLineConf->lineTrackingNumSeenFrames = stopLineParserInfo.lineTrackingNumSeenFrames_arg;
02822
02823 stopLineConf->mergeLineThetaThreshold = stopLineParserInfo.mergeLineThetaThreshold_arg;
02824 stopLineConf->mergeLineRThreshold = stopLineParserInfo.mergeLineRThreshold_arg;
02825
02826 stopLineConf->numStrips = stopLineParserInfo.numStrips_arg;
02827
02828
02829 stopLineConf->checkSplines = stopLineParserInfo.checkSplines_arg;
02830 stopLineConf->checkSplinesCurvenessThreshold = stopLineParserInfo.checkSplinesCurvenessThreshold_arg;
02831 stopLineConf->checkSplinesLengthThreshold = stopLineParserInfo.checkSplinesLengthThreshold_arg;
02832 stopLineConf->checkSplinesThetaDiffThreshold = stopLineParserInfo.checkSplinesThetaDiffThreshold_arg;
02833 stopLineConf->checkSplinesThetaThreshold = stopLineParserInfo.checkSplinesThetaThreshold_arg;
02834
02835 stopLineConf->checkIPMSplines = stopLineParserInfo.checkIPMSplines_arg;
02836 stopLineConf->checkIPMSplinesCurvenessThreshold = stopLineParserInfo.checkIPMSplinesCurvenessThreshold_arg;
02837 stopLineConf->checkIPMSplinesLengthThreshold = stopLineParserInfo.checkIPMSplinesLengthThreshold_arg;
02838 stopLineConf->checkIPMSplinesThetaDiffThreshold = stopLineParserInfo.checkIPMSplinesThetaDiffThreshold_arg;
02839 stopLineConf->checkIPMSplinesThetaThreshold = stopLineParserInfo.checkIPMSplinesThetaThreshold_arg;
02840
02841 stopLineConf->finalSplineScoreThreshold = stopLineParserInfo.finalSplineScoreThreshold_arg;
02842
02843 stopLineConf->useGroundPlane = stopLineParserInfo.useGroundPlane_arg;
02844
02845 stopLineConf->checkColor = stopLineParserInfo.checkColor_arg;
02846 stopLineConf->checkColorNumBins = stopLineParserInfo.checkColorNumBins_arg;
02847 stopLineConf->checkColorWindow = stopLineParserInfo.checkColorWindow_arg;
02848 stopLineConf->checkColorNumYellowMin = stopLineParserInfo.checkColorNumYellowMin_arg;
02849 stopLineConf->checkColorRGMin = stopLineParserInfo.checkColorRGMin_arg;
02850 stopLineConf->checkColorRGMax = stopLineParserInfo.checkColorRGMax_arg;
02851 stopLineConf->checkColorGBMin = stopLineParserInfo.checkColorGBMin_arg;
02852 stopLineConf->checkColorRBMin = stopLineParserInfo.checkColorRBMin_arg;
02853 stopLineConf->checkColorRBFThreshold = stopLineParserInfo.checkColorRBFThreshold_arg;
02854 stopLineConf->checkColorRBF = stopLineParserInfo.checkColorRBF_arg;
02855
02856 stopLineConf->ipmWindowClear = stopLineParserInfo.ipmWindowClear_arg;;
02857 stopLineConf->ipmWindowLeft = stopLineParserInfo.ipmWindowLeft_arg;;
02858 stopLineConf->ipmWindowRight = stopLineParserInfo.ipmWindowRight_arg;;
02859
02860 stopLineConf->checkLaneWidth = stopLineParserInfo.checkLaneWidth_arg;;
02861 stopLineConf->checkLaneWidthMean = stopLineParserInfo.checkLaneWidthMean_arg;;
02862 stopLineConf->checkLaneWidthStd = stopLineParserInfo.checkLaneWidthStd_arg;;
02863 }
02864
02865 void SHOW_LINE(const Line line, char str[])
02866 {
02867 cerr << str;
02868 cerr << "(" << line.startPoint.x << "," << line.startPoint.y << ")";
02869 cerr << "->";
02870 cerr << "(" << line.endPoint.x << "," << line.endPoint.y << ")";
02871 cerr << "\n";
02872 }
02873
02874 void SHOW_SPLINE(const Spline spline, char str[])
02875 {
02876 cerr << str;
02877 cerr << "(" << spline.degree << ")";
02878 for (int i=0; i<spline.degree+1; i++)
02879 cerr << " (" << spline.points[i].x << "," << spline.points[i].y << ")";
02880 cerr << "\n";
02881 }
02882
02883
02893 double mcvGetLocalMaxSubPixel(double val1, double val2, double val3)
02894 {
02895
02896 double Xp[] = {1, -1, 1, 0, 0, 1, 1, 1, 1};
02897 CvMat X = cvMat(3, 3, CV_64FC1, Xp);
02898
02899
02900 double yp[] = {val1, val2, val3};
02901 CvMat y = cvMat(3, 1, CV_64FC1, yp);
02902
02903
02904 double Ap[3];
02905 CvMat A = cvMat(3, 1, CV_64FC1, Ap);
02906 cvSolve(&X, &y, &A, CV_SVD);
02907
02908
02909 double max;
02910 max = -0.5 * Ap[1] / Ap[0];
02911
02912
02913 return max;
02914 }
02915
02923
02924 CvMat * mcvGetLinePixels(const Line &line)
02925 {
02926
02927 CvPoint start;
02928 start.x = int(line.startPoint.x); start.y = int(line.startPoint.y);
02929 CvPoint end;
02930 end.x = int(line.endPoint.x); end.y = int(line.endPoint.y);
02931
02932
02933 int deltay = end.y - start.y;
02934 int deltax = end.x - start.x;
02935
02936
02937 bool steep = false;
02938 if (abs(deltay) > abs(deltax))
02939 {
02940 steep = true;
02941
02942 int t;
02943 t = start.x;
02944 start.x = start.y;
02945 start.y = t;
02946 t = end.x;
02947 end.x = end.y;
02948 end.y = t;
02949 }
02950
02951
02952
02953 bool swap = false;
02954 if(start.x>end.x)
02955 {
02956
02957 CvPoint t = start;
02958 start = end;
02959 end = t;
02960
02961 swap = true;
02962 }
02963
02964
02965 deltay = end.y - start.y;
02966 deltax = end.x - start.x;
02967
02968
02969 int error = 0;
02970
02971
02972 int deltaerror = abs(deltay);
02973
02974
02975 int ystep = -1;
02976 if (deltay>=0)
02977 {
02978 ystep = 1;
02979 }
02980
02981
02982 CvMat *pixels = cvCreateMat(end.x-start.x+1, 2, CV_32SC1);
02983
02984
02985 int i, j;
02986 j = start.y;
02987
02988
02989 int k, kupdate;
02990 if (!swap)
02991 {
02992 k = 0;
02993 kupdate = 1;
02994 }
02995 else
02996 {
02997 k = pixels->height-1;
02998 kupdate = -1;
02999 }
03000
03001 for (i=start.x; i<=end.x; i++, k+=kupdate)
03002 {
03003
03004 if(steep)
03005 {
03006 CV_MAT_ELEM(*pixels, int, k, 0) = j;
03007 CV_MAT_ELEM(*pixels, int, k, 1) = i;
03008
03009
03010 }
03011 else
03012 {
03013 CV_MAT_ELEM(*pixels, int, k, 0) = i;
03014 CV_MAT_ELEM(*pixels, int, k, 1) = j;
03015
03016
03017 }
03018
03019
03020 error += deltaerror;
03021
03022 if(2*error>=deltax)
03023 {
03024 j = j + ystep;
03025 error -= deltax;
03026 }
03027 }
03028
03029
03030 return pixels;
03031 }
03032
03042 void mcvGetLineExtent(const CvMat *im, const Line &inLine, Line &outLine)
03043 {
03044
03045 Line line = inLine;
03046 mcvIntersectLineWithBB(&inLine, cvSize(im->width-1, im->height-1), &line);
03047
03048
03049 CvMat *pixels;
03050 pixels = mcvGetLinePixels(line);
03051
03052
03053 bool changey = false;
03054 if (fabs(line.startPoint.x-line.endPoint.x) >
03055 fabs(line.startPoint.y-line.endPoint.y))
03056 {
03057
03058 changey = true;
03059 }
03060 char changes[] = {0, -1, 1};
03061 int numChanges = 3;
03062
03063
03064 vector<int> startLocs;
03065 vector<int> endLocs;
03066 int endLoc;
03067 int startLoc;
03068 CvMat *pix = cvCreateMat(1, im->width, FLOAT_MAT_TYPE);
03069 CvMat *rstep = cvCreateMat(pix->height, pix->width, FLOAT_MAT_TYPE);
03070 CvMat *fstep = cvCreateMat(pix->height, pix->width, FLOAT_MAT_TYPE);
03071 for (int c=0; c<numChanges; c++)
03072 {
03073
03074
03075 for(int i=0; i<pixels->height; i++)
03076 {
03077 CV_MAT_ELEM(*pix, FLOAT_MAT_ELEM_TYPE, 0, i) =
03078 CV_MAT_ELEM(*im, FLOAT_MAT_ELEM_TYPE,
03079 changey ?
03080 min(max(CV_MAT_ELEM(*pixels, int, i, 1)+
03081 changes[c],0),im->height-1) :
03082 CV_MAT_ELEM(*pixels, int, i, 1),
03083 changey ? CV_MAT_ELEM(*pixels, int, i, 0) :
03084 min(max(CV_MAT_ELEM(*pixels, int, i, 0)+
03085 changes[c],0),im->width-1));
03086
03087
03088 }
03089
03090 CvScalar mean = cvAvg(pix);
03091 cvSubS(pix, mean, pix);
03092
03093
03094 FLOAT_MAT_ELEM_TYPE stepp[] = {-0.3000, -0.2, -0.1, 0, 0, 0.1, 0.2, 0.3, 0.4};
03095
03096 int stepsize = 9;
03097
03098 CvMat step = cvMat(1, stepsize, FLOAT_MAT_TYPE, stepp);
03099
03100
03101
03102
03103
03104
03105
03106 cvFilter2D(pix, rstep, &step);
03107
03108
03109
03110
03111
03112 double max;
03113 mcvGetVectorMax(rstep, &max, &startLoc, 0);
03114
03115 if(max==0)
03116 startLoc = startLocs[c-1];
03117
03118
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128 cvConvertScale(rstep, fstep, -1);
03129 mcvGetVectorMax(fstep, &max, &endLoc, 0);
03130
03131 if(max==0)
03132 endLoc = endLocs[c-1];
03133 if(endLoc<=startLoc)
03134 endLoc = im->width-1;
03135
03136
03137 startLocs.push_back(startLoc);
03138 endLocs.push_back(endLoc);
03139 }
03140
03141
03142 startLoc = quantile(startLocs, 0);
03143 endLoc = quantile(endLocs, 1);
03144
03145
03146
03147
03148
03149 outLine.startPoint.x = CV_MAT_ELEM(*pixels, int, startLoc, 0);
03150 outLine.startPoint.y = CV_MAT_ELEM(*pixels, int, startLoc, 1);
03151 outLine.endPoint.x = CV_MAT_ELEM(*pixels, int, endLoc, 0);
03152 outLine.endPoint.y = CV_MAT_ELEM(*pixels, int, endLoc, 1);
03153
03154
03155
03156
03157 cvReleaseMat(&pix);
03158 cvReleaseMat(&rstep);
03159 cvReleaseMat(&fstep);
03160 cvReleaseMat(&pixels);
03161
03162
03163 startLocs.clear();
03164 endLocs.clear();
03165 }
03166
03167
03168
03178 void mcvLineXY2RTheta(const Line &line, float &r, float &theta)
03179 {
03180
03181 if(line.startPoint.x == line.endPoint.x)
03182 {
03183
03184 r = fabs(line.startPoint.x);
03185
03186 theta = line.startPoint.x>=0 ? 0. : CV_PI;
03187 }
03188
03189 else if(line.startPoint.y == line.endPoint.y)
03190 {
03191
03192 r = fabs(line.startPoint.y);
03193
03194 theta = (float) line.startPoint.y>=0 ? CV_PI/2 : -CV_PI/2;
03195 }
03196
03197 else
03198 {
03199
03200 theta = atan2(line.endPoint.x-line.startPoint.x,
03201 line.startPoint.y-line.endPoint.y);
03202
03203 float r1 = line.startPoint.x * cos(theta) + line.startPoint.y * sin(theta);
03204 r = line.endPoint.x * cos(theta) + line.endPoint.y * sin(theta);
03205
03206 if(r1<0 || r<0)
03207 {
03208
03209 theta += CV_PI;
03210 if(theta>CV_PI)
03211 theta -= 2*CV_PI;
03212
03213 r = fabs(r);
03214 }
03215 }
03216 }
03217
03230 void mcvFitRobustLine(const CvMat *points, float *lineRTheta,
03231 float *lineAbc)
03232 {
03233
03234 CvMat *cpoints = cvCloneMat(points);
03235
03236 float meanX=0, meanY=0;
03237 CvScalar mean;
03238 CvMat row1, row2;
03239
03240 cvGetRow(cpoints, &row1, 0);
03241 mean = cvAvg(&row1);
03242 meanX = (float) mean.val[0];
03243 cvSubS(&row1, mean, &row1);
03244
03245 cvGetRow(cpoints, &row2, 1);
03246 mean = cvAvg(&row2);
03247 meanY = (float) mean.val[0];
03248 cvSubS(&row2, mean, &row2);
03249
03250
03251 CvMat *W = cvCreateMat(2, 1, CV_32FC1);
03252 CvMat *V = cvCreateMat(2, 2, CV_32FC1);
03253
03254 CvMat *cpointst = cvCreateMat(cpoints->cols, cpoints->rows, CV_32FC1);
03255 cvTranspose(cpoints, cpointst);
03256 cvSVD(cpointst, W, 0, V, CV_SVD_V_T);
03257 cvTranspose(V, V);
03258 cvReleaseMat(&cpointst);
03259
03260
03261
03262 float a, b, c;
03263 a = CV_MAT_ELEM(*V, float, 0, 1);
03264 b = CV_MAT_ELEM(*V, float, 1, 1);
03265
03266
03267 c = -(meanX * a + meanY * b);
03268
03269
03270
03271
03272 float r, theta;
03273 theta = atan2(b, a);
03274 r = meanX * cos(theta) + meanY * sin(theta);
03275
03276 if (r<0)
03277 {
03278
03279 r = -r;
03280
03281 theta += CV_PI;
03282 if (theta>CV_PI)
03283 theta -= 2*CV_PI;
03284 }
03285
03286 if (lineRTheta)
03287 {
03288 lineRTheta[0] = r;
03289 lineRTheta[1] = theta;
03290 }
03291 if (lineAbc)
03292 {
03293 lineAbc[0] = a;
03294 lineAbc[1] = b;
03295 lineAbc[2] = c;
03296 }
03297
03298 cvReleaseMat(&cpoints);
03299 cvReleaseMat(&W);
03300 cvReleaseMat(&V);
03301 }
03302
03303
03304
03322 void mcvFitRansacLine(const CvMat *image, int numSamples, int numIterations,
03323 float threshold, float scoreThreshold, int numGoodFit,
03324 bool getEndPoints, LineType lineType,
03325 Line *lineXY, float *lineRTheta, float *lineScore)
03326 {
03327
03328
03329 CvMat *points;
03330 points = mcvGetNonZeroPoints(image,true);
03331 if (!points)
03332 return;
03333
03334 if (numSamples>points->cols)
03335 numSamples = points->cols;
03336
03337 cvAddS(points, cvRealScalar(0.5), points);
03338
03339
03340
03341 CvMat w;
03342 cvGetRow(points, &w, 2);
03343
03344 CvMat *weights = cvCloneMat(&w);
03345 cvNormalize(weights, weights, 1, 0, CV_L1);
03346
03347 mcvCumSum(weights, weights);
03348
03349
03350 CvRNG rng = cvRNG(0xffffffff);
03351
03352 CvMat *randInd = cvCreateMat(numSamples, 1, CV_32SC1);
03353 CvMat *samplePoints = cvCreateMat(2, numSamples, CV_32FC1);
03354
03355 CvMat *pointIn = cvCreateMat(1, points->cols, CV_8SC1);
03356
03357 float curLineRTheta[2], curLineAbc[3];
03358 float bestLineRTheta[2]={-1.f,0.f};
03359 float bestLineAbc[3];
03360 float bestScore=0;
03361 float bestDist=1e5;
03362 float dist, score;
03363 Line curEndPointLine={{-1.,-1.},{-1.,-1.}},
03364 bestEndPointLine={{-1.,-1.},{-1.,-1.}};
03365
03366
03367 float minc=1e5f, maxc=-1e5f, mind, maxd;
03368 float x, y, c=0.;
03369 CvPoint2D32f minp={-1., -1.}, maxp={-1., -1.};
03370
03371 for (int i=0; i<numIterations; i++)
03372 {
03373
03374
03375 cvSetZero(pointIn);
03376
03377 #warning "Using weighted sampling for Ransac Line"
03378
03379 mcvSampleWeighted(weights, numSamples, randInd, &rng);
03380
03381 for (int j=0; j<numSamples; j++)
03382 {
03383
03384 CV_MAT_ELEM(*pointIn, char, 0, CV_MAT_ELEM(*randInd, int, j, 0)) = 1;
03385
03386 CV_MAT_ELEM(*samplePoints, float, 0, j) =
03387 CV_MAT_ELEM(*points, float, 0, CV_MAT_ELEM(*randInd, int, j, 0));
03388 CV_MAT_ELEM(*samplePoints, float, 1, j) =
03389 CV_MAT_ELEM(*points, float, 1, CV_MAT_ELEM(*randInd, int, j, 0));
03390 }
03391
03392
03393 mcvFitRobustLine(samplePoints, curLineRTheta, curLineAbc);
03394
03395
03396 minc = 1e5; mind = 1e5; maxc = -1e5; maxd = -1e5;
03397 for (int j=0; getEndPoints && j<numSamples; ++j)
03398 {
03399
03400 x = CV_MAT_ELEM(*samplePoints, float, 0, j);
03401 y = CV_MAT_ELEM(*samplePoints, float, 1, j);
03402
03403
03404 if (lineType == LINE_HORIZONTAL)
03405 c = x;
03406 else if (lineType == LINE_VERTICAL)
03407 c = y;
03408
03409 if (c>maxc)
03410 {
03411 maxc = c;
03412 maxp = cvPoint2D32f(x, y);
03413 }
03414 if (c<minc)
03415 {
03416 minc = c;
03417 minp = cvPoint2D32f(x, y);
03418 }
03419 }
03420
03421
03422
03423
03424
03425 score=0;
03426 for (int j=0; j<points->cols; j++)
03427 {
03428
03429
03430
03431
03432 dist = fabs(CV_MAT_ELEM(*points, float, 0, j) * curLineAbc[0] +
03433 CV_MAT_ELEM(*points, float, 1, j) * curLineAbc[1] + curLineAbc[2]);
03434
03435 if (dist<=threshold)
03436 {
03437
03438 CV_MAT_ELEM(*pointIn, char, 0, j) = 1;
03439
03440 score += cvGetReal2D(image, (int)(CV_MAT_ELEM(*points, float, 1, j)-.5),
03441 (int)(CV_MAT_ELEM(*points, float, 0, j)-.5));
03442 }
03443
03444 }
03445
03446
03447 int numClose = cvCountNonZero(pointIn);
03448
03449 if (numClose >= numGoodFit)
03450 {
03451
03452 CvMat *fitPoints = cvCreateMat(2, numClose, CV_32FC1);
03453 int k=0;
03454
03455 for (int j=0; j<points->cols; j++)
03456 if(CV_MAT_ELEM(*pointIn, char, 0, j))
03457 {
03458 CV_MAT_ELEM(*fitPoints, float, 0, k) =
03459 CV_MAT_ELEM(*points, float, 0, j);
03460 CV_MAT_ELEM(*fitPoints, float, 1, k) =
03461 CV_MAT_ELEM(*points, float, 1, j);
03462 k++;
03463
03464 }
03465
03466
03467 mcvFitRobustLine(fitPoints, curLineRTheta, curLineAbc);
03468
03469
03470 dist = 0.;
03471 for (int j=0; j<fitPoints->cols; j++)
03472 {
03473
03474 x = CV_MAT_ELEM(*fitPoints, float, 0, j);
03475 y = CV_MAT_ELEM(*fitPoints, float, 1, j);
03476 float d = fabs( x * curLineAbc[0] +
03477 y * curLineAbc[1] +
03478 curLineAbc[2])
03479 * cvGetReal2D(image, (int)(y-.5), (int)(x-.5));
03480 dist += d;
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507 }
03508
03509
03510 if (getEndPoints)
03511 {
03512
03513
03514 mind = minp.x * curLineAbc[0] +
03515 minp.y * curLineAbc[1] + curLineAbc[2];
03516 maxd = maxp.x * curLineAbc[0] +
03517 maxp.y * curLineAbc[1] + curLineAbc[2];
03518
03519
03520
03521
03522 curEndPointLine.startPoint.x = minp.x
03523 - mind * curLineAbc[0];
03524 curEndPointLine.startPoint.y = minp.y
03525 - mind * curLineAbc[1];
03526
03527 curEndPointLine.endPoint.x = maxp.x
03528 - maxd * curLineAbc[0];
03529 curEndPointLine.endPoint.y = maxp.y
03530 - maxd * curLineAbc[1];
03531
03532
03533
03534 }
03535
03536
03537
03538
03539 cvReleaseMat(&fitPoints);
03540
03541
03542 if (score>=scoreThreshold && score>bestScore)
03543 {
03544
03545 bestScore = score;
03546 bestDist = dist;
03547
03548 bestLineRTheta[0] = curLineRTheta[0];
03549 bestLineRTheta[1] = curLineRTheta[1];
03550 bestLineAbc[0] = curLineAbc[0];
03551 bestLineAbc[1] = curLineAbc[1];
03552 bestLineAbc[2] = curLineAbc[2];
03553 bestEndPointLine = curEndPointLine;
03554 }
03555 }
03556
03557
03558 if (DEBUG_LINES) {
03559 char str[256];
03560
03561 CvMat* im = cvCloneMat(image);
03562 mcvScaleMat(image, im);
03563 CvMat *imageClr = cvCreateMat(image->rows, image->cols, CV_32FC3);
03564 cvCvtColor(im, imageClr, CV_GRAY2RGB);
03565
03566 Line line;
03567
03568 if (curLineRTheta[0]>0)
03569 {
03570 mcvIntersectLineRThetaWithBB(curLineRTheta[0], curLineRTheta[1],
03571 cvSize(image->cols, image->rows), &line);
03572 mcvDrawLine(imageClr, line, CV_RGB(1,0,0), 1);
03573 if (getEndPoints)
03574 mcvDrawLine(imageClr, curEndPointLine, CV_RGB(0,1,0), 1);
03575 }
03576
03577
03578 if (bestLineRTheta[0]>0)
03579 {
03580 mcvIntersectLineRThetaWithBB(bestLineRTheta[0], bestLineRTheta[1],
03581 cvSize(image->cols, image->rows), &line);
03582 mcvDrawLine(imageClr, line, CV_RGB(0,0,1), 1);
03583 if (getEndPoints)
03584 mcvDrawLine(imageClr, bestEndPointLine, CV_RGB(1,1,0), 1);
03585 }
03586 sprintf(str, "scor=%.2f, best=%.2f", score, bestScore);
03587 mcvDrawText(imageClr, str, cvPoint(30, 30), .25, CV_RGB(255,255,255));
03588
03589 SHOW_IMAGE(imageClr, "Fit Ransac Line", 10);
03590
03591
03592 cvReleaseMat(&im);
03593 cvReleaseMat(&imageClr);
03594 }
03595 }
03596
03597
03598 if (lineRTheta)
03599 {
03600 lineRTheta[0] = bestLineRTheta[0];
03601 lineRTheta[1] = bestLineRTheta[1];
03602 }
03603 if (lineXY)
03604 {
03605 if (getEndPoints)
03606 *lineXY = bestEndPointLine;
03607 else
03608 mcvIntersectLineRThetaWithBB(lineRTheta[0], lineRTheta[1],
03609 cvSize(image->cols-1, image->rows-1),
03610 lineXY);
03611 }
03612 if (lineScore)
03613 *lineScore = bestScore;
03614
03615
03616 cvReleaseMat(&points);
03617 cvReleaseMat(&samplePoints);
03618 cvReleaseMat(&randInd);
03619 cvReleaseMat(&pointIn);
03620 }
03621
03622
03623
03624
03633 CvMat* mcvGetNonZeroPoints(const CvMat *inMat, bool floatMat)
03634 {
03635
03636
03637 #define MCV_GET_NZ_POINTS(inMatType, outMatType) \
03638 \
03639 for (int i=0; i<inMat->rows; i++) \
03640 for (int j=0; j<inMat->cols; j++) \
03641 if (CV_MAT_ELEM(*inMat, inMatType, i, j)) \
03642 { \
03643 CV_MAT_ELEM(*outMat, outMatType, 0, k) = j; \
03644 CV_MAT_ELEM(*outMat, outMatType, 1, k) = i; \
03645 CV_MAT_ELEM(*outMat, outMatType, 2, k) = \
03646 (outMatType) CV_MAT_ELEM(*inMat, inMatType, i, j); \
03647 k++; \
03648 } \
03649
03650 int k=0;
03651
03652
03653 int numnz = cvCountNonZero(inMat);
03654
03655
03656 CvMat* outMat;
03657 if (numnz)
03658 {
03659 if (floatMat)
03660 outMat = cvCreateMat(3, numnz, CV_32FC1);
03661 else
03662 outMat = cvCreateMat(3, numnz, CV_32SC1);
03663 }
03664 else
03665 return NULL;
03666
03667
03668 if (CV_MAT_TYPE(inMat->type)==FLOAT_MAT_TYPE &&
03669 CV_MAT_TYPE(outMat->type)==FLOAT_MAT_TYPE)
03670 {
03671 MCV_GET_NZ_POINTS(FLOAT_MAT_ELEM_TYPE, FLOAT_MAT_ELEM_TYPE)
03672 }
03673 else if (CV_MAT_TYPE(inMat->type)==FLOAT_MAT_TYPE &&
03674 CV_MAT_TYPE(outMat->type)==INT_MAT_TYPE)
03675 {
03676 MCV_GET_NZ_POINTS(FLOAT_MAT_ELEM_TYPE, INT_MAT_ELEM_TYPE)
03677 }
03678 else if (CV_MAT_TYPE(inMat->type)==INT_MAT_TYPE &&
03679 CV_MAT_TYPE(outMat->type)==FLOAT_MAT_TYPE)
03680 {
03681 MCV_GET_NZ_POINTS(INT_MAT_ELEM_TYPE, FLOAT_MAT_ELEM_TYPE)
03682 }
03683 else if (CV_MAT_TYPE(inMat->type)==INT_MAT_TYPE &&
03684 CV_MAT_TYPE(outMat->type)==INT_MAT_TYPE)
03685 {
03686 MCV_GET_NZ_POINTS(INT_MAT_ELEM_TYPE, INT_MAT_ELEM_TYPE)
03687 }
03688 else
03689 {
03690 cerr << "Unsupported type in mcvGetMatLocalMax\n";
03691 exit(1);
03692 }
03693
03694
03695 return outMat;
03696 }
03697
03698
03706 void mcvGroupLines(vector<Line> &lines, vector<float> &lineScores,
03707 float groupThreshold, CvSize bbox)
03708 {
03709
03710
03711 int numInLines = lines.size();
03712 vector<float> rs(numInLines);
03713 vector<float> thetas(numInLines);
03714 for (int i=0; i<numInLines; i++)
03715 mcvLineXY2RTheta(lines[i], rs[i], thetas[i]);
03716
03717
03718 bool stop = false;
03719 while (!stop)
03720 {
03721
03722 float minDist = groupThreshold+5, dist;
03723 vector<float>::iterator ir, jr, itheta, jtheta, minIr, minJr, minItheta, minJtheta,
03724 iscore, jscore, minIscore, minJscore;
03725
03726 for (ir=rs.begin(), itheta=thetas.begin(), iscore=lineScores.begin();
03727 ir!=rs.end(); ir++, itheta++, iscore++)
03728 for (jr=ir+1, jtheta=itheta+1, jscore=iscore+1;
03729 jr!=rs.end(); jr++, jtheta++, jscore++)
03730 {
03731
03732 float t1 = *itheta<0 ? *itheta : *itheta+CV_PI;
03733 float t2 = *jtheta<0 ? *jtheta : *jtheta+CV_PI;
03734
03735 dist = 1 * fabs(*ir - *jr) + 1 * fabs(t1 - t2);
03736
03737 if (dist<minDist)
03738 {
03739 minDist = dist;
03740 minIr = ir; minItheta = itheta;
03741 minJr = jr; minJtheta = jtheta;
03742 minIscore = iscore; minJscore = jscore;
03743 }
03744 }
03745
03746 if (minDist >= groupThreshold)
03747 stop = true;
03748 else
03749 {
03750
03751 *minIr = (*minIr + *minJr)/2;
03752 *minItheta = (*minItheta + *minJtheta)/2;
03753 *minIscore = (*minIscore + *minJscore)/2;
03754
03755 rs.erase(minJr);
03756 thetas.erase(minJtheta);
03757 lineScores.erase(minJscore);
03758 }
03759 }
03760
03761
03762 lines.clear();
03763
03764 vector<float> newScores=lineScores;
03765 lineScores.clear();
03766 for (int i=0; i<(int)rs.size(); i++)
03767 {
03768
03769 Line line;
03770 mcvIntersectLineRThetaWithBB(rs[i], thetas[i], bbox, &line);
03771
03772 vector<float>::iterator iscore;
03773 vector<Line>::iterator iline;
03774 for (iscore=lineScores.begin(), iline=lines.begin();
03775 iscore!=lineScores.end() && newScores[i]<=*iscore; iscore++, iline++);
03776 lineScores.insert(iscore, newScores[i]);
03777 lines.insert(iline, line);
03778 }
03779
03780 newScores.clear();
03781 }
03782
03788 void mcvGroupSplines(vector<Spline> &splines, vector<float> &scores)
03789
03790 {
03791
03792
03793 if(DEBUG_LINES) {
03794
03795 CvMat* im = cvCreateMat(240, 320, CV_8UC3);
03796 cvSet(im, cvRealScalar(0.));
03797
03798 for (unsigned int i=0; i<splines.size(); i++)
03799 mcvDrawSpline(im, splines[i], CV_RGB(255, 0, 0), 1);
03800
03801 SHOW_IMAGE(im, "Splines Before grouping", 10);
03802
03803 cvReleaseMat(&im);
03804
03805 }
03806
03807
03808
03809 bool stop = false;
03810 while (!stop)
03811 {
03812
03813 stop = true;
03814
03815 vector<Spline>::iterator spi, spj;
03816 vector<float>::iterator si, sj;
03817 for (spi=splines.begin(), si=scores.begin();
03818 spi!=splines.end(); spi++, si++)
03819 for (spj=spi+1, sj=si+1; spj!=splines.end(); spj++, sj++)
03820
03821 if (mcvCheckMergeSplines(*spi, *spj, .1, 5, .2, 10, 15))
03822 {
03823 stop = false;
03824
03825 float ci, cj;
03826 mcvGetSplineFeatures(*spi, 0, 0, 0, 0, 0, 0, &ci);
03827 mcvGetSplineFeatures(*spj, 0, 0, 0, 0, 0, 0, &cj);
03828
03829 if (cj>ci)
03830 {
03831
03832 *spi = *spj;
03833 *si = *sj;
03834 }
03835
03836 splines.erase(spj);
03837 scores.erase(sj);
03838
03839
03840 break;
03841 }
03842 }
03843
03844
03845 if(DEBUG_LINES) {
03846
03847 CvMat* im = cvCreateMat(240, 320, CV_8UC3);
03848 cvSet(im, cvRealScalar(0.));
03849
03850 for (unsigned int i=0; i<splines.size(); i++)
03851 mcvDrawSpline(im, splines[i], CV_RGB(255, 0, 0), 1);
03852
03853 SHOW_IMAGE(im, "Splines After grouping", 10);
03854
03855 cvReleaseMat(&im);
03856
03857 }
03858
03859 }
03860
03868 void mcvGroupBoundingBoxes(vector<CvRect> &boxes, LineType type,
03869 float groupThreshold)
03870 {
03871 bool cont = true;
03872
03873
03874
03875
03876
03877
03878
03879
03880 float overlap, maxOverlap;
03881 while(cont)
03882 {
03883 maxOverlap = overlap = -1e5;
03884
03885 vector<CvRect>::iterator i, j, maxI, maxJ;
03886 for(i = boxes.begin(); i != boxes.end(); i++)
03887 {
03888 for(j = i+1; j != boxes.end(); j++)
03889 {
03890 switch(type)
03891 {
03892 case LINE_VERTICAL:
03893
03894
03895 overlap = i->x < j->x ?
03896 (i->x + i->width - j->x) / (float)j->width :
03897 (j->x + j->width - i->x) / (float)i->width;
03898
03899 break;
03900
03901 case LINE_HORIZONTAL:
03902
03903
03904 overlap = i->y < j->y ?
03905 (i->y + i->height - j->y) / (float)j->height :
03906 (j->y + j->height - i->y) / (float)i->height;
03907
03908 break;
03909
03910 }
03911
03912
03913 if(overlap > maxOverlap)
03914 {
03915 maxI = i;
03916 maxJ = j;
03917 maxOverlap = overlap;
03918 }
03919 }
03920 }
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930 if (maxOverlap >= groupThreshold)
03931 {
03932
03933 *maxI = cvRect(min((*maxI).x, (*maxJ).x),
03934 min((*maxI).y, (*maxJ).y),
03935 max((*maxI).width, (*maxJ).width),
03936 max((*maxI).height, (*maxJ).height));
03937
03938 boxes.erase(maxJ);
03939 }
03940 else
03941
03942 cont = false;
03943
03944
03945
03946
03947
03948
03949
03950 }
03951 }
03952
03962 void mcvGetRansacLines(const CvMat *im, vector<Line> &lines,
03963 vector<float> &lineScores, LaneDetectorConf *lineConf,
03964 LineType lineType)
03965 {
03966
03967 CvMat *image = cvCloneMat(im);
03968 if (lineConf->ransacLineBinarize)
03969 mcvBinarizeImage(image);
03970
03971 int width = image->width-1;
03972 int height = image->height-1;
03973
03974
03975 mcvGroupLines(lines, lineScores, lineConf->groupThreshold,
03976 cvSize(width, height));
03977
03978
03979 float overlapThreshold = lineConf->overlapThreshold;
03980 vector<CvRect> boxes;
03981 mcvGetLinesBoundingBoxes(lines, lineType, cvSize(width, height),
03982 boxes);
03983 mcvGroupBoundingBoxes(boxes, lineType, overlapThreshold);
03984
03985
03986
03987
03988
03989
03990
03991 int window = lineConf->ransacLineWindow;
03992 vector<Line> newLines;
03993 vector<float> newScores;
03994 for (int i=0; i<(int)boxes.size(); i++)
03995 {
03996
03997
03998 CvRect mask, box;
03999
04000 box = boxes[i];
04001 switch (lineType)
04002 {
04003 case LINE_HORIZONTAL:
04004 {
04005
04006
04007
04008 int ystart = (int)fmax(box.y - window, 0);
04009 int yend = (int)fmin(box.y + box.height + window, height-1);
04010
04011 mask = cvRect(0, ystart, width, yend-ystart+1);
04012 }
04013 break;
04014
04015 case LINE_VERTICAL:
04016 {
04017
04018
04019
04020 int xstart = (int)fmax(box.x - window, 0);
04021 int xend = (int)fmin(box.x + box.width + window, width-1);
04022
04023 mask = cvRect(xstart, 0, xend-xstart+1, height);
04024 }
04025 break;
04026 }
04027
04028 CvMat *subimage = cvCloneMat(image);
04029
04030 mcvSetMat(subimage, mask, 0);
04031
04032
04033
04034
04035 float lineRTheta[2]={-1,0};
04036 float lineScore;
04037 Line line;
04038 mcvFitRansacLine(subimage, lineConf->ransacLineNumSamples,
04039 lineConf->ransacLineNumIterations,
04040 lineConf->ransacLineThreshold,
04041 lineConf->ransacLineScoreThreshold,
04042 lineConf->ransacLineNumGoodFit,
04043 lineConf->getEndPoints, lineType,
04044 &line, lineRTheta, &lineScore);
04045
04046
04047
04048 #warning "check this screening in ransacLines"
04049 if (lineRTheta[0]>=0)
04050 {
04051 bool put =true;
04052 switch(lineType)
04053 {
04054 case LINE_HORIZONTAL:
04055
04056 if (fabs(lineRTheta[1]) < 30*CV_PI/180)
04057 put = false;
04058 break;
04059
04060 case LINE_VERTICAL:
04061
04062 if((fabs(lineRTheta[1]) > 20*CV_PI/180))
04063 put = false;
04064 break;
04065 }
04066 if (put)
04067 {
04068 newLines.push_back(line);
04069 newScores.push_back(lineScore);
04070 }
04071 }
04072
04073
04074 if(DEBUG_LINES) {
04075
04076
04077 char str[256];
04078 switch (lineType)
04079 {
04080 case LINE_HORIZONTAL:
04081 sprintf(str, "Subimage Line H #%d", i);
04082 break;
04083 case LINE_VERTICAL:
04084 sprintf(str, "Subimage Line V #%d", i);
04085 break;
04086 }
04087
04088 mcvScaleMat(subimage, subimage);
04089 CvMat *subimageClr = cvCreateMat(subimage->rows, subimage->cols,
04090 CV_32FC3);
04091 cvCvtColor(subimage, subimageClr, CV_GRAY2RGB);
04092
04093
04094
04095 mcvDrawRectangle(subimageClr, mask, CV_RGB(255, 255, 255), 1);
04096
04097
04098 if (lineRTheta[0]>0)
04099 mcvDrawLine(subimageClr, line, CV_RGB(1,0,0), 1);
04100 SHOW_IMAGE(subimageClr, str, 10);
04101
04102 cvReleaseMat(&subimageClr);
04103 }
04104
04105
04106 cvReleaseMat(&subimage);
04107 }
04108
04109
04110 vector<Line> oldLines;
04111 if (DEBUG_LINES)
04112 oldLines = lines;
04113 lines.clear();
04114 lineScores.clear();
04115 #warning "not grouping at end of getRansacLines"
04116
04117 lines = newLines;
04118 lineScores = newScores;
04119
04120
04121 if(DEBUG_LINES) {
04122
04123
04124 char title[256];
04125 switch (lineType)
04126 {
04127 case LINE_HORIZONTAL:
04128 sprintf(title, "Lines H");
04129 break;
04130 case LINE_VERTICAL:
04131 sprintf(title, "Lines V");
04132 break;
04133 }
04134
04135 CvMat* im2 = cvCloneMat(im);
04136 mcvScaleMat(im2, im2);
04137 CvMat *imClr = cvCreateMat(im->rows, im->cols, CV_32FC3);
04138 cvCvtColor(im2, imClr, CV_GRAY2RGB);
04139 CvMat* imClr2 = cvCloneMat(imClr);
04140 cvReleaseMat(&im2);
04141
04142
04143 for (unsigned int j=0; j<lines.size(); j++)
04144 mcvDrawLine(imClr, lines[j], CV_RGB(0,1,0), 1);
04145 SHOW_IMAGE(imClr, title, 10);
04146
04147
04148 for (unsigned int j=0; j<oldLines.size(); j++)
04149 mcvDrawLine(imClr2, oldLines[j], CV_RGB(1,0,0), 1);
04150 SHOW_IMAGE(imClr2, "Input Lines", 10);
04151
04152
04153 cvReleaseMat(&imClr);
04154 cvReleaseMat(&imClr2);
04155 oldLines.clear();
04156 }
04157
04158
04159
04160
04161
04162
04163
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174 boxes.clear();
04175 newLines.clear();
04176 newScores.clear();
04177 cvReleaseMat(&image);
04178 }
04179
04186 void mcvSetMat(CvMat *inMat, CvRect mask, double val)
04187 {
04188
04189
04190
04191 int xstart = mask.x, xend = mask.x + mask.width-1;
04192
04193 int ystart = mask.y, yend = mask.y + mask.height-1;
04194
04195
04196 CvMat maskMat;
04197 CvRect rect;
04198
04199 rect = cvRect(0, 0, xstart-1, inMat->height);
04200 if (rect.x<inMat->width && rect.y<inMat->height &&
04201 rect.x>=0 && rect.y>=0 && rect.width>0 && rect.height>0)
04202 {
04203 cvGetSubRect(inMat, &maskMat, rect);
04204 cvSet(&maskMat, cvRealScalar(val));
04205 }
04206
04207 rect = cvRect(xend+1, 0, inMat->width-xend-1, inMat->height);
04208 if (rect.x<inMat->width && rect.y<inMat->height &&
04209 rect.x>=0 && rect.y>=0 && rect.width>0 && rect.height>0)
04210 {
04211 cvGetSubRect(inMat, &maskMat, rect);
04212 cvSet(&maskMat, cvRealScalar(val));
04213 }
04214
04215
04216 rect = cvRect(xstart, 0, mask.width, ystart-1);
04217 if (rect.x<inMat->width && rect.y<inMat->height &&
04218 rect.x>=0 && rect.y>=0 && rect.width>0 && rect.height>0)
04219 {
04220 cvGetSubRect(inMat, &maskMat, rect);
04221 cvSet(&maskMat, cvRealScalar(val));
04222 }
04223
04224
04225 rect = cvRect(xstart, yend+1, mask.width, inMat->height-yend-1);
04226 if (rect.x<inMat->width && rect.y<inMat->height &&
04227 rect.x>=0 && rect.y>=0 && rect.width>0 && rect.height>0)
04228 {
04229 cvGetSubRect(inMat, &maskMat, rect);
04230 cvSet(&maskMat, cvRealScalar(val));
04231 }
04232 }
04233
04234
04242 void mcvSortPoints(const CvMat *inPoints, CvMat *outPoints,
04243 int dim, int dir)
04244 {
04245
04246 CvMat *pts = cvCloneMat(inPoints);
04247
04248
04249
04250
04251
04252 list<int> sorted;
04253 list<int>::iterator sortedi;
04254 int i, j;
04255
04256
04257 for (i=0; i<pts->height; i++)
04258 {
04259
04260 if (dir==0)
04261 for (sortedi = sorted.begin();
04262 sortedi != sorted.end() &&
04263 (CV_MAT_ELEM(*pts, float, i, dim) >=
04264 CV_MAT_ELEM(*outPoints, float, *sortedi, dim));
04265 sortedi++);
04266
04267 else
04268 for (sortedi = sorted.begin();
04269 sortedi != sorted.end() &&
04270 (CV_MAT_ELEM(*pts, float, i, dim) <=
04271 CV_MAT_ELEM(*outPoints, float, *sortedi, dim));
04272 sortedi++);
04273
04274
04275 sorted.insert(sortedi, i);
04276 }
04277
04278
04279 for (i=0, sortedi=sorted.begin(); sortedi != sorted.end(); sortedi++, i++)
04280 for(j=0; j<outPoints->width; j++)
04281 CV_MAT_ELEM(*outPoints, float, i, j) = CV_MAT_ELEM(*pts, float,
04282 *sortedi, j);
04283
04284
04285 cvReleaseMat(&pts);
04286 sorted.clear();
04287 }
04288
04295 Spline mcvFitBezierSpline(CvMat *points, int degree)
04296 {
04297
04298
04299 Spline spline;
04300 spline.degree = degree;
04301
04302
04303 int n = points->height;
04304
04305
04306
04307 mcvSortPoints(points, points, 1, 0);
04308
04309
04310
04311
04312
04313
04314 float diff = 0.f;
04315 float *us = new float[points->height];
04316 us[0] = 0;
04317 for (int i=1; i<points->height; ++i)
04318 {
04319 float dx = CV_MAT_ELEM(*points, float, i, 0) -
04320 CV_MAT_ELEM(*points, float, i-1, 0);
04321 float dy = CV_MAT_ELEM(*points, float, i, 1) -
04322 CV_MAT_ELEM(*points, float, i-1, 1);
04323 us[i] = cvSqrt(dx*dx + dy*dy) + us[i-1];
04324
04325 }
04326 diff = us[points->height-1];
04327
04328
04329
04330
04331
04332 float M2[] = {1, -2, 1,
04333 -2, 2, 0,
04334 1, 0, 0};
04335 float M3[] = {-1, 3, -3, 1,
04336 3, -6, 3, 0,
04337 -3, 3, 0, 0,
04338 1, 0, 0, 0};
04339
04340
04341 CvMat M;
04342
04343
04344 CvMat *B;
04345
04346
04347 float u = 0.f;
04348
04349
04350 switch(degree)
04351 {
04352
04353 case 2:
04354
04355 M = cvMat(3, 3, CV_32FC1, M2);
04356
04357
04358 B = cvCreateMat(n, 3, CV_32FC1);
04359 for (int i=0; i<B->height; i++)
04360 {
04361
04362
04363
04364
04365
04366
04367
04368
04369 u = us[i] / diff;
04370
04371 CV_MAT_ELEM(*B, float, i, 2) = 1;
04372 CV_MAT_ELEM(*B, float, i, 1) = u;
04373 CV_MAT_ELEM(*B, float, i, 0) = u*u;
04374 }
04375 break;
04376
04377
04378 case 3:
04379
04380 M = cvMat(4, 4, CV_32FC1, M3);
04381
04382
04383 B = cvCreateMat(n, 4, CV_32FC1);
04384 for (int i=0; i<B->height; i++)
04385 {
04386
04387
04388
04389
04390
04391
04392
04393
04394 u = us[i] / diff;
04395
04396 CV_MAT_ELEM(*B, float, i, 3) = 1;
04397 CV_MAT_ELEM(*B, float, i, 2) = u;
04398 CV_MAT_ELEM(*B, float, i, 1) = u*u;
04399 CV_MAT_ELEM(*B, float, i, 0) = u*u*u;
04400 }
04401 break;
04402 }
04403
04404
04405 cvMatMul(B, &M, B);
04406
04407
04408
04409 CvMat *sp = cvCreateMat(degree+1, 2, CV_32FC1);
04410 cvSolve(B, points, sp, CV_SVD);
04411
04412
04413
04414
04415 memcpy((float *)spline.points, sp->data.fl, sizeof(float)*(spline.degree+1)*2);
04416
04417
04418
04419
04420 cvReleaseMat(&B);
04421 cvReleaseMat(&sp);
04422 delete [] us;
04423
04424
04425 return spline;
04426 }
04427
04428
04429
04437 CvMat* mcvEvalBezierSpline(const Spline &spline, float h, CvMat *tangents)
04438 {
04439
04440 int n = (int)(1./h)+1;
04441
04442
04443 CvMat *points = cvCreateMat(n, 2, CV_32FC1);
04444
04445
04446 CvMat M;
04447 float M2[] = {1, -2, 1,
04448 -2, 2, 0,
04449 1, 0, 0};
04450 float M3[] = {-1, 3, -3, 1,
04451 3, -6, 3, 0,
04452 -3, 3, 0, 0,
04453 1, 0, 0, 0};
04454
04455
04456 CvMat *sp = cvCreateMat(spline.degree+1, 2, CV_32FC1);
04457 memcpy(sp->data.fl, (float *)spline.points,
04458 sizeof(float)*(spline.degree+1)*2);
04459
04460
04461 CvMat *abcd;
04462
04463 float P[2], dP[2], ddP[2], dddP[2];
04464 float h2 = h*h, h3 = h2*h;
04465
04466
04467 switch(spline.degree)
04468 {
04469
04470 case 2:
04471
04472 M = cvMat(3, 3, CV_32FC1, M2);
04473
04474
04475 abcd = cvCreateMat(3, 2, CV_32FC1);
04476 cvMatMul(&M, sp, abcd);
04477
04478
04479 P[0] = CV_MAT_ELEM(*abcd, float, 2, 0);
04480 P[1] = CV_MAT_ELEM(*abcd, float, 2, 1);
04481
04482
04483 dP[0] = CV_MAT_ELEM(*abcd, float, 1, 0)*h +
04484 CV_MAT_ELEM(*abcd, float, 0, 0)*h2;
04485 dP[1] = CV_MAT_ELEM(*abcd, float, 1, 1)*h +
04486 CV_MAT_ELEM(*abcd, float, 0, 1)*h2;
04487
04488
04489 ddP[0] = 2 * CV_MAT_ELEM(*abcd, float, 0, 0)*h2;
04490 ddP[1] = 2 * CV_MAT_ELEM(*abcd, float, 0, 1)*h2;
04491
04492
04493 for (int i=0; i<n; i++)
04494 {
04495
04496 CV_MAT_ELEM(*points, float, i, 0) = P[0];
04497 CV_MAT_ELEM(*points, float, i, 1) = P[1];
04498
04499
04500 P[0] += dP[0]; P[1] += dP[1];
04501 dP[0] += ddP[0]; dP[1] += ddP[1];
04502 }
04503
04504
04505 if (tangents)
04506 {
04507
04508 CV_MAT_ELEM(*tangents, float, 0, 0) =
04509 CV_MAT_ELEM(*abcd, float, 1, 0);
04510 CV_MAT_ELEM(*tangents, float, 0, 1) =
04511 CV_MAT_ELEM(*abcd, float, 1, 1);
04512
04513 CV_MAT_ELEM(*tangents, float, 1, 0) = 2 *
04514 CV_MAT_ELEM(*abcd, float, 0, 0) +
04515 CV_MAT_ELEM(*abcd, float, 1, 0);
04516 CV_MAT_ELEM(*tangents, float, 1, 1) = 2 *
04517 CV_MAT_ELEM(*abcd, float, 0, 1) +
04518 CV_MAT_ELEM(*abcd, float, 1, 1);
04519 }
04520 break;
04521
04522
04523 case 3:
04524
04525 M = cvMat(4, 4, CV_32FC1, M3);
04526
04527
04528 abcd = cvCreateMat(4, 2, CV_32FC1);
04529 cvMatMul(&M, sp, abcd);
04530
04531
04532 P[0] = CV_MAT_ELEM(*abcd, float, 3, 0);
04533 P[1] = CV_MAT_ELEM(*abcd, float, 3, 1);
04534
04535
04536 dP[0] = CV_MAT_ELEM(*abcd, float, 2, 0)*h +
04537 CV_MAT_ELEM(*abcd, float, 1, 0)*h2 +
04538 CV_MAT_ELEM(*abcd, float, 0, 0)*h3;
04539 dP[1] = CV_MAT_ELEM(*abcd, float, 2, 1)*h +
04540 CV_MAT_ELEM(*abcd, float, 1, 1)*h2 +
04541 CV_MAT_ELEM(*abcd, float, 0, 1)*h3;
04542
04543
04544 dddP[0] = 6 * CV_MAT_ELEM(*abcd, float, 0, 0) * h3;
04545 dddP[1] = 6 * CV_MAT_ELEM(*abcd, float, 0, 1) * h3;
04546
04547
04548 ddP[0] = 2 * CV_MAT_ELEM(*abcd, float, 1, 0) * h2 + dddP[0];
04549 ddP[1] = 2 * CV_MAT_ELEM(*abcd, float, 1, 1) * h2 + dddP[1];
04550
04551
04552 for (int i=0; i<n; i++)
04553 {
04554
04555 CV_MAT_ELEM(*points, float, i, 0) = P[0];
04556 CV_MAT_ELEM(*points, float, i, 1) = P[1];
04557
04558
04559 P[0] += dP[0]; P[1] += dP[1];
04560 dP[0] += ddP[0]; dP[1] += ddP[1];
04561 ddP[0] += dddP[0]; ddP[1] += dddP[1];
04562 }
04563
04564
04565 if (tangents)
04566 {
04567
04568 CV_MAT_ELEM(*tangents, float, 0, 0) = CV_MAT_ELEM(*abcd, float, 2, 0);
04569 CV_MAT_ELEM(*tangents, float, 0, 1) = CV_MAT_ELEM(*abcd, float, 2, 1);
04570
04571 CV_MAT_ELEM(*tangents, float, 1, 0) =
04572 3 * CV_MAT_ELEM(*abcd, float, 0, 0) +
04573 2 * CV_MAT_ELEM(*abcd, float, 1, 0) +
04574 CV_MAT_ELEM(*abcd, float, 2, 0);
04575 CV_MAT_ELEM(*tangents, float, 1, 1) =
04576 3 * CV_MAT_ELEM(*abcd, float, 0, 1) +
04577 2 * CV_MAT_ELEM(*abcd, float, 1, 1) +
04578 CV_MAT_ELEM(*abcd, float, 2, 1);
04579 }
04580 break;
04581 }
04582
04583
04584 cvReleaseMat(&abcd);
04585 cvReleaseMat(&sp);
04586
04587
04588 return points;
04589 }
04590
04591
04602 CvMat* mcvGetBezierSplinePixels(Spline &spline, float h, CvSize box,
04603 bool extendSpline)
04604 {
04605
04606 CvMat *tangents = cvCreateMat(2, 2, CV_32FC1);
04607 CvMat * points = mcvEvalBezierSpline(spline, h, tangents);
04608
04609
04610
04611
04612 list<int> inpoints;
04613 list<int>::iterator inpointsi;
04614 int lastin = -1, numin = 0;
04615 for (int i=0; i<points->height; i++)
04616 {
04617
04618 CV_MAT_ELEM(*points, float, i, 0) = cvRound(CV_MAT_ELEM(*points, float, i, 0));
04619 CV_MAT_ELEM(*points, float, i, 1) = cvRound(CV_MAT_ELEM(*points, float, i, 1));
04620
04621
04622 if(CV_MAT_ELEM(*points, float, i, 0) >= 0 &&
04623 CV_MAT_ELEM(*points, float, i, 0) < box.width &&
04624 CV_MAT_ELEM(*points, float, i, 1) >= 0 &&
04625 CV_MAT_ELEM(*points, float, i, 1) < box.height)
04626 {
04627
04628 if(lastin<0 ||
04629 (lastin>=0 &&
04630 !(CV_MAT_ELEM(*points, float, lastin, 1)==
04631 CV_MAT_ELEM(*points, float, i, 1) &&
04632 CV_MAT_ELEM(*points, float, lastin, 0)==
04633 CV_MAT_ELEM(*points, float, i, 0) )) )
04634 {
04635
04636
04637 inpoints.push_back(i);
04638 lastin = i;
04639 numin++;
04640 }
04641 }
04642 }
04643
04644
04645 CvMat *pixelst0, *pixelst1;
04646 if (extendSpline)
04647 {
04648
04649 int p0 = inpoints.front();
04650
04651
04652 Line line;
04653 line.startPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, p0, 0) - 10 *
04654 CV_MAT_ELEM(*tangents, float, 0, 0),
04655 CV_MAT_ELEM(*points, float, p0, 1) - 10 *
04656 CV_MAT_ELEM(*tangents, float, 0, 1));
04657 line.endPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, p0, 0),
04658 CV_MAT_ELEM(*points, float, p0, 1));
04659
04660 mcvIntersectLineWithBB(&line, cvSize(box.width-1, box.height-1), &line);
04661
04662 pixelst0 = mcvGetLinePixels(line);
04663 numin += pixelst0->height;
04664
04665
04666 int p1 = inpoints.back();
04667
04668 line.endPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, p1, 0) + 10 *
04669 CV_MAT_ELEM(*tangents, float, 1, 0),
04670 CV_MAT_ELEM(*points, float, p1, 1) + 10 *
04671 CV_MAT_ELEM(*tangents, float, 1, 1));
04672 line.startPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, p1, 0),
04673 CV_MAT_ELEM(*points, float, p1, 1));
04674
04675 mcvIntersectLineWithBB(&line, cvSize(box.width-1, box.height-1), &line);
04676
04677 pixelst1 = mcvGetLinePixels(line);
04678 numin += pixelst1->height;
04679 }
04680
04681
04682 CvMat *rpoints;
04683 if (numin>0)
04684 rpoints = cvCreateMat(numin, 2, CV_32SC1);
04685 else
04686 {
04687 return NULL;
04688 }
04689
04690
04691
04692 if(extendSpline)
04693 {
04694
04695 memcpy(cvPtr2D(rpoints, 0, 0), pixelst0->data.fl,
04696 sizeof(float)*2*pixelst0->height);
04697 }
04698
04699
04700 int ri = extendSpline ? pixelst0->height : 0;
04701 for (inpointsi=inpoints.begin();
04702 inpointsi!=inpoints.end(); ri++, inpointsi++)
04703 {
04704 CV_MAT_ELEM(*rpoints, int, ri, 0) = (int)CV_MAT_ELEM(*points,
04705 float, *inpointsi, 0);
04706 CV_MAT_ELEM(*rpoints, int, ri, 1) = (int)CV_MAT_ELEM(*points,
04707 float, *inpointsi, 1);
04708 }
04709
04710
04711 if(extendSpline)
04712 {
04713
04714 memcpy(cvPtr2D(rpoints, ri, 0), pixelst1->data.fl,
04715 sizeof(float)*2*pixelst1->height);
04716
04717 cvReleaseMat(&pixelst0);
04718 cvReleaseMat(&pixelst1);
04719 }
04720
04721
04722
04723
04724 cvReleaseMat(&points);
04725 cvReleaseMat(&tangents);
04726 inpoints.clear();
04727
04728
04729 return rpoints;
04730 }
04731
04732
04744 void mcvGetRansacSplines(const CvMat *im, vector<Line> &lines,
04745 vector<float> &lineScores, LaneDetectorConf *lineConf,
04746 LineType lineType, vector<Spline> &splines,
04747 vector<float> &splineScores, LineState* state)
04748 {
04749
04750 CvMat *image = cvCloneMat(im);
04751 if (lineConf->ransacSplineBinarize)
04752 mcvBinarizeImage(image);
04753
04754 int width = image->width;
04755 int height = image->height;
04756
04757
04758 #warning "no line grouping in getRansacSplines"
04759 vector<Line> tlines = lines;
04760 vector<float> tlineScores = lineScores;
04761 mcvGroupLines(tlines, tlineScores, lineConf->groupThreshold,
04762 cvSize(width-1, height-1));
04763
04764
04765 for (unsigned int i=0; state->ipmSplines.size() &&
04766 i<lines.size(); ++i)
04767 {
04768
04769 Spline spline = mcvLineXY2Spline
04770 (lines[i], lineConf->ransacSplineDegree);
04771 state->ipmSplines.push_back(spline);
04772 }
04773
04774
04775 float overlapThreshold = lineConf->overlapThreshold;
04776 vector<CvRect> boxes;
04777 CvSize size = cvSize(width, height);
04778 mcvGetLinesBoundingBoxes(tlines, lineType, size, boxes);
04779 mcvGroupBoundingBoxes(boxes, lineType, overlapThreshold);
04780
04781
04782 tlines.clear();
04783 tlineScores.clear();
04784
04785
04786 #warning "Turned off adding boxes from previous frame"
04787
04788
04789
04790
04791
04792
04793
04794 int window = lineConf->ransacSplineWindow;
04795 vector<Spline> newSplines;
04796 vector<float> newSplineScores;
04797 for (int i=0; i<(int)boxes.size(); i++)
04798 {
04799
04800
04801 CvRect mask, box;
04802
04803
04804 box = boxes[i];
04805
04806 switch (lineType)
04807 {
04808 case LINE_HORIZONTAL:
04809 {
04810
04811
04812
04813 int ystart = (int)fmax(box.y - window, 0);
04814 int yend = (int)fmin(box.y + box.height + window, height-1);
04815
04816 mask = cvRect(0, ystart, width, yend-ystart+1);
04817 }
04818 break;
04819
04820 case LINE_VERTICAL:
04821 {
04822
04823
04824
04825 int xstart = (int)fmax(box.x - window, 0);
04826 int xend = (int)fmin(box.x + box.width + window, width-1);
04827
04828 mask = cvRect(xstart, 0, xend-xstart+1, height);
04829 }
04830 break;
04831 }
04832
04833 CvMat *subimage = cvCloneMat(image);
04834
04835 mcvSetMat(subimage, mask, 0);
04836
04837
04838
04839
04840 Spline spline;
04841 float splineScore;
04842
04843 float h = lineConf->ransacSplineStep;
04844 mcvFitRansacSpline(subimage, lineConf->ransacSplineNumSamples,
04845 lineConf->ransacSplineNumIterations,
04846 lineConf->ransacSplineThreshold,
04847 lineConf->ransacSplineScoreThreshold,
04848 lineConf->ransacSplineNumGoodFit,
04849 lineConf->ransacSplineDegree, h,
04850 &spline, &splineScore,
04851 lineConf->splineScoreJitter,
04852 lineConf->splineScoreLengthRatio,
04853 lineConf->splineScoreAngleRatio,
04854 lineConf->splineScoreStep,
04855 &state->ipmSplines);
04856
04857
04858 if (spline.degree > 0)
04859 {
04860 newSplines.push_back(spline);
04861 newSplineScores.push_back(splineScore);
04862 }
04863
04864
04865 if(DEBUG_LINES) {
04866
04867
04868 char str[256], title[256];;
04869 switch (lineType)
04870 {
04871 case LINE_HORIZONTAL:
04872 sprintf(title, "Subimage Spline H #%d", i);
04873 break;
04874 case LINE_VERTICAL:
04875 sprintf(title, "Subimage Spline V #%d", i);
04876 break;
04877 }
04878
04879 mcvScaleMat(subimage, subimage);
04880 CvMat *subimageClr = cvCreateMat(subimage->rows, subimage->cols,
04881 CV_32FC3);
04882 cvCvtColor(subimage, subimageClr, CV_GRAY2RGB);
04883
04884
04885
04886
04887 mcvDrawRectangle(subimageClr, mask, CV_RGB(255, 255, 255), 1);
04888
04889
04890 sprintf(str, "score=%.2f", splineScore);
04891
04892
04893
04894
04895 if (spline.degree > 0)
04896 mcvDrawSpline(subimageClr, spline, CV_RGB(1,0,0), 1);
04897 SHOW_IMAGE(subimageClr, title, 10);
04898
04899 cvReleaseMat(&subimageClr);
04900 }
04901
04902
04903 cvReleaseMat(&subimage);
04904 }
04905
04906
04907
04908 splines.clear();
04909 splineScores.clear();
04910 vector<Spline>::iterator li;
04911 vector<float>::iterator si;
04912 for (int i=0; i<(int)newSplines.size(); i++)
04913 {
04914
04915 for (li=splines.begin(), si=splineScores.begin();
04916 si!=splineScores.end() && newSplineScores[i]<=*si;
04917 si++, li++);
04918 splines.insert(li, newSplines[i]);
04919 splineScores.insert(si, newSplineScores[i]);
04920 }
04921
04922
04923 mcvGroupSplines(splines, splineScores);
04924
04925
04926 if(DEBUG_LINES) {
04927
04928
04929 char title[256];
04930 switch (lineType)
04931 {
04932 case LINE_HORIZONTAL:
04933 sprintf(title, "Splines H");
04934 break;
04935 case LINE_VERTICAL:
04936 sprintf(title, "Splines V");
04937 break;
04938 }
04939
04940 CvMat* im2 = cvCloneMat(im);
04941 mcvScaleMat(im2, im2);
04942 CvMat *imClr = cvCreateMat(im->rows, im->cols, CV_32FC3);
04943 cvCvtColor(im2, imClr, CV_GRAY2RGB);
04944 cvReleaseMat(&im2);
04945
04946
04947 for (unsigned int j=0; j<splines.size(); j++)
04948 mcvDrawSpline(imClr, splines[j], CV_RGB(0,1,0), 1);
04949 SHOW_IMAGE(imClr, title, 10);
04950
04951 cvReleaseMat(&imClr);
04952 }
04953
04954
04955
04956 boxes.clear();
04957 newSplines.clear();
04958 newSplineScores.clear();
04959 cvReleaseMat(&image);
04960 }
04961
04985 void mcvFitRansacSpline(const CvMat *image, int numSamples, int numIterations,
04986 float threshold, float scoreThreshold, int numGoodFit,
04987 int splineDegree, float h, Spline *spline,
04988 float *splineScore, int splineScoreJitter,
04989 float splineScoreLengthRatio,
04990 float splineScoreAngleRatio, float splineScoreStep,
04991 vector<Spline> *prevSplines)
04992 {
04993
04994 CvMat *points = mcvGetNonZeroPoints(image, true);
04995 if (points==0 || points->cols < numSamples)
04996 {
04997 if (spline) spline->degree = -1;
04998 cvReleaseMat(&points);
04999 return;
05000 }
05001
05002
05003 #warning "check adding half to points"
05004 CvMat p;
05005 cvGetRows(points, &p, 0, 2);
05006 cvAddS(&p, cvRealScalar(0.5), &p);
05007
05008
05009
05010 CvMat w;
05011 cvGetRow(points, &w, 2);
05012
05013 CvMat *weights = cvCloneMat(&w);
05014 cvNormalize(weights, weights, 1, 0, CV_L1);
05015
05016 mcvCumSum(weights, weights);
05017
05018
05019 CvRNG rng = cvRNG(0xffffffff);
05020
05021 CvMat *randInd = cvCreateMat(numSamples, 1, CV_32SC1);
05022 CvMat *samplePoints = cvCreateMat(numSamples, 2, CV_32FC1);
05023
05024 CvMat *pointIn = cvCreateMat(1, points->cols, CV_8SC1);
05025
05026 Spline curSpline, bestSpline;
05027 bestSpline.degree = 0;
05028 float bestScore=0;
05029
05030
05031 vector<Spline>::iterator prevSpline;
05032 bool randSpline = prevSplines==NULL || prevSplines->size()==0;
05033 if (!randSpline) prevSpline = prevSplines->begin();
05034
05035
05036
05037
05038 for (int i=0; i<numIterations; i++)
05039 {
05040
05041 if (!randSpline)
05042 {
05043
05044 curSpline = *prevSpline;
05045
05046 randSpline = ++prevSpline == prevSplines->end();
05047 }
05048
05049 else
05050 {
05051
05052 cvSetZero(pointIn);
05053
05054
05055 mcvSampleWeighted(weights, numSamples, randInd, &rng);
05056
05057 for (int j=0; j<randInd->rows; j++)
05058 {
05059
05060 int p = CV_MAT_ELEM(*randInd, int, j, 0);
05061 CV_MAT_ELEM(*pointIn, char, 0, p) = 1;
05062
05063 CV_MAT_ELEM(*samplePoints, float, j, 0) =
05064 CV_MAT_ELEM(*points, float, 0, p);
05065 CV_MAT_ELEM(*samplePoints, float, j, 1) =
05066 CV_MAT_ELEM(*points, float, 1, p);
05067 }
05068
05069
05070 curSpline = mcvFitBezierSpline(samplePoints, splineDegree);
05071
05072 }
05073
05074
05075
05076
05077
05078
05079 float score = mcvGetSplineScore(image, curSpline, splineScoreStep,
05080 splineScoreJitter,
05081 splineScoreLengthRatio,
05082 splineScoreAngleRatio);
05083
05084
05085
05086
05087
05088 if (score>bestScore && score >= scoreThreshold)
05089 {
05090
05091 bestScore = score;
05092 bestSpline = curSpline;
05093 }
05094
05095
05096 if(0) {
05097
05098
05099 char str[256];
05100 sprintf(str, "Spline Fit: score=%f, best=%f", score, bestScore);
05101
05102
05103
05104
05105
05106 CvMat *imageClr = cvCreateMat(image->rows, image->cols,
05107 CV_32FC3);
05108 CvMat *im = cvCloneMat(image);
05109 mcvScaleMat(image, im);
05110 cvCvtColor(im, imageClr, CV_GRAY2RGB);
05111
05112
05113 for (unsigned int k=0; prevSplines && k<prevSplines->size(); ++k)
05114 mcvDrawSpline(imageClr, (*prevSplines)[k], CV_RGB(0,1,0), 1);
05115 if(curSpline.degree>0)
05116 mcvDrawSpline(imageClr, curSpline, CV_RGB(1,0,0), 1);
05117 if(bestSpline.degree>0)
05118 mcvDrawSpline(imageClr, bestSpline, CV_RGB(0,0,1), 1);
05119
05120
05121 CvFont font;
05122 cvInitFont(&font, CV_FONT_HERSHEY_TRIPLEX, .25f, .25f);
05123 sprintf(str, "score=%.2f bestScre=%.2f", score, bestScore);
05124 cvPutText(imageClr, str, cvPoint(30, 30), &font, CV_RGB(1,1,1));
05125
05126 sprintf(str, "Spline Fit");
05127 SHOW_IMAGE(imageClr, str, 10);
05128
05129 cvReleaseMat(&imageClr);
05130 cvReleaseMat(&im);
05131 }
05132 }
05133
05134
05135 if (spline)
05136 *spline = bestSpline;
05137 if (splineScore)
05138 *splineScore = bestScore;
05139
05140
05141
05142 cvReleaseMat(&points);
05143 cvReleaseMat(&samplePoints);
05144 cvReleaseMat(&randInd);
05145 cvReleaseMat(&pointIn);
05146 cvReleaseMat(&weights);
05147 }
05148
05156 void mcvDrawSpline(CvMat *image, Spline spline, CvScalar color, int width)
05157 {
05158
05159 CvMat *pixels = mcvGetBezierSplinePixels(spline, .05,
05160 cvSize(image->width, image->height),
05161 false);
05162
05163 if (!pixels)
05164 return;
05165
05166
05167 for (int i=0; i<pixels->height-1; i++)
05168
05169
05170
05171
05172 cvLine(image, cvPoint((int)cvGetReal2D(pixels, i, 0),
05173 (int)cvGetReal2D(pixels, i, 1)),
05174 cvPoint((int)cvGetReal2D(pixels, i+1, 0),
05175 (int)cvGetReal2D(pixels, i+1, 1)),
05176 color, width);
05177
05178
05179 for (int i=0; i<spline.degree+1; i++)
05180 cvCircle(image, cvPointFrom32f(spline.points[i]), 3, color, -1);
05181
05182
05183 cvReleaseMat(&pixels);
05184 }
05185
05186
05195 void mcvDrawRectangle (CvMat *image, CvRect rect, CvScalar color, int width)
05196 {
05197
05198 cvRectangle(image, cvPoint(rect.x, rect.y),
05199 cvPoint(rect.x + rect.width-1, rect.y + rect.height-1),
05200 color, width);
05201
05202 }
05203
05213 void mcvDrawText(CvMat *image, char* str, CvPoint point,
05214 float size, CvScalar color)
05215 {
05216
05217 CvFont font;
05218 cvInitFont(&font, CV_FONT_HERSHEY_TRIPLEX, size, size);
05219 cvPutText(image, str, point, &font, color);
05220
05221 }
05222
05232 void mcvLinesImIPM2Im(vector<Line> &lines, IPMInfo &ipmInfo,
05233 CameraInfo &cameraInfo, CvSize imSize)
05234 {
05235
05236 if (lines.size()!=0)
05237 {
05238
05239 for (unsigned int i=0; i<lines.size(); i++)
05240 {
05241 Line *line;
05242 line = & (lines[i]);
05243
05244 mcvPointImIPM2World(&(line->startPoint), &ipmInfo);
05245 mcvPointImIPM2World(&(line->endPoint), &ipmInfo);
05246 }
05247
05248
05249
05250
05251 Line dummy = {{1.,1.},{2.,2.}};
05252 lines.insert(lines.begin(), dummy);
05253
05254 CvMat *mat = cvCreateMat(2, 2*lines.size(), FLOAT_MAT_TYPE);
05255 mcvLines2Mat(&lines, mat);
05256 lines.clear();
05257 mcvTransformGround2Image(mat, mat, &cameraInfo);
05258
05259 mcvMat2Lines(mat, &lines);
05260
05261 lines.erase(lines.begin());
05262
05263 cvReleaseMat(&mat);
05264
05265
05266 for (unsigned int i=0; i<lines.size(); i++)
05267 {
05268
05269 mcvIntersectLineWithBB(&(lines[i]), imSize, &(lines[i]));
05270
05271
05272 }
05273 }
05274 }
05275
05276
05286 void mcvSplinesImIPM2Im(vector<Spline> &splines, IPMInfo &ipmInfo,
05287 CameraInfo &cameraInfo, CvSize imSize)
05288 {
05289
05290 for (int i=0; i<(int)splines.size(); i++)
05291 {
05292
05293 CvMat *points = mcvEvalBezierSpline(splines[i], .1);
05294
05295
05296 CvMat *points2 = cvCreateMat(2, points->height, CV_32FC1);
05297 cvTranspose(points, points2);
05298
05299
05300 mcvTransformImIPM2Im(points2, points2, &ipmInfo, &cameraInfo);
05301 cvTranspose(points2, points);
05302 cvReleaseMat(&points2);
05303
05304
05305 splines[i] = mcvFitBezierSpline(points, splines[i].degree);
05306 }
05307 }
05308
05309
05319 void mcvSampleWeighted(const CvMat *cumSum, int numSamples, CvMat *randInd,
05320 CvRNG *rng)
05321 {
05322
05323
05324
05325
05326
05327
05328
05329 int i=0;
05330 if (numSamples >= cumSum->cols)
05331 {
05332 for (; i<numSamples; i++)
05333 CV_MAT_ELEM(*randInd, int, i, 0) = i;
05334 }
05335 else
05336 {
05337
05338 while(i<numSamples)
05339 {
05340
05341 double r = cvRandReal(rng);
05342
05343
05344 int j;
05345 for (j=0; j<cumSum->cols && r>CV_MAT_ELEM(*cumSum, float, 0, j); j++);
05346
05347
05348 bool put = true;
05349 for (int k=0; k<i; k++)
05350 if (CV_MAT_ELEM(*randInd, int, k, 0) == j)
05351
05352 put = false;
05353
05354 if (put)
05355 {
05356
05357 CV_MAT_ELEM(*randInd, int, i, 0) = j;
05358
05359 i++;
05360 }
05361 }
05362 }
05363 }
05364
05371 void mcvCumSum(const CvMat *inMat, CvMat *outMat)
05372 {
05373
05374 #define MCV_CUM_SUM(type) \
05375 \
05376 if(inMat->rows == 1) \
05377 for (int i=1; i<outMat->cols; i++) \
05378 CV_MAT_ELEM(*outMat, type, 0, i) += \
05379 CV_MAT_ELEM(*outMat, type, 0, i-1); \
05380 \
05381 else \
05382 for (int i=1; i<outMat->rows; i++) \
05383 CV_MAT_ELEM(*outMat, type, i, 0) += \
05384 CV_MAT_ELEM(*outMat, type, i-1, 0);
05385
05386
05387 if(inMat != outMat)
05388 cvCopy(inMat, outMat);
05389
05390
05391 if (CV_MAT_TYPE(inMat->type)==CV_32FC1)
05392 {
05393 MCV_CUM_SUM(float)
05394 }
05395 else if (CV_MAT_TYPE(inMat->type)==CV_32SC1)
05396 {
05397 MCV_CUM_SUM(int)
05398 }
05399 else
05400 {
05401 cerr << "Unsupported type in mcvCumSum\n";
05402 exit(1);
05403 }
05404 }
05405
05406
05418 void mcvLocalizePoints(const CvMat *im, const CvMat *inPoints,
05419 CvMat *outPoints, int numLinePixels,
05420 float angleThreshold)
05421 {
05422
05423 if(inPoints->height<3)
05424 {
05425 cvCopy(inPoints, outPoints);
05426 return;
05427 }
05428
05429
05430
05431
05432 CvPoint2D32f tangent, normal;
05433
05434
05435
05436 CvMat *imageClr;
05437 char str[256];
05438 if(DEBUG_LINES) {
05439
05440 sprintf(str, "Localize Points");
05441
05442
05443 imageClr = cvCreateMat(im->rows, im->cols, CV_32FC3);
05444 cvCvtColor(im, imageClr, CV_GRAY2RGB);
05445 }
05446
05447
05448
05449 for (int i=0; i<inPoints->height; i++)
05450 {
05451
05452
05453 if (i==0)
05454 {
05455
05456 tangent = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float, 1, 0) -
05457 CV_MAT_ELEM(*inPoints, float, 0, 0),
05458 CV_MAT_ELEM(*inPoints, float, 1, 1) -
05459 CV_MAT_ELEM(*inPoints, float, 0, 1));
05460 }
05461 else if (i==1)
05462 tangent = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float, 1, 0) -
05463 CV_MAT_ELEM(*outPoints, float, 0, 0),
05464 CV_MAT_ELEM(*inPoints, float, 1, 1) -
05465 CV_MAT_ELEM(*outPoints, float, 0, 1));
05466
05467 else
05468 {
05469
05470 tangent = cvPoint2D32f(CV_MAT_ELEM(*outPoints, float, i-1, 0) -
05471 CV_MAT_ELEM(*outPoints, float, i-2, 0),
05472 CV_MAT_ELEM(*outPoints, float, i-1, 1) -
05473 CV_MAT_ELEM(*outPoints, float, i-2, 1));
05474
05475
05476
05477
05478 }
05479
05480
05481
05482
05483
05484
05485
05486
05487
05488
05489 float ss = cvInvSqrt(tangent.x * tangent.x + tangent.y * tangent.y);
05490 tangent.x *= ss; tangent.y *= ss;
05491 normal.x = tangent.y; normal.y = -tangent.x;
05492
05493
05494 Line line;
05495 line.startPoint = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float, i, 0) +
05496 numLinePixels * normal.x,
05497 CV_MAT_ELEM(*inPoints, float, i, 1) +
05498 numLinePixels * normal.y);
05499 line.endPoint = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float, i, 0) -
05500 numLinePixels * normal.x,
05501 CV_MAT_ELEM(*inPoints, float, i, 1) -
05502 numLinePixels * normal.y);
05503
05504
05505 CvPoint2D32f prevPoint = {0., 0.};
05506 if (i>0)
05507 prevPoint = cvPoint2D32f(CV_MAT_ELEM(*outPoints, float, i-1, 0),
05508 CV_MAT_ELEM(*outPoints, float, i-1, 1));
05509
05510
05511 CvPoint2D32f peak;
05512
05513
05514 vector<CvPoint2D32f> peaks;
05515 vector<float> peakVals;
05516 float val = mcvGetLinePeak(im, line, peaks, peakVals);
05517
05518
05519
05520
05521
05522 peak = peaks.front();
05523 val = peakVals.front();
05524
05525 peaks.clear();
05526 peakVals.clear();
05527
05528
05529 if (mcvIsPointInside(line.startPoint, cvSize(im->width, im->height)) &&
05530 mcvIsPointInside(line.endPoint, cvSize(im->width, im->height)) &&
05531 (
05532 (i>0 &&
05533 mcvIsValidPeak(peak, tangent, prevPoint,
05534 angleThreshold))) )
05535 {
05536
05537 CV_MAT_ELEM(*outPoints, float, i, 0) = peak.x;
05538 CV_MAT_ELEM(*outPoints, float, i, 1) = peak.y;
05539 }
05540 else
05541 {
05542
05543 CV_MAT_ELEM(*outPoints, float, i, 0) = CV_MAT_ELEM(*inPoints, float, i, 0);
05544 CV_MAT_ELEM(*outPoints, float, i, 1) = CV_MAT_ELEM(*inPoints, float, i, 1);
05545 }
05546
05547
05548 if(DEBUG_LINES) {
05549
05550 fprintf(stderr, "Localize val=%.3f\n", val);
05551
05552
05553 cvLine(imageClr, cvPointFrom32f(line.startPoint),
05554 cvPointFrom32f(line.endPoint), CV_RGB(0, 0, 1));
05555
05556 cvCircle(imageClr, cvPoint((int)CV_MAT_ELEM(*outPoints, float, i, 0),
05557 (int)CV_MAT_ELEM(*outPoints, float, i, 1)),
05558 1, CV_RGB(0, 1, 0), -1);
05559
05560 cvCircle(imageClr, cvPoint((int)(line.startPoint.x+line.endPoint.x)/2,
05561 (int)(line.startPoint.y+line.endPoint.y)/2),
05562 1, CV_RGB(1, 0, 0), -1);
05563
05564 SHOW_IMAGE(imageClr, str, 10);
05565 }
05566 }
05567
05568 if(DEBUG_LINES) {
05569 SHOW_IMAGE(imageClr, str, 10);
05570
05571 cvReleaseMat(&imageClr);
05572 }
05573 }
05574
05575
05586 bool mcvIsValidPeak(const CvPoint2D32f &peak, const CvPoint2D32f &tangent,
05587 const CvPoint2D32f &prevPoint, float angleThreshold)
05588 {
05589
05590 CvPoint2D32f peakTangent;
05591 peakTangent.x = peak.x - prevPoint.x;
05592 peakTangent.y = peak.y - prevPoint.y;
05593
05594
05595 float ss = cvInvSqrt(peakTangent.x * peakTangent.x + peakTangent.y *
05596 peakTangent.y);
05597 peakTangent.x *= ss; peakTangent.y *= ss;
05598
05599
05600 float angle = fabs(peakTangent.x*tangent.x + peakTangent.y*tangent.y);
05601 if (DEBUG_LINES)
05602 fprintf(stderr, "angle=%f\n", angle);
05603
05604 return (angle >= angleThreshold) ? true : false;
05605
05606 }
05607
05608
05624 int mcvChooseBestPeak(const vector<CvPoint2D32f> &peaks,
05625 const vector<float> &peakVals,
05626 CvPoint2D32f &peak, float &peakVal,
05627 float contThreshold, const CvPoint2D32f &tangent,
05628 const CvPoint2D32f &prevPoint, float angleThreshold)
05629 {
05630 int index=-1;
05631 float maxAngle=0;
05632 peakVal = -1;
05633
05634
05635 for (unsigned int i=0; i<peaks.size(); ++i)
05636 {
05637 CvPoint2D32f peak = peaks[i];
05638
05639
05640 CvPoint2D32f peakTangent;
05641 peakTangent.x = peak.x - prevPoint.x;
05642 peakTangent.y = peak.y - prevPoint.y;
05643 peakTangent = mcvNormalizeVector(peakTangent);
05644
05645
05646 float angle = fabs(peakTangent.x*tangent.x + peakTangent.y*tangent.y);
05647
05648
05649 if (DEBUG_LINES)
05650 fprintf(stderr, "peak#%d/%d (%f, %f): angle=%f, maxAngle=%f\n",
05651 i, peaks.size(), peaks[i].x, peaks[i].y,
05652 angle, maxAngle);
05653 if (peakVals[i]>=contThreshold && angle>=angleThreshold &&
05654 angle>maxAngle)
05655 {
05656
05657 maxAngle = angle;
05658 index = i;
05659 }
05660 }
05661
05662
05663 if (index>=0)
05664 {
05665 peak = peaks[index];
05666 peakVal = peakVals[index];
05667 }
05668
05669 if (DEBUG_LINES)
05670 fprintf(stderr, "Chosen peak is: (%f, %f)\n", peak.x, peak.y);
05671
05672 return index;
05673 }
05674
05675
05692 CvMat* mcvExtendPoints(const CvMat *im, const CvMat *inPoints,
05693 float angleThreshold, float meanDirAngleThreshold,
05694 int linePixelsTangent, int linePixelsNormal,
05695 float contThreshold, int deviationThreshold,
05696 CvRect bbox, bool smoothPeaks)
05697 {
05698
05699 if(inPoints->height<4)
05700 {
05701 return cvCloneMat(inPoints);
05702 }
05703
05704
05705 char str[256];
05706 CvMat *imageClr;
05707 if(DEBUG_LINES) {
05708
05709 sprintf(str, "Extend Points");
05710
05711
05712 imageClr = cvCreateMat(im->rows, im->cols, CV_32FC3);
05713 CvMat *im2 = cvCloneMat(im);
05714 mcvScaleMat(im, im2);
05715 cvCvtColor(im2, imageClr, CV_GRAY2RGB);
05716 cvReleaseMat(&im2);
05717
05718
05719 for(int i=0; i<inPoints->height; i++)
05720
05721 cvCircle(imageClr, cvPoint((int)(CV_MAT_ELEM(*inPoints, float, i, 0)),
05722 (int)(CV_MAT_ELEM(*inPoints, float, i, 1))),
05723 1, CV_RGB(0, 1, 1), -1);
05724
05725 SHOW_IMAGE(imageClr, str, 10);
05726 }
05727
05728
05729 CvPoint2D32f tangent, curPoint, peak, nextPoint, meanDir;
05730
05731
05732
05733
05734 bool cont = true;
05735
05736
05737
05738
05739
05740
05741
05742
05743
05744
05745
05746
05747 vector<CvPoint2D32f> backPoints;
05748 int numBack = 0;
05749 int deviationCount = 0;
05750 vector<CvPoint2D32f> peaks;
05751 vector<float> peakVals;
05752
05753 meanDir = mcvGetPointsMeanVector(inPoints, false);
05754 while(cont)
05755 {
05756 int outSize = (int)backPoints.size();
05757
05758 if(outSize==0)
05759 {
05760 curPoint = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float, 0, 0),
05761 CV_MAT_ELEM(*inPoints, float, 0, 1));
05762 tangent = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float, 0, 0) -
05763 CV_MAT_ELEM(*inPoints, float, 1, 0),
05764 CV_MAT_ELEM(*inPoints, float, 0, 1) -
05765 CV_MAT_ELEM(*inPoints, float, 1, 1));
05766
05767
05768
05769
05770
05771
05772
05773
05774
05775
05776
05777 }
05778
05779 else
05780 {
05781
05782
05783 curPoint = backPoints[outSize-1];
05784 if (outSize==1)
05785 {
05786 tangent = cvPoint2D32f(backPoints[outSize-1].x -
05787 CV_MAT_ELEM(*inPoints, float, 0, 0),
05788 backPoints[outSize-1].y -
05789 CV_MAT_ELEM(*inPoints, float, 0, 1));
05790 }
05791
05792 else
05793 {
05794 tangent = cvPoint2D32f(backPoints[outSize-1].x -
05795 backPoints[outSize-2].x,
05796 backPoints[outSize-1].y -
05797 backPoints[outSize-2].y);
05798 }
05799 }
05800
05801
05802 Line line;
05803 line = mcvGetExtendedNormalLine(curPoint, tangent, linePixelsTangent,
05804 linePixelsNormal, nextPoint);
05805
05806
05807
05808 if (mcvIsPointInside(nextPoint, bbox))
05809 {
05810
05811 mcvIntersectLineWithBB(&line, cvSize(im->width-1, im->height-1), &line);
05812
05813
05814 float val = mcvGetLinePeak(im, line, peaks, peakVals,
05815 true, smoothPeaks);
05816
05817
05818
05819 mcvChooseBestPeak(peaks, peakVals, peak, val, contThreshold, tangent,
05820 curPoint, 0);
05821
05822 peaks.clear();
05823 peakVals.clear();
05824
05825
05826
05827
05828 if (!mcvIsValidPeak(peak, tangent, curPoint, angleThreshold) ||
05829 !mcvIsValidPeak(peak, meanDir, curPoint, meanDirAngleThreshold))
05830 {
05831 peak = nextPoint;
05832 deviationCount++;
05833 }
05834 else
05835 deviationCount = 0;
05836
05837 if (DEBUG_LINES){
05838 fprintf(stderr, "Extension back #%d val=%.3f\n", outSize, val);
05839 fprintf(stderr, "Deviation Count=%d\n", deviationCount);
05840 }
05841
05842
05843
05844 if(val<contThreshold || deviationCount>deviationThreshold)
05845 {
05846 cont = false;
05847
05848
05849 if (deviationCount)
05850 backPoints.erase(backPoints.end() - (deviationCount-1),
05851 backPoints.end());
05852 }
05853
05854
05855
05856
05857
05858
05859
05860
05861
05862
05863 else
05864 {
05865
05866 backPoints.push_back(peak);
05867
05868 }
05869 }
05870
05871 else
05872 cont = false;
05873
05874 if(DEBUG_LINES) {
05875
05876 cvLine(imageClr, cvPointFrom32f(line.startPoint),
05877 cvPointFrom32f(line.endPoint),
05878 CV_RGB(0, 0, 1));
05879
05880 cvCircle(imageClr, cvPointFrom32f(peak), 1, CV_RGB(0, 1, 0), -1);
05881
05882 cvCircle(imageClr, cvPointFrom32f(nextPoint), 1, CV_RGB(1, 0, 0), -1);
05883
05884 SHOW_IMAGE(imageClr, str, 10);
05885 }
05886 }
05887
05888
05889 cont = true;
05890 vector<CvPoint2D32f> frontPoints;
05891 int numFront = 0;
05892 deviationCount = 0;
05893
05894 meanDir = mcvGetPointsMeanVector(inPoints, true);
05895 while(cont)
05896 {
05897 int outSize = (int)frontPoints.size();
05898
05899 if(outSize==0)
05900 {
05901 curPoint = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float,
05902 inPoints->height-1, 0),
05903 CV_MAT_ELEM(*inPoints, float,
05904 inPoints->height-1, 1));
05905 tangent = cvPoint2D32f(CV_MAT_ELEM(*inPoints, float,
05906 inPoints->height-1, 0) -
05907 CV_MAT_ELEM(*inPoints, float,
05908 inPoints->height-2, 0),
05909 CV_MAT_ELEM(*inPoints, float,
05910 inPoints->height-1, 1) -
05911 CV_MAT_ELEM(*inPoints, float,
05912 inPoints->height-2, 1));
05913
05914
05915
05916
05917
05918
05919
05920
05921
05922
05923
05924
05925 }
05926
05927 else
05928 {
05929
05930
05931 curPoint = frontPoints[outSize-1];
05932 if (outSize==1)
05933 {
05934 tangent = cvPoint2D32f(frontPoints[outSize-1].x -
05935 CV_MAT_ELEM(*inPoints, float,
05936 inPoints->height-1, 0),
05937 frontPoints[outSize-1].y -
05938 CV_MAT_ELEM(*inPoints, float,
05939 inPoints->height-1, 1));
05940 }
05941
05942 else
05943 {
05944 tangent = cvPoint2D32f(frontPoints[outSize-1].x -
05945 frontPoints[outSize-2].x,
05946 frontPoints[outSize-1].y -
05947 frontPoints[outSize-2].y);
05948 }
05949 }
05950
05951 Line line;
05952 line = mcvGetExtendedNormalLine(curPoint, tangent, linePixelsTangent,
05953 linePixelsNormal, nextPoint);
05954
05955
05956
05957 if (mcvIsPointInside(nextPoint, bbox))
05958 {
05959
05960 mcvIntersectLineWithBB(&line, cvSize(im->width-1, im->height-1), &line);
05961
05962
05963
05964 float val = mcvGetLinePeak(im, line, peaks, peakVals, true, smoothPeaks);
05965
05966
05967
05968 mcvChooseBestPeak(peaks, peakVals, peak, val, contThreshold, tangent,
05969 curPoint, 0);
05970
05971
05972 peaks.clear();
05973 peakVals.clear();
05974
05975
05976
05977
05978 if(!mcvIsValidPeak(peak, tangent, curPoint, angleThreshold) ||
05979 !mcvIsValidPeak(peak, meanDir, curPoint, meanDirAngleThreshold))
05980 {
05981
05982 peak = nextPoint;
05983
05984 deviationCount++;
05985 }
05986 else
05987 deviationCount = 0;
05988
05989 if (DEBUG_LINES){
05990 fprintf(stderr, "Extension front #%d val=%.3f\n", outSize, val);
05991 fprintf(stderr, "Deviation Count=%d\n", deviationCount);
05992 }
05993
05994
05995 if(val<contThreshold || deviationCount>deviationThreshold)
05996 {
05997 cont = false;
05998
05999
06000 if (deviationCount)
06001 frontPoints.erase(frontPoints.end() - (deviationCount-1),
06002 frontPoints.end());
06003
06004 }
06005
06006
06007
06008
06009
06010
06011
06012 else
06013 {
06014
06015 frontPoints.push_back(peak);
06016
06017 }
06018 }
06019
06020 else
06021 cont = false;
06022
06023 if(DEBUG_LINES) {
06024
06025 cvLine(imageClr, cvPointFrom32f(line.startPoint),
06026 cvPointFrom32f(line.endPoint), CV_RGB(0, 0, 1));
06027
06028 cvCircle(imageClr, cvPointFrom32f(peak), 1, CV_RGB(0, 1, 0), -1);
06029
06030 cvCircle(imageClr, cvPointFrom32f(nextPoint), 1, CV_RGB(1, 0, 0), -1);
06031
06032 SHOW_IMAGE(imageClr, str, 10);
06033 }
06034 }
06035
06036 numFront = frontPoints.size();
06037 numBack = backPoints.size();
06038
06039
06040 CvMat *extendedPoints = cvCreateMat(inPoints->height + numBack + numFront,
06041 2, CV_32FC1);
06042
06043 vector<CvPoint2D32f>::iterator pointi;
06044 int i = 0;
06045 for (i=0, pointi=backPoints.end()-1; i<numBack; i++, pointi--)
06046 {
06047 CV_MAT_ELEM(*extendedPoints, float, i, 0) = (*pointi).x;
06048 CV_MAT_ELEM(*extendedPoints, float, i, 1) = (*pointi).y;
06049 }
06050
06051
06052 i = numBack;
06053 memcpy(cvPtr2D(extendedPoints, i, 0), inPoints->data.fl,
06054 sizeof(float)*2*inPoints->height);
06055
06056
06057 for (i = numBack+inPoints->height, pointi=frontPoints.begin();
06058 i<extendedPoints->height; pointi++, i++)
06059 {
06060 CV_MAT_ELEM(*extendedPoints, float, i, 0) = (*pointi).x;
06061 CV_MAT_ELEM(*extendedPoints, float, i, 1) = (*pointi).y;
06062 }
06063
06064 if(DEBUG_LINES) {
06065 SHOW_IMAGE(imageClr, str, 10);
06066
06067 cvReleaseMat(&imageClr);
06068 }
06069
06070
06071 backPoints.clear();
06072 frontPoints.clear();
06073
06074 return extendedPoints;
06075 }
06076
06077
06078
06089 Line mcvGetExtendedNormalLine(CvPoint2D32f &curPoint, CvPoint2D32f &tangent,
06090 int linePixelsTangent, int linePixelsNormal,
06091 CvPoint2D32f &nextPoint)
06092 {
06093
06094 float ssq = cvInvSqrt(tangent.x*tangent.x + tangent.y*tangent.y);
06095 tangent.x *= ssq;
06096 tangent.y *= ssq;
06097
06098
06099 nextPoint.x = curPoint.x + linePixelsTangent * tangent.x;
06100 nextPoint.y = curPoint.y + linePixelsTangent * tangent.y;
06101
06102
06103 CvPoint2D32f normal = cvPoint2D32f(-tangent.y, tangent.x);
06104
06105
06106 Line line;
06107 line.startPoint = cvPoint2D32f(nextPoint.x + linePixelsNormal*normal.x,
06108 nextPoint.y + linePixelsNormal*normal.y);
06109 line.endPoint = cvPoint2D32f(nextPoint.x - linePixelsNormal*normal.x,
06110 nextPoint.y - linePixelsNormal*normal.y);
06111
06112
06113 return line;
06114 }
06115
06116
06117
06132 float mcvGetLinePeak(const CvMat *im, const Line &line,
06133 vector<CvPoint2D32f> &peaks,
06134 vector<float> &peakVals, bool positivePeak,
06135 bool smoothPeaks)
06136 {
06137
06138 FLOAT_MAT_ELEM_TYPE stepp[] =
06139
06140
06141
06142 { 0.000003726653172, 0.000040065297393, 0.000335462627903,
06143 0.002187491118183, 0.011108996538242, 0.043936933623407,
06144 0.135335283236613, 0.324652467358350, 0.606530659712633,
06145 0.882496902584595, 1.000000000000000, 0.882496902584595,
06146 0.606530659712633, 0.324652467358350, 0.135335283236613,
06147 0.043936933623407, 0.011108996538242, 0.002187491118183,
06148 0.000335462627903, 0.000040065297393, 0.000003726653172};
06149 int stepsize = 21;
06150 CvMat step = cvMat(1, stepsize, CV_32FC1, stepp);
06151
06152
06153 if (!positivePeak)
06154 cvScale(&step, &step, -1);
06155
06156
06157
06158
06159
06160
06161
06162
06163
06164
06165
06166 CvMat *pixels;
06167 pixels = mcvGetLinePixels(line);
06168
06169 CvMat *pix = cvCreateMat(1, pixels->height, CV_32FC1);
06170 for(int j=0; j<pixels->height; j++)
06171 {
06172 CV_MAT_ELEM(*pix, float, 0, j) =
06173 cvGetReal2D(im,
06174 MIN(MAX(CV_MAT_ELEM(*pixels, int, j, 1),0),im->height-1),
06175 MIN(MAX(CV_MAT_ELEM(*pixels, int, j, 0),0),im->width-1));
06176 }
06177
06178 cvReleaseMat(&pixels);
06179
06180
06181 CvScalar mean = cvAvg(pix);
06182 cvSubS(pix, mean, pix);
06183
06184
06185 CvMat *pixStep = cvCreateMat(pix->height, pix->width, CV_32FC1);
06186 if (smoothPeaks)
06187 cvFilter2D(pix, pixStep, &step);
06188 else
06189 cvCopy(pix, pixStep);
06190
06191
06192
06193
06194 double topVal;
06195 float top;
06196 vector<double> maxima;
06197 vector<int> maximaLoc;
06198 CvPoint2D32f peak;
06199
06200 mcvGetVectorLocalMax(pixStep, maxima, maximaLoc);
06201 if(maximaLoc.size()>0)
06202 {
06203
06204 topVal = maxima.front();
06205
06206 for (unsigned int i=0; i<maximaLoc.size(); ++i)
06207 {
06208
06209 double val1 = CV_MAT_ELEM(*pixStep, float, 0, MAX(maximaLoc[i]-1, 0));
06210 double val3 = CV_MAT_ELEM(*pixStep, float, 0, MIN(maximaLoc[i]+1,
06211 pixStep->width-1));
06212 top = (float)mcvGetLocalMaxSubPixel(val1, maxima[i], val3);
06213 top += maximaLoc[i];
06214
06215
06216 top /= pix->width;
06217
06218
06219
06220 peak.x = line.startPoint.x*(1-top) + top * line.endPoint.x;
06221 peak.y = line.startPoint.y*(1-top) + top * line.endPoint.y;
06222
06223 peaks.push_back(peak);
06224 peakVals.push_back(maxima[i]);
06225 }
06226 }
06227 else
06228 {
06229 top = (pix->width-2)/2./(pix->width);
06230 topVal = -1;
06231
06232 peak.x = line.startPoint.x*(1-top) + top * line.endPoint.x;
06233 peak.y = line.startPoint.y*(1-top) + top * line.endPoint.y;
06234
06235 peaks.push_back(peak);
06236 peakVals.push_back(topVal);
06237
06238 }
06239 maxima.clear();
06240 maximaLoc.clear();
06241
06242
06243
06244
06245
06246
06247
06248 cvReleaseMat(&pix);
06249 cvReleaseMat(&pixStep);
06250
06251
06252 return topVal;
06253 }
06254
06259 CvPoint2D32f mcvNormalizeVector(const CvPoint2D32f &v)
06260 {
06261
06262 CvPoint2D32f ret = v;
06263
06264
06265 float ssq = cvInvSqrt(ret.x*ret.x + ret.y*ret.y);
06266 ret.x *= ssq;
06267 ret.y *= ssq;
06268
06269
06270 return ret;
06271 }
06272
06273
06278 CvPoint2D32f mcvNormalizeVector(const CvPoint &v)
06279 {
06280
06281 return mcvNormalizeVector(cvPointTo32f(v));
06282
06283 }
06284
06290 CvPoint2D32f mcvNormalizeVector(float x, float y)
06291 {
06292
06293 return mcvNormalizeVector(cvPoint2D32f(x, y));
06294 }
06295
06296
06303 CvPoint2D32f mcvAddVector(CvPoint2D32f v1, CvPoint2D32f v2)
06304 {
06305
06306 CvPoint2D32f sum = cvPoint2D32f(v1.x + v2.x, v1.y + v2.y);
06307
06308 return sum;
06309 }
06310
06311
06318 CvPoint2D32f mcvMultiplyVector(CvPoint2D32f v, float s)
06319 {
06320
06321 CvPoint2D32f prod;
06322 prod.x = v.x * s;
06323 prod.y = v.y * s;
06324
06325 return prod;
06326 }
06327
06341 float mcvGetSplineScore(const CvMat* image, Spline& spline, float h,
06342 int jitterVal, float lengthRatio, float angleRatio)
06343 {
06344
06345
06346 CvSize size = cvSize(image->width-1, image->height-1);
06347
06348 for (int i=0; i<=spline.degree; i++)
06349 if (!mcvIsPointInside(spline.points[i], size))
06350 return -100.f;
06351
06352
06353 CvMat *pixels = mcvGetBezierSplinePixels(spline, h, size, false);
06354 if(!pixels)
06355 return -100.f;
06356
06357
06358 vector<int>jitter = mcvGetJitterVector(jitterVal);
06359
06360
06361
06362
06363 float score = 0.f;
06364 for (unsigned int j=0; j<jitter.size(); j++)
06365 for (int i=0; i<pixels->height; i++)
06366 {
06367
06368
06369
06370
06371 score += cvGetReal2D(image, CV_MAT_ELEM(*pixels, int, i, 1),
06372 MIN(MAX(CV_MAT_ELEM(*pixels, int, i, 0) +
06373 jitter[j], 0), image->width-1));
06374
06375
06376
06377
06378
06379 }
06380
06381
06382
06383
06384 float length = 0.f;
06385
06386
06387
06388
06389
06390
06391
06392
06393
06394
06395
06396
06397 CvPoint2D32f v = mcvSubtractVector(spline.points[0], spline.points[spline.degree]);
06398 length = cvSqrt(v.x * v.x + v.y * v.y);
06399
06400 length /= image->height;
06401
06402
06403
06404
06405 float angle = 0;
06406 for (int i=0; i<spline.degree-1; i++)
06407 {
06408
06409 CvPoint2D32f t1 = mcvNormalizeVector (mcvSubtractVector(spline.points[i+1],
06410 spline.points[i]));
06411
06412
06413 CvPoint2D32f t2 = mcvNormalizeVector (mcvSubtractVector(spline.points[i+2],
06414 spline.points[i+1]));
06415
06416 angle += t1.x*t2.x + t1.y*t2.y;
06417 }
06418
06419 angle /= (spline.degree-1);
06420
06421 angle += 1;
06422 angle /= 2;
06423
06424
06425
06426
06427
06428
06429
06430
06431 angle -= 1;
06432 length -= 1;
06433
06434
06435
06436
06437
06438
06439
06440
06441 if (DEBUG_LINES)
06442 fprintf(stderr, "raw score=%.2f, angle=%.2f, length=%.2f, final=%.2f\n",
06443 score, angle, length, score *
06444 (1 + (angleRatio*angle + lengthRatio*length)/2));
06445 score = score * (1 + (angleRatio*angle + lengthRatio*length)/2);
06446
06447
06448
06449 cvReleaseMat(&pixels);
06450 jitter.clear();
06451
06452
06453 return score;
06454 }
06455
06456
06457
06466 vector<int> mcvGetJitterVector(int maxJitter)
06467 {
06468 vector<int> jitter(2*maxJitter+1);
06469
06470
06471 jitter.push_back(0);
06472 for(int i=1; i<=maxJitter; ++i)
06473 {
06474 jitter.push_back(i);
06475 jitter.push_back(-i);
06476 }
06477
06478
06479 return jitter;
06480 }
06481
06482
06491 CvPoint2D32f mcvGetPointsMeanVector(const CvMat *points, bool forward)
06492 {
06493 CvPoint2D32f mean, v;
06494
06495
06496 mean = cvPoint2D32f(0,0);
06497
06498
06499 for (int i=1; i<points->height; ++i)
06500 {
06501
06502 v = cvPoint2D32f(CV_MAT_ELEM(*points, float, i, 0) -
06503 CV_MAT_ELEM(*points, float, i-1, 0),
06504 CV_MAT_ELEM(*points, float, i, 1) -
06505 CV_MAT_ELEM(*points, float, i-1, 1));
06506
06507 v = mcvNormalizeVector(v);
06508
06509 mean.x = (mean.x * (i-1) + v.x) / i;
06510 mean.y = (mean.y * (i-1) + v.y) / i;
06511
06512 mean = mcvNormalizeVector(mean);
06513 }
06514
06515
06516 if (!forward)
06517 mean = cvPoint2D32f(-mean.x, -mean.y);
06518
06519 return mean;
06520 }
06521
06522
06538 bool mcvCheckMergeSplines(const Spline& sp1, const Spline& sp2,
06539 float thetaThreshold, float rThreshold,
06540 float meanThetaThreshold, float meanRThreshold,
06541 float centroidThreshold)
06542 {
06543
06544 CvPoint2D32f centroid1, centroid2;
06545 float theta1, theta2, length1, length2, r1, r2;
06546 float meanTheta1, meanTheta2, meanR1, meanR2;
06547 mcvGetSplineFeatures(sp1, ¢roid1, &theta1, &r1,
06548 &length1, &meanTheta1, &meanR1);
06549 mcvGetSplineFeatures(sp2, ¢roid2, &theta2, &r2,
06550 &length2, &meanTheta2, &meanR2);
06551
06552
06553
06554
06555
06556
06557
06558 float meanThetaDist = fabs(meanTheta1 - meanTheta2);
06559 float meanRDist = fabs(meanR1 - meanR2);
06560 float thetaDist = fabs(theta1 - theta2);
06561 float rDist = fabs(r1 - r2);
06562 float centroidDist = fabs(mcvGetVectorNorm(mcvSubtractVector(centroid1, centroid2)));
06563
06564
06565
06566
06567
06568
06569 bool meanThetaOk = meanThetaDist <= meanThetaThreshold;
06570 bool meanROk = meanRDist <= meanRThreshold;
06571 bool thetaOk = thetaDist <= thetaThreshold;
06572 bool rOk = rDist <= rThreshold;
06573 bool centroidOk = centroidDist <= centroidThreshold;
06574
06575 bool centroidNotOk = centroidDist >= 200;
06576 bool rNotOk = rDist >= 100;
06577 bool thetaNotOk = thetaDist >= .8;
06578
06579 bool merge = false;
06580
06581 if ((thetaOk || meanThetaOk) && (rOk || meanROk || centroidOk) &&
06582 !rNotOk && !centroidNotOk && !thetaNotOk)
06583 merge = true;
06584
06585
06586
06587 if(DEBUG_LINES) {
06588
06589
06590
06591
06592 fprintf(stderr, "%s: thetaDist=%.2f, meanThetaDist=%.2f, "
06593 "rDist=%.2f, meanRDist=%.2f, centroidDist=%.2f\n",
06594 merge? "Merged " : "Not merged",
06595 thetaDist, meanThetaDist, rDist, meanRDist, centroidDist);
06596
06597 fprintf(stderr, "\ttheta1=%.2f, theta2=%.2f\n", theta1, theta2);
06598
06599 CvMat* im = cvCreateMat(480, 640, CV_8UC3);
06600 cvSet(im, cvRealScalar(0.));
06601
06602 mcvDrawSpline(im, sp1, CV_RGB(255, 0, 0), 1);
06603 mcvDrawSpline(im, sp2, CV_RGB(0, 255, 0), 1);
06604 SHOW_IMAGE(im, "Check Merge Splines", 10);
06605
06606 cvReleaseMat(&im);
06607
06608 }
06609
06610
06611 return merge;
06612 }
06613
06631 void mcvGetPointsFeatures(const CvMat* points, CvPoint2D32f* centroid,
06632 float* theta, float* r, float* length,
06633 float* meanTheta, float* meanR, float* curveness)
06634 {
06635
06636
06637 CvPoint2D32f start = cvPoint2D32f(CV_MAT_ELEM(*points, float, 0, 0),
06638 CV_MAT_ELEM(*points, float, 0, 1));
06639 CvPoint2D32f end = cvPoint2D32f(CV_MAT_ELEM(*points, float,
06640 points->height-1, 0),
06641 CV_MAT_ELEM(*points, float,
06642 points->height-1, 1));
06643
06644 if (centroid)
06645 {
06646
06647 *centroid = cvPoint2D32f(0, 0);
06648 for (int i=0; i<=points->height; ++i)
06649 *centroid = mcvAddVector(*centroid,
06650 cvPoint2D32f(CV_MAT_ELEM(*points, float, i, 0),
06651 CV_MAT_ELEM(*points, float, i, 1)));
06652
06653 *centroid = cvPoint2D32f(centroid->x / (points->height),
06654 centroid->y / (points->height));
06655 }
06656
06657
06658 if (theta && r)
06659 {
06660
06661 Line line;
06662 line.startPoint = start;
06663 line.endPoint = end;
06664
06665
06666 mcvLineXY2RTheta(line, *r, *theta);
06667
06668 if (*theta<0)
06669 *theta += CV_PI;
06670 }
06671
06672
06673 if (meanTheta && meanR)
06674 {
06675 *meanTheta = 0;
06676 *meanR = 0;
06677
06678
06679 for (int i=0; i<points->height-1; i++)
06680 {
06681
06682 Line line;
06683 line.startPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, i, 0),
06684 CV_MAT_ELEM(*points, float, i, 1));
06685 line.endPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, i+1, 0),
06686 CV_MAT_ELEM(*points, float, i+1, 1));
06687
06688 float r, t;
06689 mcvLineXY2RTheta(line, r, t);
06690
06691 if (t<0) t += CV_PI;
06692
06693 *meanTheta += t;
06694 *meanR += r;
06695 }
06696
06697
06698 *meanTheta /= points->height - 1;
06699 *meanR /= points->height - 1;
06700 }
06701
06702
06703 if (length)
06704 {
06705
06706 CvPoint2D32f v = mcvSubtractVector(start, end);
06707
06708
06709 *length = cvSqrt(v.x * v.x + v.y * v.y);
06710 }
06711
06712
06713 if (curveness)
06714 {
06715 *curveness = 0;
06716 if (points->height>2)
06717 {
06718
06719 CvPoint2D32f p0;
06720 CvPoint2D32f p1 = start;
06721 CvPoint2D32f p2 = cvPoint2D32f(CV_MAT_ELEM(*points, float, 1, 0),
06722 CV_MAT_ELEM(*points, float, 1, 1));
06723
06724 for (int i=0; i<points->height-2; i++)
06725 {
06726
06727 p0 = p1;
06728 p1 = p2;
06729 p2 = cvPoint2D32f(CV_MAT_ELEM(*points, float, i+2, 0),
06730 CV_MAT_ELEM(*points, float, i+2, 1));
06731
06732 CvPoint2D32f t1 = mcvNormalizeVector(mcvSubtractVector(p1, p0));
06733
06734
06735 CvPoint2D32f t2 = mcvNormalizeVector (mcvSubtractVector(p2, p1));
06736
06737 *curveness += t1.x*t2.x + t1.y*t2.y;
06738 }
06739
06740 *curveness /= points->height-2;
06741 }
06742 }
06743 }
06744
06745
06763 void mcvGetSplineFeatures(const Spline& spline, CvPoint2D32f* centroid,
06764 float* theta, float* r, float* length,
06765 float* meanTheta, float* meanR, float* curveness)
06766 {
06767
06768 if (centroid)
06769 {
06770
06771 *centroid = cvPoint2D32f(0, 0);
06772 for (int i=0; i<=spline.degree; ++i)
06773 *centroid = mcvAddVector(*centroid, spline.points[i]);
06774
06775 *centroid = cvPoint2D32f(centroid->x / (spline.degree+1),
06776 centroid->y / (spline.degree+1));
06777 }
06778
06779
06780 if (theta && r)
06781 {
06782
06783 Line line;
06784 line.startPoint = spline.points[0];
06785 line.endPoint = spline.points[spline.degree];
06786
06787
06788 mcvLineXY2RTheta(line, *r, *theta);
06789
06790
06791
06792
06793 *theta = mcvGetLineAngle(line);
06794 }
06795
06796
06797 if (meanTheta && meanR)
06798 {
06799 *meanTheta = 0;
06800 *meanR = 0;
06801
06802 CvMat* points = mcvEvalBezierSpline(spline, .1);
06803
06804 for (int i=0; i<points->height-1; i++)
06805 {
06806
06807 Line line;
06808 line.startPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, i, 0),
06809 CV_MAT_ELEM(*points, float, i, 1));
06810 line.endPoint = cvPoint2D32f(CV_MAT_ELEM(*points, float, i+1, 0),
06811 CV_MAT_ELEM(*points, float, i+1, 1));
06812
06813 float r, t;
06814 mcvLineXY2RTheta(line, r, t);
06815
06816 #warning "add pi to theta calculations for spline feature"
06817
06818
06819 t = mcvGetLineAngle(line);
06820 *meanTheta += t;
06821 *meanR += r;
06822 }
06823
06824
06825 *meanTheta /= points->height - 1;
06826 *meanR /= points->height - 1;
06827
06828
06829 cvReleaseMat(&points);
06830 }
06831
06832
06833 if (length)
06834 {
06835
06836 CvPoint2D32f v = cvPoint2D32f(spline.points[0].x -
06837 spline.points[spline.degree].x,
06838 spline.points[0].y -
06839 spline.points[spline.degree].y);
06840
06841 *length = cvSqrt(v.x * v.x + v.y * v.y);
06842 }
06843
06844
06845 if (curveness)
06846 {
06847 *curveness = 0;
06848 for (int i=0; i<spline.degree-1; i++)
06849 {
06850
06851 CvPoint2D32f t1 =
06852 mcvNormalizeVector(mcvSubtractVector(spline.points[i+1],
06853 spline.points[i]));
06854
06855
06856 CvPoint2D32f t2 =
06857 mcvNormalizeVector(mcvSubtractVector(spline.points[i+2],
06858 spline.points[i+1]));
06859
06860 *curveness += t1.x*t2.x + t1.y*t2.y;
06861 }
06862
06863 *curveness /= (spline.degree-1);
06864 }
06865 }
06866
06867
06875 CvPoint2D32f mcvSubtractVector(const CvPoint2D32f& v1, const CvPoint2D32f& v2)
06876 {
06877 return cvPoint2D32f(v1.x - v2.x, v1.y - v2.y);
06878 }
06879
06886 float mcvGetVectorNorm(const CvPoint2D32f& v)
06887 {
06888
06889 return cvSqrt(v.x * v.x + v.y * v.y);
06890 }
06891
06892
06903 bool mcvCheckMergeLines(const Line& line1, const Line& line2,
06904 float thetaThreshold, float rThreshold)
06905
06906 {
06907
06908 float r1, r2, theta1, theta2;
06909 mcvLineXY2RTheta(line1, r1, theta1);
06910 mcvLineXY2RTheta(line2, r2, theta2);
06911
06912
06913 if (theta1<0) theta1 += CV_PI;
06914 if (theta2<0) theta2 += CV_PI;
06915
06916
06917 float rDist = fabs(r1 - r2);
06918 float thetaDist = fabs(theta1 - theta2);
06919
06920 bool rOk = rDist <= rThreshold;
06921 bool thetaOk = thetaDist <= thetaThreshold;
06922
06923 bool merge = false;
06924 if (rOk && thetaOk) merge = true;
06925
06926
06927 if(DEBUG_LINES) {
06928
06929
06930 fprintf(stderr, "%s: thetaDist=%.2f, rDist=%.2f\n",
06931 merge? "Merged" : "Not ", thetaDist, rDist);
06932
06933
06934 CvMat* im = cvCreateMat(480, 640, CV_8UC3);
06935 cvSet(im, cvRealScalar(0.));
06936
06937 mcvDrawLine(im, line1, CV_RGB(255, 0, 0), 1);
06938 mcvDrawLine(im, line2, CV_RGB(0, 255, 0), 1);
06939 SHOW_IMAGE(im, "Check Merge Lines", 10);
06940
06941 cvReleaseMat(&im);
06942
06943 }
06944
06945 return merge;
06946 }
06947
06948
06957 Spline mcvLineXY2Spline(const Line& line, int degree)
06958 {
06959
06960 Spline spline;
06961 spline.degree = degree;
06962
06963
06964 spline.points[0] = line.startPoint;
06965 spline.points[degree] = line.endPoint;
06966
06967
06968 CvPoint2D32f dir = mcvSubtractVector(line.endPoint, line.startPoint);
06969
06970 for (int j=1; j<degree; ++j)
06971 {
06972
06973 CvPoint2D32f point;
06974 float t = j / (float)degree;
06975 point.x = line.startPoint.x + t * dir.x;
06976 point.y = line.startPoint.y + t * dir.y;
06977
06978 spline.points[j] = point;
06979 }
06980
06981
06982 return spline;
06983 }
06984
06985
06993 float mcvGetLineAngle(const Line& line)
06994 {
06995
06996 CvPoint2D32f v = mcvNormalizeVector(mcvSubtractVector(line.startPoint,
06997 line.endPoint));
06998
06999
07000 return acos(fabs(v.x));
07001 }
07002
07018 LineColor mcvGetPointsColor(const CvMat* im, const CvMat* points,
07019 int window, float numYellowMin,
07020 float rgMin, float rgMax,
07021 float gbMin, float rbMin,
07022 bool rbf, float rbfThreshold)
07023 {
07024
07025
07026 if (cvGetElemType(im) != CV_8UC3)
07027 return LINE_COLOR_WHITE;
07028
07029
07030
07031
07032
07033
07034
07035
07036
07037
07038
07039
07040 int numBins = 16;
07041 int histLen = 3*numBins + 3;
07042 float binWidth = 255. / numBins;
07043
07044
07045 CvMat* hist = cvCreateMat(1, histLen, CV_32FC1);
07046
07047
07048 int rbfNumCentroids = 10;
07049 float rbfSigma = 400;
07050 float rbfCentroids[] =
07051
07052 {0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,1.473684,9.236842,15.421053,3.921053,3.736842,3.500000,4.026316,3.105263,1.026316,3.552632,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000 \
07053 ,1.921053,9.157895,14.342105,5.026316,3.157895,3.710526,4.421053,3.078947,0.868421,3.315789,0.000000,0.000000,0.000000,0.000000,0.000000,0.052632,3.394737,12.473684,12.947368,4.078947,3.289474,4.500000, \
07054 3.710526,1.131579,0.815789,2.605263,2.346402,7.178840,8.077336,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.043478,0.695652,7.478261,9.565217,4.826087,3.173913,4.000000,4.000000,5.652174,9.565217,\
07055 0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.043478,1.304348,12.130435,9.434783,6.000000,6.043478,7.956522,2.521739,2.739130,0.826087,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.043478,\
07056 3.173913,21.434783,12.739130,9.782609,1.826087,0.000000,0.000000,0.000000,0.000000,20.372671,23.477374,43.850044,0.000000,0.000000,0.000000,0.000000,0.000000,1.046512,6.395349,1.906977,2.930233,14.697674,12.651163,\
07057 3.418605,1.279070,1.139535,1.465116,2.069767,0.000000,0.000000,0.000000,0.000000,0.000000,1.906977,5.674419,1.651163,3.116279,18.000000,10.906977,2.023256,1.023256,1.255814,1.395349,2.046512,0.000000,0.000000,\
07058 0.000000,0.000000,0.023256,3.441860,5.046512,1.930233,7.953488,19.883721,4.232558,1.534884,1.069767,1.279070,1.046512,1.558140,2.570005,7.212625,9.312767,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000\
07059 ,0.000000,0.615385,4.538462,8.538462,7.115385,4.807692,4.884615,5.230769,13.269231,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.576923,5.230769,10.423077,9.000000,7.000000,5.269231,5.730769\
07060 ,5.769231,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,1.923077,11.576923,15.576923,15.076923,4.000000,0.730769,0.115385,0.000000,10.828885,24.554160,35.383046,0.000000,0.000000,0.000000\
07061 ,0.000000,3.285714,4.857143,1.857143,1.857143,0.857143,3.142857,1.571429,3.142857,1.857143,2.000000,2.571429,22.000000,0.000000,0.000000,0.000000,0.000000,5.142857,4.428571,2.571429,1.428571,2.142857,3.571429,\
07062 3.000000,3.285714,2.428571,3.714286,7.714286,9.571429,0.000000,0.000000,0.000000,0.000000,7.714286,6.714286,5.571429,21.142857,5.428571,1.857143,0.285714,0.285714,0.000000,0.000000,0.000000,0.000000,20.274053,\
07063 66.647230,86.921283,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.323529,3.500000,6.264706,3.294118,2.352941,2.029412,2.676471,2.264706,4.705882,21.588235,0.000000,0.000000,0.000000,0.000000,0.000000,\
07064 0.117647,0.470588,5.588235,6.794118,3.382353,4.205882,7.411765,9.911765,8.000000,2.294118,0.823529,0.000000,0.000000,0.000000,0.000000,0.000000,0.147059,1.352941,11.117647,10.941176,14.794118,8.441176,1.764706,\
07065 0.441176,0.000000,0.000000,0.000000,31.429772,33.329532,64.759304,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,2.461538,5.615385,4.076923,1.153846,1.692308,1.230769,2.076923,2.153846,28.538462,\
07066 0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,2.076923,6.076923,3.384615,1.692308,1.307692,1.769231,1.615385,2.076923,29.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.153846,2.461538\
07067 ,5.769231,3.461538,1.538462,1.615385,1.384615,1.923077,3.000000,27.692308,3.149137,3.576138,5.896389,0.000000,0.000000,0.000000,0.000000,0.000000,0.750000,0.250000,0.250000,0.250000,2.250000,1.000000,0.500000,\
07068 0.500000,0.750000,2.000000,40.500000,0.000000,0.000000,0.000000,0.000000,0.500000,0.250000,0.500000,0.250000,1.250000,2.500000,1.750000,1.000000,1.750000,1.500000,4.250000,33.500000,0.000000,0.000000,0.000000,\
07069 0.000000,0.750000,1.250000,1.750000,21.250000,24.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,12.535714,109.326531,121.862245,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000\
07070 ,0.000000,0.000000,0.000000,0.000000,4.750000,23.250000,11.750000,5.250000,4.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,3.625000,24.875000,13.375000\
07071 ,3.875000,3.250000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.125000,11.875000,24.000000,7.000000,2.875000,3.125000,2.778061,5.803571,6.367347,0.000000,0.000000,\
07072 0.000000,0.000000,0.000000,0.000000,1.000000,0.461538,0.230769,1.307692,20.000000,13.230769,3.923077,2.076923,3.000000,3.769231,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.846154,0.461538,0.384615,\
07073 1.076923,19.000000,14.384615,4.076923,2.307692,3.307692,3.153846,0.000000,0.000000,0.000000,0.000000,0.000000,0.076923,1.000000,0.538462,0.384615,2.384615,24.615385,9.923077,2.153846,2.230769,2.692308,3.000000,\
07074 1.921507,5.174254,5.394034};
07075 float rbfWeights[] =
07076 {-0.014830,-1.586532,0.842004,-1.478210,1.868582,1.531812,0.848317,-1.189907,2.452640,-1.003280,-1.286481};
07077
07078 float f = rbfWeights[0];
07079
07080 int numYellow=0;
07081
07082 for (int i=0; i<points->rows; ++i)
07083 {
07084
07085 cvSet(hist, cvRealScalar(0));
07086
07087
07088 int xmin = MAX(cvRound(CV_MAT_ELEM(*points, float, i, 0)-window), 0);
07089 int xmax = MIN(cvRound(CV_MAT_ELEM(*points, float, i, 0)+window),
07090 im->cols);
07091 int ymin = MAX(cvRound(CV_MAT_ELEM(*points, float, i, 1)-window), 0);
07092 int ymax = MIN(cvRound(CV_MAT_ELEM(*points, float, i, 1)+window),
07093 im->rows);
07094
07095
07096 float r=0.f, g=0.f, b=0.f, rr, gg, bb;
07097 int bin;
07098 for (int x=xmin; x<=xmax; x++)
07099 for (int y=ymin; y<=ymax; y++)
07100 {
07101
07102 rr = (im->data.ptr + im->step*y)[x*3];
07103 gg = (im->data.ptr + im->step*y)[x*3+1];
07104 bb = (im->data.ptr + im->step*y)[x*3+2];
07105
07106 r += rr;
07107 g += gg;
07108 b += bb;
07109
07110 if (rbf)
07111 {
07112
07113 bin = MIN((int)(rr / binWidth), numBins);
07114 hist->data.fl[bin] ++;
07115 bin = MIN((int)(gg / binWidth), numBins);
07116 hist->data.fl[bin + numBins] ++;
07117 bin = MIN((int)(bb / binWidth), numBins);
07118 hist->data.fl[bin + 2*numBins] ++;
07119 }
07120 }
07121
07122
07123 int num = (xmax-xmin+1) * (ymax-ymin+1);
07124 r /= num;
07125 g /= num;
07126 b /= num;
07127
07128
07129 float rg = r - g;
07130 float gb = g - b;
07131 float rb = r - b;
07132
07133
07134 if (rbf)
07135 {
07136 hist->data.fl[hist->width-2] = fabs(rg);
07137 hist->data.fl[hist->width-1] = fabs(gb);
07138 hist->data.fl[hist->width] = fabs(rb);
07139
07140
07141
07142
07143 for (int j=0; j<rbfNumCentroids; j++)
07144 {
07145
07146 float d = 0., t;
07147 for (int k=0; k<histLen; k++)
07148 {
07149 t = hist->data.fl[k] -
07150 rbfCentroids[j*histLen + k];
07151 d += t*t;
07152 }
07153
07154
07155 f += rbfWeights[j+1] * exp(-.5 * d /rbfSigma);
07156 }
07157 }
07158
07159
07160 bool yellow;
07161 if (rbf)
07162 yellow = f > rbfThreshold;
07163 else
07164 yellow = rg>rgMin && rg<rgMax && gb>gbMin && rb>rbMin;
07165 if (yellow)
07166 numYellow++;
07167
07168 if (DEBUG_LINES)
07169 fprintf(stderr, "%s: f=%f, rg=%.2f, gb=%.2f, rb=%.2f\n",
07170 yellow? "YES" : "NO ", f, rg, gb, rb);
07171
07172
07173
07174 }
07175
07176
07177 LineColor clr = LINE_COLOR_WHITE;
07178 if (numYellow > numYellowMin*points->rows)
07179 clr = LINE_COLOR_YELLOW;
07180
07181
07182 cvReleaseMat(&hist);
07183
07184 return clr;
07185 }
07186
07187
07195 void mcvGetSplinesBoundingBoxes(const vector<Spline> &splines, LineType type,
07196 CvSize size, vector<CvRect> &boxes)
07197 {
07198
07199 int start, end;
07200
07201 boxes.clear();
07202 switch(type)
07203 {
07204 case LINE_VERTICAL:
07205 for(unsigned int i=0; i<splines.size(); ++i)
07206 {
07207
07208 start = (int)fmin(splines[i].points[0].x,
07209 splines[i].points[splines[i].degree].x);
07210 end = (int)fmax(splines[i].points[0].x,
07211 splines[i].points[splines[i].degree].x);
07212 boxes.push_back(cvRect(start, 0, end-start+1, size.height-1));
07213 }
07214 break;
07215
07216 case LINE_HORIZONTAL:
07217 for(unsigned int i=0; i<splines.size(); ++i)
07218 {
07219
07220 start = (int)fmin(splines[i].points[0].y,
07221 splines[i].points[splines[i].degree].y);
07222 end = (int)fmax(splines[i].points[0].y,
07223 splines[i].points[splines[i].degree].y);
07224 boxes.push_back(cvRect(0, start, size.width-1, end-start+1));
07225 }
07226 break;
07227 }
07228 }
07229
07237 void mcvGetLinesBoundingBoxes(const vector<Line> &lines, LineType type,
07238 CvSize size, vector<CvRect> &boxes)
07239 {
07240
07241 int start, end;
07242
07243 boxes.clear();
07244 switch(type)
07245 {
07246 case LINE_VERTICAL:
07247 for(unsigned int i=0; i<lines.size(); ++i)
07248 {
07249
07250 start = (int)fmin(lines[i].startPoint.x, lines[i].endPoint.x);
07251 end = (int)fmax(lines[i].startPoint.x, lines[i].endPoint.x);
07252 boxes.push_back(cvRect(start, 0, end-start+1, size.height-1));
07253 }
07254 break;
07255
07256 case LINE_HORIZONTAL:
07257 for(unsigned int i=0; i<lines.size(); ++i)
07258 {
07259
07260 start = (int)fmin(lines[i].startPoint.y, lines[i].endPoint.y);
07261 end = (int)fmax(lines[i].startPoint.y, lines[i].endPoint.y);
07262 boxes.push_back(cvRect(0, start, size.width-1, end-start+1));
07263 }
07264 break;
07265 }
07266 }
07267
07268
07276 void mcvCheckLaneWidth(vector<Line> &lines, vector<float> &scores,
07277 float wMu, float wSigma)
07278 {
07279
07280 if (lines.size() <2)
07281 return;
07282
07283
07284 int numInLines = lines.size();
07285 vector<float> rs;
07286 for (int i=0; i<numInLines; i++)
07287 rs.push_back( (lines[i].startPoint.x + lines[i].endPoint.x) / 2.);
07288
07289
07290 vector<float>::iterator ir, jr;
07291 int i, j, maxi, maxj;
07292 double score = 0., maxScore = -5.;
07293 wSigma *= wSigma;
07294 for (i=0, ir=rs.begin(); ir!=rs.end(); ir++, i++)
07295 for (j=i+1, jr=ir+1; jr!=rs.end(); jr++, j++)
07296 {
07297
07298 score = fabs(*ir - *jr) - wMu;
07299 score = exp(-.5 * score * score / wSigma);
07300
07301
07302 if (score >= maxScore)
07303 {
07304 maxScore = score;
07305 maxi = i;
07306 maxj = j;
07307
07308 fprintf(stderr, "diff=%.5f score=%.10f i=%d j=%d\n",
07309 *ir - *jr, score, maxi, maxj);
07310 }
07311 }
07312
07313
07314 vector<Line> newLines;
07315 vector<float> newScores;
07316
07317 if (maxScore<.4)
07318 {
07319 maxi = scores[maxi] > scores[maxj] ? maxi : maxj;
07320 newLines.push_back(lines[maxi]);
07321 newScores.push_back(scores[maxi]);
07322 }
07323
07324 else
07325 {
07326 newLines.push_back(lines[maxi]);
07327 newLines.push_back(lines[maxj]);
07328 newScores.push_back(scores[maxi]);
07329 newScores.push_back(scores[maxj]);
07330 }
07331 lines = newLines;
07332 scores = newScores;
07333
07334
07335 newLines.clear();
07336 newScores.clear();
07337 rs.clear();
07338 }
07339
07340
07341 void dummy()
07342 {
07343
07344 }
07345
07346 }
07347