00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "Image/OpenCVUtil.H"
00037
00038 #include "GUI/XWinManaged.H"
00039
00040 #include "Image/Pixels.H"
00041 #include "Raster/Raster.H"
00042
00043 #include "Util/Timer.H"
00044 #include "Util/Types.H"
00045 #include "Util/log.H"
00046
00047 #include "Image/ColorOps.H"
00048 #include "Image/CutPaste.H"
00049 #include "Image/MathOps.H"
00050 #include "Image/DrawOps.H"
00051 #include "Image/FilterOps.H"
00052 #include "Image/Transforms.H"
00053
00054 #include "BeoSub/hysteresis.H"
00055 #include "VFAT/segmentImageTrackMC.H"
00056 #include "BeoSub/HoughTransform.H"
00057 #include "BeoSub/ColorTracker.H"
00058 #include "BeoSub/CannyEdge.H"
00059 #include "BeoSub/IsolateColor.H"
00060 #include "rutz/compat_cmath.h"
00061
00062 #include "BeoSub/BeoSubCross.H"
00063
00064 #include <cstdio>
00065 #include <cstdlib>
00066 #include <cstring>
00067 #include <iostream>
00068 #include <math.h>
00069 #include <vector>
00070 #include <cmath>
00071
00072
00073 BeoSubCross::BeoSubCross()
00074 {
00075 houghThreshold = 40;
00076 minThreshold = 10;
00077 maxThreshold = 50;
00078 sigma = 1.1;
00079 tlow = 0.3;
00080 thigh = 1.1;
00081 linescale = 80;
00082 avgCrossCenterX = 0;
00083 avgCrossCenterY = 0;
00084 avgCrossAngle = 0.0;
00085 stdDevCrossX = 0.0;
00086 stdDevCrossY = 0.0;
00087 stdDevCrossAngle = 0.0;
00088
00089 stdDevAngleCount = 0;
00090 stdDevCenterCount = 0;
00091
00092 color.resize(4,0.0F);
00093 std.resize(4,0.0F);
00094 norm.resize(4,0.0F);
00095 adapt.resize(4,0.0F);
00096 lowerBound.resize(4,0.0F);
00097 upperBound.resize(4,0.0F);
00098
00099
00100 foundCount = 0;
00101
00102 itsSetupOrangeTracker = false;
00103
00104
00105 }
00106
00107
00108 BeoSubCross::~BeoSubCross()
00109 { }
00110
00111
00112 void BeoSubCross::setupOrangeTracker()
00113 {
00114
00115
00116 int width = 360;
00117 int height = 240;
00118
00119 segmenter = new segmentImageTrackMC<float,unsigned int, 4> (width*height);
00120
00121 int wi = width/4;
00122 int hi = height/4;
00123
00124 segmenter->SITsetFrame(&wi,&hi);
00125
00126 segmenter->SITsetCircleColor(0,255,0);
00127 segmenter->SITsetBoxColor(255,255,0,0,255,255);
00128 segmenter->SITsetUseSmoothing(false,10);
00129
00130
00131 segmenter->SITtoggleCandidateBandPass(false);
00132 segmenter->SITtoggleColorAdaptation(true);
00133
00134
00135 colorConf.openFile("colortrack.conf", true);
00136
00137
00138 PixRGB<float> P1(colorConf.getItemValueF("ORNG_R"),
00139 colorConf.getItemValueF("ORNG_G"),
00140 colorConf.getItemValueF("ORNG_B"));
00141
00142 PixH2SV1<float> ORNG(P1);
00143
00144 color[0] = ORNG.H1(); color[1] = ORNG.H2(); color[2] = ORNG.S(); color[3] = ORNG.V();
00145
00146 printf("h1: %f, h2: %f, sat: %f, value: %f", color[0], color[1], color[2], color[3]);
00147
00148
00149 std[0] = colorConf.getItemValueF("ORNG_std0");
00150 std[1] = colorConf.getItemValueF("ORNG_std1");
00151 std[2] = colorConf.getItemValueF("ORNG_std2");
00152 std[3] = colorConf.getItemValueF("ORNG_std3");
00153
00154
00155 norm[0] = colorConf.getItemValueF("ORNG_norm0");
00156 norm[1] = colorConf.getItemValueF("ORNG_norm1");
00157 norm[2] = colorConf.getItemValueF("ORNG_norm2");
00158 norm[3] = colorConf.getItemValueF("ORNG_norm3");
00159
00160
00161 adapt[0] = colorConf.getItemValueF("ORNG_adapt0");
00162 adapt[1] = colorConf.getItemValueF("ORNG_adapt1");
00163 adapt[2] = colorConf.getItemValueF("ORNG_adapt2");
00164 adapt[3] = colorConf.getItemValueF("ORNG_adapt3");
00165
00166
00167 upperBound[0] = color[0] + colorConf.getItemValueF("ORNG_up0");
00168 upperBound[1] = color[1] + colorConf.getItemValueF("ORNG_up1");
00169 upperBound[2] = color[2] + colorConf.getItemValueF("ORNG_up2");
00170 upperBound[3] = color[3] + colorConf.getItemValueF("ORNG_up3");
00171
00172
00173 lowerBound[0] = color[0] - colorConf.getItemValueF("ORNG_lb0");
00174 lowerBound[1] = color[1] - colorConf.getItemValueF("ORNG_lb1");
00175 lowerBound[2] = color[2] - colorConf.getItemValueF("ORNG_lb2");
00176 lowerBound[3] = color[3] - colorConf.getItemValueF("ORNG_lb3");
00177
00178
00179 segmenter->SITsetTrackColor(&color,&std,&norm,&adapt,&upperBound,&lowerBound);
00180
00181 }
00182
00183 int BeoSubCross::getOrangeMass(Image< PixRGB<byte> > image,
00184 Image< PixRGB<byte> > &display)
00185 {
00186 Image<PixRGB<byte> > Aux;
00187 Aux.resize(100,450,true);
00188
00189 Image< PixH2SV2<float> > H2SVimage(image);
00190
00191 segmenter->SITtrackImageAny(H2SVimage,&display,&Aux,true);
00192
00193 int mass;
00194 segmenter->SITgetBlobWeight(mass);
00195 return mass;
00196 }
00197
00198
00199
00200
00201 std::vector<LineSegment2D> BeoSubCross::pruneLines (std::vector<LineSegment2D> lines)
00202 {
00203 uint nLines = lines.size();
00204
00205 float sumLength = 0.0; float meanLength = 0.0;
00206 for (uint i = 0; i < nLines; i++) sumLength += lines[i].length();
00207 meanLength = sumLength / nLines;
00208
00209
00210 float sumsqr = 0.0;
00211 for (uint i = 0; i < nLines; i++)
00212 sumsqr += pow((float)(lines[i].length()) - meanLength, 2.0);
00213 float stdevLength = sqrt(sumsqr / (nLines-1));
00214
00215
00216 LDEBUG ("Mean: %f StdDev: %f", meanLength, stdevLength);
00217 std::vector<LineSegment2D> nlines;
00218 for(uint i = 0; i < nLines; i++)
00219 {
00220 if (lines[i].length() > (meanLength - stdevLength) &&
00221 lines[i].length() < (meanLength + stdevLength) )
00222 nlines.push_back(lines[i]);
00223 }
00224
00225 if (nlines.size() == 0)
00226 { LDEBUG("*** NO LINE LENGTH WITHIN STD DEV ***"); return lines; }
00227
00228 std::vector<LineSegment2D> flines = nlines;
00229 LDEBUG("\n\n\n\nSum the Average...");
00230 double sumAngle = 0;
00231 std::vector<LineSegment2D>::iterator itr = flines.begin();
00232 while(itr < flines.end())
00233 {
00234 float angle = (*itr).angle();
00235 LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f",
00236 (*itr).point1().i, (*itr).point1().j,
00237 (*itr).point2().i, (*itr).point2().j,
00238 angle * 180/M_PI);
00239
00240
00241 if(!isnan(angle)) { sumAngle += angle; itr++; }
00242 else
00243 {
00244 sumAngle += 90.0;
00245
00246 LDEBUG("Drop a line");
00247 }
00248 }
00249 if (flines.size() == 0) return lines;
00250
00251
00252
00253 float meanAngle = sumAngle / flines.size();
00254 float stdAngleSum = 0.0;
00255 float stdAngleSqr = 0.0;
00256 for(uint i = 0; i < flines.size(); i++)
00257 {
00258 float angle = flines[i].angle();
00259 stdAngleSum = angle - meanAngle;
00260 stdAngleSqr += (stdAngleSum * stdAngleSum);
00261 }
00262 float stdevAngle = stdAngleSqr / flines.size();
00263 double stdtemp = sqrt((double)stdevAngle);
00264 stdevAngle = (float)stdtemp;
00265
00266
00267 sumAngle = 0.0; itr = flines.begin();
00268 while(itr < flines.end())
00269 {
00270 float angle = (*itr).angle();
00271 if(angle >= (meanAngle - stdevAngle) &&
00272 angle <= (meanAngle + stdevAngle))
00273 { sumAngle += angle; itr++; }
00274 else itr = flines.erase(itr);
00275 }
00276
00277 return flines;
00278 }
00279
00280
00281
00282 std::vector<LineSegment2D> BeoSubCross::getHoughLines
00283 (Image< PixRGB <byte> > &cameraImage,
00284 Image< PixRGB <byte> > &outputImage)
00285 {
00286 std::vector <LineSegment2D> lines;
00287
00288 #ifndef HAVE_OPENCV
00289 LFATAL("OpenCV must be installed in order to use this function");
00290 #else
00291
00292 IplImage *edge = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 );
00293 cvCanny( img2ipl(luminance(cameraImage)), edge, 100, 150, 3 );
00294
00295
00296
00297
00298
00299
00300
00301 CvMemStorage* storage = cvCreateMemStorage(0);
00302
00303
00304
00305 outputImage = ipl2gray(edge);
00306
00307 CvSeq* cvlines = cvHoughLines2(edge, storage, CV_HOUGH_STANDARD,
00308 1, CV_PI/180, 40 , 0, 0);
00309
00310
00311
00312 for(int i = 0; i < MIN(cvlines->total,10); i++ )
00313 {
00314 float* line = (float*)cvGetSeqElem(cvlines,i);
00315 float rho = line[0];
00316 float theta = line[1];
00317 CvPoint pt1, pt2;
00318 double a = cos(theta), b = sin(theta);
00319 double x0 = a*rho, y0 = b*rho;
00320 pt1.x = cvRound(x0 + 1000*(-b));
00321 pt1.y = cvRound(y0 + 1000*(a));
00322 pt2.x = cvRound(x0 - 1000*(-b));
00323 pt2.y = cvRound(y0 - 1000*(a));
00324 lines.push_back(LineSegment2D(Point2D<int>(pt1.x,pt1.y),
00325 Point2D<int>(pt2.x,pt2.y)));
00326 drawLine(outputImage, Point2D<int>(pt1.x,pt1.y),
00327 Point2D<int>(pt2.x, pt2.y), PixRGB<byte>(255,0,0));
00328 }
00329
00330 cvReleaseMemStorage(&storage);
00331 cvReleaseImage(&edge);
00332
00333
00334
00335
00336
00337 #endif // HAVE_OPENCV
00338
00339 return lines;
00340 }
00341
00342
00343
00344 Point2D<int> BeoSubCross::getCrossCenter (const std::vector<LineSegment2D> lines,
00345 std::vector<LineSegment2D> ¢erPointLines,
00346 uint& stalePointCount)
00347 {
00348
00349 Point2D<int> avgCrossCenterPoint = Point2D<int>(avgCrossCenterX,avgCrossCenterY);
00350
00351 uint nLines = lines.size();
00352 if(nLines == 0)
00353 {
00354 LDEBUG("*** NO LINES ***");
00355 stalePointCount++;
00356 return avgCrossCenterPoint;
00357 }
00358
00359 std::vector<LineSegment2D> posAngleLines, negAngleLines;
00360
00361 for(uint i = 0; i < nLines; i++)
00362 {
00363 if(lines[i].angle() >= 0)
00364 {
00365 posAngleLines.push_back(lines[i]);
00366 }
00367 else
00368 {
00369 negAngleLines.push_back(lines[i]);
00370 }
00371 }
00372
00373 std::vector<LineSegment2D> fPosAngleLines = posAngleLines;
00374 std::vector<LineSegment2D> fNegAngleLines = negAngleLines;
00375
00376 std::vector<LineSegment2D> flines;
00377
00378 for(uint i = 0; i < fPosAngleLines.size(); i++)
00379 {
00380 flines.push_back(fPosAngleLines[i]);
00381 }
00382
00383 for(uint i = 0; i < fNegAngleLines.size(); i++)
00384 {
00385 flines.push_back(fNegAngleLines[i]);
00386 }
00387
00388
00389 std::vector<std::vector<Point2D<int> > > intersectPts;
00390
00391
00392 for(uint r = 0; r < flines.size(); r++)
00393 {
00394 for(uint s = 0; s < flines.size(); s++)
00395 {
00396 if(r != s)
00397 {
00398 double xIntersect, yIntersect = 0.0;
00399
00400 if(flines[r].intersects(flines[s],xIntersect,yIntersect)
00401 && (fabs(flines[r].angleBetween(flines[s])) >= 0.95 * M_PI/2)
00402 && (fabs(flines[r].angleBetween(flines[s])) <= 1.05 * M_PI/2))
00403 {
00404 int ptIndex = -1;
00405
00406 centerPointLines.push_back(flines[r]);
00407 centerPointLines.push_back(flines[s]);
00408
00409
00410
00411 for(uint c = 0; c < intersectPts.size(); c++)
00412 {
00413 if(xIntersect < intersectPts[c][0].i + 5 &&
00414 xIntersect > intersectPts[c][0].i - 5 &&
00415 yIntersect < intersectPts[c][0].j + 5 &&
00416 yIntersect > intersectPts[c][0].j - 5 )
00417 {
00418 ptIndex = c;
00419 }
00420
00421 }
00422
00423
00424 if(ptIndex > 0)
00425 {
00426 int x = (int)(xIntersect);
00427 int y = (int)(yIntersect);
00428
00429 intersectPts[ptIndex].push_back(Point2D<int>(x,y));
00430
00431
00432 intersectPts[ptIndex][0].i += x;
00433 intersectPts[ptIndex][0].i /= 2;
00434 intersectPts[ptIndex][0].j += y;
00435 intersectPts[ptIndex][0].j /= 2;
00436
00437 }
00438
00439 else
00440 {
00441 int x = (int)(xIntersect);
00442 int y = (int)(yIntersect);
00443
00444 std::vector<Point2D<int> > newIntPts;
00445 newIntPts.push_back(Point2D<int>(x,y));
00446 intersectPts.push_back(newIntPts);
00447 }
00448 }
00449 }
00450 }
00451 }
00452
00453 if(intersectPts.size() == 0)
00454 {
00455 LDEBUG("*** NO INTERSECT POINTS FOUND ***");
00456 stalePointCount++;
00457 return avgCrossCenterPoint;
00458 }
00459
00460 uint maxPts = intersectPts[0].size();
00461 uint maxIndex = 0;
00462
00463 for(uint i = 0; i < intersectPts.size(); i++)
00464 {
00465 if(intersectPts[i].size() > maxPts)
00466 {
00467 maxPts = intersectPts[i].size();
00468 maxIndex = i;
00469 }
00470 }
00471
00472 Point2D<int> finalPoint = intersectPts[maxIndex][0];
00473
00474
00475
00476
00477
00478 bool isWithinStdDev = false;
00479
00480 if(centerPointBuff.size() < 2
00481 || (abs(finalPoint.i - avgCrossCenterX) <= stdDevCrossX
00482 && abs(finalPoint.j - avgCrossCenterY) <= stdDevCrossY)
00483 )
00484 {
00485 stdDevCenterCount = 0;
00486 isWithinStdDev = true;
00487 }
00488 else
00489 {
00490 stdDevCenterCount++;
00491
00492 LINFO("Current X: %d Y: %d",finalPoint.i, finalPoint.j);
00493 LINFO("AVG X: %d Y: %d",avgCrossCenterX, avgCrossCenterY);
00494 LINFO("STDDEV CROSS (X,Y):(%f,%f)",stdDevCrossX, stdDevCrossY);
00495
00496 }
00497
00498 stalePointCount = 0;
00499
00500 uint centerBuffSize = centerPointBuff.size();
00501
00502 if(stdDevCenterCount > 5)
00503 {
00504 isWithinStdDev = true;
00505 centerPointBuff.clear();
00506 }
00507
00508 if(isWithinStdDev)
00509 {
00510 if(centerBuffSize >= 30)
00511 {
00512 centerPointBuff.pop_front();
00513 }
00514
00515 centerPointBuff.push_back(finalPoint);
00516
00517 centerBuffSize = centerPointBuff.size();
00518 }
00519
00520 if(centerBuffSize > 0)
00521 {
00522 int sumX = 0, sumY = 0;
00523 std::list<Point2D<int> >::iterator it;
00524
00525 for(it = centerPointBuff.begin(); it != centerPointBuff.end(); ++it)
00526 {
00527 sumX += (*it).i;
00528 sumY += (*it).j;
00529 }
00530
00531 avgCrossCenterX = sumX / centerBuffSize;
00532 avgCrossCenterY = sumY / centerBuffSize;
00533
00534 avgCrossCenterPoint = Point2D<int>(avgCrossCenterX,avgCrossCenterY);
00535
00536 float sqrStdCenterX = 0.0;
00537 float sqrStdCenterY = 0.0;
00538
00539
00540 for(it = centerPointBuff.begin(); it != centerPointBuff.end(); ++it)
00541 {
00542 sqrStdCenterX += (((*it).i - avgCrossCenterX) * ((*it).i - avgCrossCenterX));
00543 sqrStdCenterY += (((*it).j - avgCrossCenterY) * ((*it).j - avgCrossCenterY));
00544 }
00545
00546 float stdevCenterX = sqrStdCenterX / centerBuffSize;
00547 float stdevCenterY = sqrStdCenterY / centerBuffSize;
00548 double stdTempCenterX = sqrt((double)stdevCenterX);
00549 double stdTempCenterY = sqrt((double)stdevCenterY);
00550 stdDevCrossX = (float)stdTempCenterX;
00551 stdDevCrossY = (float)stdTempCenterY;
00552 }
00553 else
00554 {
00555 avgCrossCenterPoint = finalPoint;
00556 }
00557
00558 return avgCrossCenterPoint;
00559 }
00560
00561
00562
00563 float BeoSubCross::getCrossDir
00564 (const std::vector<LineSegment2D> lines)
00565 {
00566 uint nLines = lines.size();
00567 if(nLines == 0) { LDEBUG("*** NO LINES ***"); return avgCrossAngle;}
00568
00569
00570 std::vector<LineSegment2D> posAngleLines, negAngleLines;
00571
00572 for(uint i = 0; i < nLines; i++)
00573 {
00574 if(lines[i].angle() >= 0)
00575 {
00576 posAngleLines.push_back(lines[i]);
00577 }
00578 else
00579 {
00580 negAngleLines.push_back(lines[i]);
00581 }
00582 }
00583
00584 std::vector<LineSegment2D> fPosAngleLines = posAngleLines;
00585 std::vector<LineSegment2D> fNegAngleLines = negAngleLines;
00586
00587 double avgPosAngle, avgNegAngle;
00588
00589
00590
00591 double sumPosAngle = 0;
00592 std::vector<LineSegment2D>::iterator itr = fPosAngleLines.begin();
00593 while(itr < fPosAngleLines.end())
00594 {
00595 float angle = (*itr).angle();
00596 LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f",
00597 (*itr).point1().i, (*itr).point1().j,
00598 (*itr).point2().i, (*itr).point2().j,
00599 angle * 180/M_PI);
00600
00601
00602 if(!isnan(angle)) { sumPosAngle += angle; itr++; }
00603 else
00604 { sumPosAngle += 90.0;
00605
00606 LDEBUG("Drop a line");
00607 }
00608 }
00609
00610 if (fPosAngleLines.size() == 0)
00611 {
00612 return avgCrossAngle;
00613 }
00614 else
00615 {
00616 avgPosAngle = sumPosAngle / fPosAngleLines.size();
00617 }
00618
00619
00620 double sumNegAngle = 0;
00621 itr = fNegAngleLines.begin();
00622 while(itr < fNegAngleLines.end())
00623 {
00624 float angle = (*itr).angle();
00625 LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f",
00626 (*itr).point1().i, (*itr).point1().j,
00627 (*itr).point2().i, (*itr).point2().j,
00628 angle * 180/M_PI);
00629
00630
00631 if(!isnan(angle)) { sumNegAngle += angle; itr++; }
00632 else
00633 { sumNegAngle += 90.0;
00634
00635
00636 LDEBUG("Drop a line");
00637 }
00638 }
00639
00640
00641 if (fNegAngleLines.size() == 0)
00642 {
00643 return avgCrossAngle;
00644 }
00645 else
00646 {
00647 avgNegAngle = sumNegAngle / fNegAngleLines.size();
00648 }
00649
00650
00651 int posAngleDistance = abs(90 - (int)avgPosAngle);
00652 int negAngleDistance = abs(90 - abs((int)avgNegAngle));
00653
00654 float sumAngle = 0.0;
00655 std::vector<LineSegment2D> flines;
00656
00657 if(posAngleDistance <= negAngleDistance)
00658 {
00659 flines = fPosAngleLines;
00660 sumAngle = sumPosAngle;
00661 }
00662 else
00663 {
00664 flines = fNegAngleLines;
00665 sumAngle = sumNegAngle;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 float avgAngle = 0.0;
00694
00695 if (flines.size() != 0)
00696 {
00697 avgAngle = sumAngle / flines.size();
00698 }
00699 else
00700 {
00701 return avgCrossAngle;
00702 }
00703
00704 if (avgAngle > 0) avgAngle -= M_PI;
00705
00706
00707
00708 uint angleBuffSize = angleBuff.size();
00709
00710 bool isWithinStdDev = false;
00711
00712 if(angleBuff.size() < 2
00713 || (fabs(avgAngle - avgCrossAngle) <= stdDevCrossAngle ))
00714 {
00715 stdDevAngleCount = 0;
00716 isWithinStdDev = true;
00717 }
00718 else
00719 {
00720 stdDevAngleCount++;
00721 }
00722
00723 if(stdDevAngleCount > 10)
00724 {
00725 angleBuff.clear();
00726 isWithinStdDev = true;
00727 }
00728
00729 if(isWithinStdDev)
00730 {
00731 if(angleBuffSize >= 50)
00732 {
00733 angleBuff.pop_front();
00734 }
00735
00736 angleBuff.push_back(avgAngle);
00737
00738 angleBuffSize = angleBuff.size();
00739 }
00740
00741 if(angleBuffSize > 0)
00742 {
00743 float sumBuffAngle = 0.0;
00744 std::list<float>::iterator it;
00745
00746 for(it = angleBuff.begin(); it != angleBuff.end(); ++it)
00747 {
00748 sumBuffAngle += (*it);
00749 }
00750
00751 avgCrossAngle = sumBuffAngle / angleBuffSize;
00752
00753
00754
00755
00756 float sqrStdDevAngle = 0.0;
00757 for(it = angleBuff.begin(); it != angleBuff.end(); ++it)
00758 {
00759 sqrStdDevAngle = ((*it - avgCrossAngle) * (*it - avgCrossAngle));
00760 }
00761
00762 float stdevAngle = sqrStdDevAngle / angleBuffSize;
00763 double stdTempAngle = sqrt((double)stdevAngle);
00764 stdDevCrossAngle = (float)stdTempAngle;
00765 }
00766 else
00767 {
00768 avgCrossAngle = avgAngle;
00769 }
00770
00771 return avgCrossAngle;
00772 }
00773
00774
00775
00776
00777
00778