outlet_model.cpp
Go to the documentation of this file.
00001 // outlet_model.cpp :
00002 //
00003 //*****************************************************************************************
00004 // Warning: this is research code with poor architecture, performance and no documentation!
00005 //*****************************************************************************************
00006 
00007 #include <vector>
00008 #include <map>
00009 #include <string>
00010 #include <algorithm>
00011 
00012 #include <cv.h>
00013 #include <highgui.h>
00014 #include <ml.h>
00015 
00016 #include "outlet_pose_estimation/detail/outlet_model.h"
00017 #include "outlet_pose_estimation/detail/learning.h"
00018 #include "outlet_pose_estimation/detail/planar.h"
00019 #include "outlet_pose_estimation/detail/outlet_tuple.h"
00020 
00021 using namespace std;
00022 
00023 const int xsize = 11;
00024 const int ysize = 11;
00025 const int feature_count = xsize*ysize;
00026 
00027 void DrawKeypoints(IplImage* img, std::vector<outlet_feature_t> keypts)
00028 {
00029         for(std::vector<outlet_feature_t>::const_iterator it = keypts.begin(); it != keypts.end(); it++)
00030         {
00031                 CvPoint center = cvPoint(it->bbox.x + it->bbox.width/2, it->bbox.y + it->bbox.height/2);
00032                 int scale = MAX(it->bbox.width, it->bbox.height);
00033                 cvCircle(img, center, scale, CV_RGB(255, 0, 0), 2);
00034         }
00035 }
00036 
00037 void find_hole_candidates(IplImage* grey, IplImage* mask, CvSeq* socket, float hole_contrast, vector<CvSeq*>& holes)
00038 {
00039         cvSetZero(mask);
00040 
00041         for(CvSeq* seq = socket->v_next; seq != 0; seq = seq->h_next)
00042         {
00043                 CvRect rect = cvBoundingRect(seq);
00044 #if defined(_EUROPE)
00045                 int min_size = 5*grey->width/2272;
00046                 int max_size = min_size*6;
00047                 if(rect.width < min_size || rect.height < min_size || rect.width > max_size || rect.height > max_size)
00048                 {
00049                         continue;
00050                 }
00051 #else
00052                 const int min_size = 1;
00053                 const int max_size = 20;
00054 
00055 #if 0
00056                 if(abs(rect.x - 187) < 5 && abs(rect.y - 250) < 5)
00057                 {
00058                         int w = 1;
00059                 }
00060 #endif
00061 
00062                 if(rect.width < min_size || rect.height < min_size || rect.width > max_size || rect.height > max_size)
00063                 {
00064                         continue;
00065                 }
00066 #endif //_EUROPE
00067 
00068 #if defined(_EUROPE)
00069                 if(fabs(float(rect.width)/rect.height - 1) > 0.5)
00070                 {
00071                         continue;
00072                 }
00073 #endif //_EUROPE
00074 
00075 #if 0
00076                 CvBox2D box = cvMinAreaRect2(seq);
00077 //              float area = fabs(cvContourArea(seq));
00078 //              float length = cvArcLength(seq);
00079 //              float circle_coeff = fabs(area*4*pi)/(length*length);
00080 /*              if(circle_coeff < 0.8)
00081                 {
00082                         continue;
00083                 }
00084                 assert(circle_coeff <= 1.5);
00085 */
00086 #if defined(_EUROPE)
00087                 if(box.size.height < 0 || fabs(float(box.size.width)/box.size.height - 1) > 0.5)
00088                 {
00089                         continue;
00090                 }
00091 #endif //_EUROPE
00092 #endif
00093 
00094 #if 0
00095                 cvDrawContours(mask, seq, cvScalar(255), cvScalar(255), 0, CV_FILLED);
00096                 float avg_inside = cvAvg(grey, mask).val[0];
00097                 CvRect bound = double_rect(rect);
00098                 bound = fit_rect(bound, grey);
00099                 cvRectangle(mask, cvPoint(bound.x, bound.y), cvPoint(bound.x + bound.width, bound.y + bound.height),
00100                         cvScalar(255), CV_FILLED);
00101                 cvDrawContours(mask, seq, cvScalar(0), cvScalar(0), 0, CV_FILLED);
00102                 CvScalar avg_outside, std_outside;
00103                 cvAvgSdv(grey, &avg_outside, &std_outside, mask);
00104 #else
00105 
00106 #if 0
00107                 // !! this is old contrast calculation that I found unnecessary on
00108                 // the latest data (16mm and 5mp)
00109                 // so this is disabled to save computational time
00110                 CvRect inner_rect = resize_rect(rect, 0.75);
00111                 cvSetImageROI(grey, inner_rect);
00112                 float avg_inside = cvSum(grey).val[0];
00113                 cvResetImageROI(grey);
00114 #endif
00115 
00116 #if !defined(_TUNING)
00117                 CvRect bound = double_rect(rect);
00118 #else
00119                 CvRect bound = resize_rect(rect, 2.0f);
00120 #endif //_TUNING
00121         bound = fit_rect(bound, grey);
00122 
00123 #if 0
00124                 // !! this is old contrast calculation that I found unnecessary on
00125                 // the latest data (16mm and 5mp)
00126                 // so this is disabled to save computational time
00127                 CvScalar avg_outside, std_outside;
00128                 cvSetImageROI(grey, bound);
00129                 avg_outside = cvSum(grey);
00130                 cvResetImageROI(grey);
00131                 avg_outside.val[0] -= avg_inside;
00132                 avg_inside /= inner_rect.width*inner_rect.height;
00133                 avg_outside.val[0] /= bound.width*bound.height;
00134 #endif
00135 #endif
00136 #if 0
00137                 cvCopy(grey, mask);
00138                 cvDrawContours(mask, seq, cvScalar(255), cvScalar(255), 0, 1);
00139                 cvSetImageROI(mask, bound);
00140                 cvNamedWindow("2", 1);
00141                 cvShowImage("2", mask);
00142                 cvWaitKey(0);
00143                 cvResetImageROI(mask);
00144 #endif
00145 
00146                 // return the mask in its previous state
00147                 cvRectangle(mask, cvPoint(bound.x, bound.y), cvPoint(bound.x + bound.width, bound.y + bound.height),
00148                                         cvScalar(0), CV_FILLED);
00149 #if defined(_EUROPE)
00150                 const float avg_factor = 1.0f;
00151 #else
00152 //              const float avg_factor = 1.3f;
00153 #endif //_EUROPE
00154 
00155                 float contrast, variation;
00156                 calc_contrast_factor(grey, rect, contrast, variation);
00157 #if !defined(_TUNING)
00158                 if(/*std_outside.val[0]/avg_outside.val[0] > 0.3f ||*/ avg_outside.val[0] < avg_inside*avg_factor)
00159                 {
00160                         continue;
00161                 }
00162 #else
00163                 if(contrast < hole_contrast)// /*|| variation > 0.7f*/ || avg_outside.val[0] < avg_inside*1.0f)
00164                 {
00165                         continue;
00166                 }
00167 #endif //_TUNING
00168                 //printf("Std outside = %f\n", std_outside.val[0]/avg_outside.val[0]);
00169                 holes.push_back(seq);
00170         }
00171 }
00172 
00173 vector<outlet_feature_t>::const_iterator find_fartherst_hole(const vector<vector<outlet_feature_t>::const_iterator>& candidates,
00174                                                                                                                          outlet_feature_t feature)
00175 {
00176         vector<vector<outlet_feature_t>::const_iterator>::const_iterator itmax;
00177         int distmax = 0;
00178         int fx = feature.bbox.x + feature.bbox.width/2;
00179         for(vector<vector<outlet_feature_t>::const_iterator>::const_iterator it = candidates.begin(); it != candidates.end(); it++)
00180         {
00181                 int cx = (*it)->bbox.x + (*it)->bbox.width/2;
00182                 int dist = abs(fx - cx);
00183                 if(dist > distmax)
00184                 {
00185                         distmax = dist;
00186                         itmax = it;
00187                 }
00188         }
00189 
00190         return(*itmax);
00191 }
00192 
00193 void find_holes(const vector<outlet_feature_t>& holes, vector<outlet_t>& outlets, IplImage* grey, IplImage* mask, IplImage* img)
00194 {
00195 #if defined(_EUROPE)
00196         int min_dist = 5*grey->width/2272;
00197         int max_dist = 50*grey->width/2272;
00198         int max_dist_prox = max_dist/2;
00199 #else
00200         const int min_dist = 14;//7;//20;
00201         const int max_dist = 80;//30;//100;
00202         const int max_dist_prox = 2*max_dist;
00203 #endif //_EUROPE
00204 
00205         // we will keep a list of references to outlets for each feature
00206         // we will use this to filter out overlapping outlets
00207         vector<vector<int> > references;
00208         references.resize(holes.size());
00209 
00210         for(vector<outlet_feature_t>::const_iterator it1 = holes.begin(); it1 != holes.end(); it1++)
00211         {
00212                 vector<vector<outlet_feature_t>::const_iterator> candidates;
00213                 int proximity_count = 0;
00214 
00215                 CvRect rect1 = it1->bbox;
00216                 int x1 = rect1.x + rect1.width/2;
00217                 int y1 = rect1.y + rect1.height/2;
00218 
00219 #if 0
00220                 if(abs(x1 - 1056) < 10 && abs(y1 - 500) < 10)
00221                 {
00222                         int w = 1;
00223                 }
00224 #endif
00225 
00226 #if defined(_TUNING)
00227                 int proximity_thresh = 50;
00228                 if(x1 < proximity_thresh || y1 < proximity_thresh ||
00229                    x1 > grey->width - proximity_thresh ||
00230                    y1 > grey->height - proximity_thresh)
00231                 {
00232                         continue;
00233                 }
00234 #endif
00235                 for(vector<outlet_feature_t>::const_iterator it2 = holes.begin(); it2 != holes.end(); it2++)
00236                 {
00237 //                      if(it1 >= it2) continue;
00238 
00239                         CvRect rect2 = it2->bbox;
00240 
00241                         int x2 = rect2.x + rect2.width/2;
00242                         int y2 = rect2.y + rect2.height/2;
00243 
00244 #if 0
00245                         if(abs(x2 - 1093) < 10 && abs(y2 - 500) < 10)
00246                         {
00247                                 int w = 1;
00248                         }
00249 #endif
00250 
00251 #if defined(_TUNING)
00252                         int proximity_thresh = 20;
00253                         if(x2 < proximity_thresh || y2 < proximity_thresh ||
00254                            x2 > grey->width - proximity_thresh ||
00255                            y2 > grey->height - proximity_thresh)
00256                         {
00257                                 continue;
00258                         }
00259 #endif
00260 
00261                         if(x2 <= x1)
00262                         {
00263                                 continue;
00264                         }
00265 
00266                         if(__max(abs(x1 - x2), abs(y1 - y2)) < max_dist_prox)
00267                         {
00268                                 proximity_count++;
00269                         }
00270 
00271 #if defined(_SMALL)
00272                         const int min_candidates = 5;
00273                         const int min_ydist = 5;
00274 #else
00275 #if !defined(_USE_OUTLET_TUPLE)
00276                         const int min_candidates = 3;
00277 #else
00278                         const int min_candidates = 100;
00279 #endif //_USE_OUTLET_TUPLE
00280                         const int min_ydist = 40;
00281 #endif //_SMALL
00282                         if(abs(y1 - y2) > min_ydist)
00283                         {
00284                                 continue;
00285                         }
00286 
00287 #if !defined(_USE_OUTLET_TUPLE)
00288                          if(atan2(fabs(y1 - y2), fabs(x1 - x2)) > 2*pi/3)
00289                          {
00290                                  continue;
00291                          }
00292 #endif //_USE_OUTLET_TUPLE
00293 
00294                         float dist = sqrt(float(x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
00295                         if(dist < min_dist || dist > max_dist)
00296                         {
00297                                 continue;
00298                         }
00299 
00300             if(dist < MAX(it1->bbox.width, it2->bbox.width)*5)
00301             {
00302                 continue;
00303             }
00304 
00305                         // check if there are other outlets in the region
00306                         candidates.push_back(it2);
00307                         int s = candidates.size();
00308                         if(s > min_candidates)
00309                         {
00310                                 candidates.clear();
00311                                 break;
00312                         }
00313                 }
00314 
00315 
00316 #if defined(_EUROPE)
00317                 if(proximity_count < 4 && candidates.size() > 0)
00318 #else
00319                         for(unsigned int i = 0; i < candidates.size(); i++)
00320 #endif
00321                 {
00322 #if defined(_EUROPE)
00323                         vector<outlet_feature_t>::const_iterator cand_it = find_fartherst_hole(candidates, *it1);
00324 #else
00325                         vector<outlet_feature_t>::const_iterator cand_it = candidates[i];
00326 #endif //_EUROPE
00327                         outlet_feature_t cand = *cand_it;
00328                         CvRect rect2 = cand.bbox;//candidates[0].bbox;
00329                         int x2 = rect2.x + rect2.width/2;
00330                         int y2 = rect2.y + rect2.height/2;
00331 
00332                         CvRect small_rect = cvRect(MIN(rect1.x, rect2.x), MIN(rect1.y, rect2.y),
00333                                                                            MAX(rect2.x + rect2.width - rect1.x, rect1.x + rect1.width - rect2.x),
00334                                                                            MAX(rect2.y + rect2.height - rect1.y, rect1.y + rect1.height - rect2.y));
00335 
00336                         cvSetZero(mask);
00337                         //cvRectangle(mask, small_rect, cvScalar(255), CV_FILLED);
00338                         cvSetImageROI(grey, small_rect);
00339                         cvSetImageROI(mask, small_rect);
00340                         cvThreshold(grey, mask, 140, 255, CV_THRESH_BINARY_INV);
00341                         cvResetImageROI(grey);
00342                         cvResetImageROI(mask);
00343 #if 0
00344                         int color1 = (int)cvAvg(grey, mask).val[0];
00345 #else
00346                         int color1 = (int)cvAvg(grey).val[0];
00347 #endif
00348 //                      cvSaveImage("grey.jpg", grey);
00349 //                      cvSaveImage("mask.jpg", mask);
00350 
00351                         // double the size of the rectangle
00352                         small_rect = double_rect(small_rect);
00353                         small_rect = fit_rect(small_rect, grey);
00354 
00355                         CvRect large_rect = double_rect(small_rect);
00356                         large_rect = fit_rect(large_rect, grey);
00357 
00358                         cvRectangle(mask, large_rect, cvScalar(255), CV_FILLED);
00359                         cvRectangle(mask, small_rect, cvScalar(0), CV_FILLED);
00360                         int color2 = (int)cvAvg(grey, mask).val[0];
00361 
00362                         const float rect_ratio = 1.0f;
00363                         if(color2/color1 < rect_ratio)
00364                         {
00365 //                              continue;
00366                         }
00367 
00368 #if 0
00369                         cvRectangle(img, large_rect, CV_RGB(color2, color2, color2), CV_FILLED);
00370                         cvRectangle(img, small_rect, CV_RGB(color1, color1, color1), CV_FILLED);
00371 #endif
00372 
00373                         outlet_t outlet;
00374                         outlet.hole1 = cvPoint(x1, y1);
00375                         outlet.hole2 = cvPoint(x2, y2);
00376                         outlet.feature1 = *it1;
00377                         outlet.feature2 = cand;
00378                         outlets.push_back(outlet);
00379 
00380                         references[it1 - holes.begin()].push_back(outlets.size() - 1);
00381                         references[cand_it - holes.begin()].push_back(outlets.size() - 1);
00382                 }
00383 
00384                 candidates.clear();
00385         }
00386 
00387 #if defined(_EUROPE)
00388         // filter overlapping outlets
00389         vector<outlet_t> filtered_outlets;
00390         vector<int> outlet_flags;
00391         outlet_flags.resize(outlets.size(), 1);
00392         for(vector<vector<int> >::const_iterator it = references.begin(); it != references.end(); it++)
00393         {
00394                 float dist_max = 0;
00395                 int it_max = -1;
00396                 for(vector<int>::const_iterator oit = it->begin(); oit != it->end(); oit++)
00397                 {
00398                         float dist = outlet_size(outlets[*oit]);
00399                         if(dist > dist_max)
00400                         {
00401                                 dist_max = dist;
00402                                 it_max = *oit;
00403                         }
00404                 }
00405                 for(vector<int>::const_iterator oit = it->begin(); oit != it->end(); oit++)
00406                 {
00407                         if(*oit != it_max)
00408                         {
00409                                 outlet_flags[*oit] = outlet_flags[*oit] & 0;
00410                         }
00411                 }
00412         }
00413 
00414         for(int i = 0; i < outlet_flags.size(); i++)
00415         {
00416                 if(outlet_flags[i])
00417                 {
00418                         filtered_outlets.push_back(outlets[i]);
00419                 }
00420         }
00421 
00422         outlets = filtered_outlets;
00423 #endif //_EUROPE
00424 }
00425 
00426 int test_adjacency(const vector<outlet_feature_t>& features, outlet_feature_t f)
00427 {
00428         int fx = f.bbox.x + f.bbox.width/2;
00429         int fy = f.bbox.y + f.bbox.height/2;
00430         int fscale = max(f.bbox.width, f.bbox.height);
00431         for(vector<outlet_feature_t>::const_iterator it = features.begin(); it != features.end(); it++)
00432         {
00433                 int x = it->bbox.x + it->bbox.width/2;
00434                 int y = it->bbox.y + it->bbox.height/2;
00435 
00436                 if(abs(fx - x) < fscale && abs(fy - y) < fscale)
00437                 {
00438                         return 1;
00439                 }
00440         }
00441 
00442         return 0;
00443 }
00444 
00445 void find_outlet_features(IplImage* src, vector<outlet_feature_t>& features, const char* filename)
00446 {
00447         const float min_intersect = 0.2;
00448 
00449         //cvErode(src, src);
00450         IplImage* grey = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00451         cvCvtColor(src, grey, CV_RGB2GRAY);
00452         cvSmooth(grey, grey);
00453         IplImage* mask = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00454 
00455         IplImage* mask_black = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00456         IplImage* mask_white = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00457         IplImage* imgfeat = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00458         cvSetZero(imgfeat);
00459 
00460         CvMemStorage* storage = cvCreateMemStorage();
00461 
00462         IplImage* imgholes = cvCloneImage(src);
00463         for(int coi = 1; coi < 4; coi++)
00464         {
00465                 cvSetImageCOI(imgholes, coi);
00466                 cvCopy(grey, imgholes);
00467         }
00468         cvSetImageCOI(imgholes, 0);
00469 
00470         for(int thresh = 20; thresh < 170; thresh += 20)
00471         {
00472                 cvSet(mask_black, cvScalar(255));
00473                 cvSet(mask_white, cvScalar(255));
00474                 IplImage* tempgrey = cvCloneImage(mask_white);
00475                 IplImage* tempmask = cvCloneImage(mask_white);
00476 
00477 #if 0
00478                 for(int coi = 1; coi < 4; coi++)
00479                 {
00480                         cvSetImageCOI(src, coi);
00481                         cvCopy(src, tempgrey);
00482                         cvThreshold(tempgrey, tempmask, thresh, 255, CV_THRESH_BINARY_INV);
00483                         cvAnd(mask_black, tempmask, mask_black);
00484 
00485                         cvThreshold(tempgrey, tempmask, thresh, 255, CV_THRESH_BINARY);
00486                         cvAnd(mask_white, tempmask, mask_white);
00487                 }
00488 #else
00489                 cvThreshold(grey, mask_white, thresh, 255, CV_THRESH_BINARY);
00490                 cvThreshold(grey, mask_black, thresh, 255, CV_THRESH_BINARY_INV);
00491 #endif
00492                 cvSetImageCOI(src, 0);
00493                 cvNot(mask_black, mask_black);
00494 
00495 #if 0
00496                 cvAnd(mask_white, mask_black, tempgrey);
00497                 printf("Processing thresh = %d\n", thresh);
00498                 cvNamedWindow("1", 1);
00499                 cvShowImage("1", tempgrey);
00500                 cvWaitKey(0);
00501 #endif
00502                 //cvCopy(src, temp);
00503                 cvReleaseImage(&tempgrey);
00504 
00505                 CvSeq* first = 0;
00506                 cvFindContours(mask_white, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
00507 
00508                 for(CvSeq* seq = first; seq != 0; seq = seq->h_next)
00509                 {
00510                         CvRect rect = cvBoundingRect(seq);
00511                         if(rect.width < 40 || rect.height < 40)
00512                         {
00513                                 continue;
00514                         }
00515 
00516                         cvSetZero(tempmask);
00517                         cvDrawContours(tempmask, seq, cvScalar(255), cvScalar(255), 0, CV_FILLED);
00518                         cvAnd(tempmask, mask_black, tempmask);
00519                         CvSeq* outlet = 0;
00520 #if 0
00521                         int w = 1;
00522                         if(w)
00523                         {
00524 
00525                         cvNamedWindow("1", 1);
00526                         cvShowImage("1", tempmask);
00527                         cvSaveImage("mask.jpg", tempmask);
00528                         cvWaitKey(0);
00529                         }
00530 #endif
00531                         cvFindContours(tempmask, storage, &outlet, sizeof(CvContour), CV_RETR_TREE);
00532 
00533                         int holes_count = 0;
00534                         for(CvSeq* seqhole = outlet->v_next; seqhole != NULL; seqhole = seqhole->h_next, holes_count++);
00535                         if(holes_count < 2)
00536                         {
00537                                 continue;
00538                         }
00539 
00540 
00541                         vector<CvSeq*> holes;
00542             const float default_hole_contrast = 1.1f;
00543                         find_hole_candidates(grey, mask, outlet, default_hole_contrast, holes);
00544 
00545                         for(vector<CvSeq*>::iterator it = holes.begin(); it != holes.end(); it++)
00546                         {
00547                                 CvRect roi = cvBoundingRect(*it);
00548                                 cvSetImageROI(imgfeat, roi);
00549                                 float avg = cvAvg(imgfeat).val[0];
00550                                 if(avg < min_intersect)
00551                                 {
00552                                         outlet_feature_t feature;
00553                                         feature.bbox = roi;
00554 //                                      if(test_adjacency(features, feature) == 0)
00555 //                                      {
00556                                                 features.push_back(feature);
00557 //                                      }
00558                                 }
00559                         }
00560                         cvResetImageROI(imgfeat);
00561 
00562                         for(vector<outlet_feature_t>::iterator it = features.begin(); it != features.end(); it++)
00563                         {
00564                                 //cvRectangle(imgholes, it->bbox, CV_RGB(255, 0, 0), 1);
00565                                 cvCircle(imgholes, cvPoint(it->bbox.x, it->bbox.y), 2, CV_RGB(255, 0, 0));
00566                         }
00567 
00568                 }
00569 
00570 #if 0
00571                 cvNamedWindow("1", 1);
00572                 cvShowImage("1", imgholes);
00573                 cvWaitKey(0);
00574                 cvSaveImage("mask.jpg", imgholes);
00575 #endif
00576                 cvReleaseImage(&tempmask);
00577         }
00578         /*
00579          cvNamedWindow("1", 0);
00580          cvSImage("1", temp);
00581          cvWaitKey(0);
00582          */
00583         char buf[1024];
00584 
00585 #if defined(_VERBOSE)
00586         sprintf(buf, "../../holes/%s", filename);
00587         cvSaveImage(buf, imgholes);
00588 
00589         sprintf(buf, "../../src/%s", filename);
00590         cvSaveImage(buf, src);
00591 #endif //_VERBOSE
00592 
00593         cvReleaseImage(&grey);
00594         cvReleaseImage(&mask);
00595 
00596         cvReleaseImage(&mask_black);
00597         cvReleaseImage(&mask_white);
00598         cvReleaseImage(&imgholes);
00599         cvReleaseImage(&imgfeat);
00600         cvReleaseMemStorage(&storage);
00601 }
00602 
00603 inline float outlet_size(outlet_t outlet)
00604 {
00605         return fabs((float)(outlet.hole2.x - outlet.hole1.x)*(outlet.hole2.x - outlet.hole1.x) +
00606                                 (outlet.hole2.y - outlet.hole1.y)*(outlet.hole2.y - outlet.hole1.y));
00607 }
00608 
00609 CvRect outlet_rect(outlet_t outlet)
00610 {
00611         float dist = fabs((float)outlet.hole2.x - outlet.hole1.x);
00612 #if defined(_EUROPE)
00613         float width = dist*2.0f;
00614 #else
00615         float width = dist*1.5f;
00616 #endif
00617         float height = width;
00618         return double_rect(cvRect(outlet.hole1.x - width*0.25f, outlet.hole1.y - height*0.5f, width, height));
00619 
00620 }
00621 
00622 void move_features(vector<outlet_feature_t>& features, CvPoint origin)
00623 {
00624         for(vector<outlet_feature_t>::iterator it = features.begin(); it != features.end(); it++)
00625         {
00626                 it->bbox.x += origin.x;
00627                 it->bbox.y += origin.y;
00628         }
00629 }
00630 
00631 void detect_outlets(IplImage* src, vector<outlet_feature_t>& features, vector<outlet_t>& outlets,
00632                                         outlet_tuple_t* outlet_tuple, const char* output_path, const char* filename)
00633 {
00634         IplImage* temp = cvCloneImage(src);
00635         IplImage* grey = 0;
00636 
00637         CvRect roi = outlet_tuple ? outlet_tuple->roi : cvRect(0, 0, src->width, src->height);
00638         cvSetImageROI(src, roi);
00639         grey = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_8U, 1);
00640 #if 0
00641         cvCvtColor(src, grey, CV_RGB2GRAY);
00642 #else
00643         cvSetImageCOI(src, 3);
00644         cvCopy(src, grey);
00645         cvSetImageCOI(src, 0);
00646         cvConvertScale(grey, grey, 0.5);
00647 #endif
00648 
00649         cvErode(grey, grey);
00650         cvDilate(grey, grey);
00651 
00652 #if 0
00653         cvNamedWindow("1", 1);
00654         cvShowImage("1", grey);
00655         cvWaitKey(0);
00656 #endif
00657 
00658     const float default_hole_contrast = 1.1f;
00659         find_outlet_features_fast(grey, features, default_hole_contrast, output_path, filename);
00660 
00661         move_features(features, cvPoint(roi.x, roi.y));
00662 
00663         cvReleaseImage(&grey);
00664         cvResetImageROI(src);
00665 
00666 #if _PREDICT
00667         printf("Filtering keypoints...");
00668         CvRTrees* rtrees = new CvRTrees();
00669         rtrees->load("../../forest.xml");
00670         FilterPoints(grey, features, rtrees);
00671         printf("done. %d points left\n", features.size());
00672         delete rtrees;
00673 #endif //_PREDICT
00674 
00675 #if defined(_USE_OUTLET_TUPLE)
00676 //      cvErode(tuple_mask, tuple_mask, 0, 10); // remove feature points on the edges
00677 
00678         if(outlet_tuple)
00679         {
00680                 IplImage* distance_map = calc_tuple_distance_map(outlet_tuple->tuple_mask);
00681                 filter_features_distance_mask(features, distance_map);
00682                 cvReleaseImage(&distance_map);
00683         }
00684 
00685 #endif //_USE_OUTLET_TUPLE
00686 
00687 #if defined(_VERBOSE)
00688         char buf[1024];
00689         if(output_path && filename)
00690         {
00691                 IplImage* _src = cvCloneImage(src);
00692                 DrawKeypoints(_src, features);
00693                 sprintf(buf, "%s/keyout/%s", output_path, filename);
00694                 cvSaveImage(buf, _src);
00695                 cvReleaseImage(&_src);
00696         }
00697 #endif //_VERBOSE
00698 
00699         grey = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00700         IplImage* mask = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
00701         cvCvtColor(src, grey, CV_RGB2GRAY);
00702         find_holes(features, outlets, grey, mask, temp);
00703 
00704 #if defined(_PREDICT_OUTLETS)
00705         CvRTrees* outlet_rtrees = new CvRTrees();
00706         outlet_rtrees->load("../../outlet_forest.xml");
00707         filter_outlets(grey, outlets, outlet_rtrees);
00708         delete outlet_rtrees;
00709 #endif //_PREDICT_OUTLETS
00710 
00711 
00712 #if defined(_VERBOSE)
00713         if(output_path && filename)
00714         {
00715                 draw_outlets(temp, outlets);
00716 
00717                 sprintf(buf, "%s/output/%s", output_path, filename);
00718                 strcpy(buf + strlen(buf) - 3, "jpg");
00719                 cvSaveImage(buf, temp);
00720         }
00721 #endif //_VERBOSE
00722 
00723 #if defined(_TUNING) && 1
00724         cvCopy(src, temp);
00725         cvResetImageROI(src);
00726         cvResetImageROI(grey);
00727 
00728 #endif // _TUNING
00729 
00730 
00731         cvReleaseImage(&temp);
00732         cvReleaseImage(&grey);
00733         cvReleaseImage(&mask);
00734 }
00735 
00736 int filter_outlets_templmatch(IplImage* src, vector<outlet_t>& outlets, IplImage* templ, const char* output_path, const char* filename, CvMat** homography,
00737                                                           CvPoint3D32f* origin, CvPoint2D32f* scale)
00738 {
00739         // using template matching for further filtering of fps
00740         // first calculate homography
00741         CvMat* map_matrix = cvCreateMat(3, 3, CV_32FC1);
00742         CvSize dst_size;
00743         int ret = calc_image_homography(src, map_matrix, &dst_size, 0, origin, scale, output_path, filename);
00744         if(ret)
00745         {
00746                 if(homography)
00747                 {
00748                         *homography = map_matrix;
00749                 }
00750                 const int max_image_width = 2048;
00751                 const int max_image_height = 2048;
00752                 dst_size.width = MIN(dst_size.width, max_image_width);
00753                 dst_size.height = MIN(dst_size.height, max_image_height);
00754                 printf("warped size: %d %d\n", dst_size.width, dst_size.height);
00755                 IplImage* warped = cvCreateImage(dst_size, IPL_DEPTH_8U, 3);
00756                 cvWarpPerspective(src, warped, map_matrix);
00757 
00758                 cvSaveImage("warped.jpg", warped);
00759 
00760                 // now load template and calculate the mask
00761                 IplImage* warped_mask = find_templates(warped, templ);
00762                 cvDilate(warped_mask, warped_mask, 0, 4);
00763 
00764 #if 0
00765                 cvNamedWindow("1", 1);
00766                 cvShowImage("1", warped);
00767                 cvWaitKey(0);
00768 #endif
00769 
00770                 filter_outlets_templ_ex(outlets, map_matrix, warped_mask);
00771 
00772                 cvReleaseImage(&warped);
00773         }
00774 
00775         if(!homography)
00776         {
00777                 cvReleaseMat(&map_matrix);
00778         }
00779 
00780         return ret;
00781 }
00782 
00783 void read_outlet_roi(const char* filename, outlet_roi_t& outlet_roi)
00784 {
00785         FILE* fp = fopen(filename, "rt");
00786 
00787         int ret = 0;
00788         char buf[1024];
00789         int x1, y1, x2, y2;
00790         while((ret = fscanf(fp, "%s %d %d %d %d\n", buf, &x1, &y1, &x2, &y2)) > 0)
00791         {
00792                 string str = string(buf);
00793                 outlet_roi[str].push_back(cvRect(x1, y1, x2 - x1, y2 - y1));
00794         }
00795 
00796         fclose(fp);
00797 }
00798 
00799 int is_point_inside_roi(const vector<CvRect>& rects, CvPoint point)
00800 {
00801         for(vector<CvRect>::const_iterator it = rects.begin(); it != rects.end(); it++)
00802         {
00803                 if(is_point_inside_rect(*it, point))
00804                 {
00805                    return 1;
00806                 }
00807         }
00808 
00809         return 0;
00810 }
00811 
00812 int is_point_incenter_roi(const vector<CvRect>& rects, CvPoint point)
00813 {
00814         for(vector<CvRect>::const_iterator it = rects.begin(); it != rects.end(); it++)
00815         {
00816                 CvRect _small = resize_rect(*it, 0.5f);
00817                 if(is_point_inside_rect(_small, point))
00818                 {
00819                         return 1;
00820                 }
00821         }
00822 
00823         return 0;
00824 }
00825 
00826 int is_point_inside_roi(const outlet_roi_t& outlet_roi, CvPoint point, string img_name)
00827 {
00828         map<string, vector<CvRect> >::const_iterator it = outlet_roi.find(img_name);
00829         //vector<CvRect> vrect = it->second;
00830         if(it == outlet_roi.end())
00831         {
00832                 // no element with such a name
00833                 return 0;
00834         }
00835 
00836         int ret = is_point_inside_roi(it->second, point);
00837         return ret;
00838 }
00839 
00840 inline int is_rect_inside_rect(CvRect large, CvRect smaller)
00841 {
00842         if(smaller.x >= large.x && smaller.y >= large.y && smaller.x + smaller.width <= large.x + large.width &&
00843            smaller.y + smaller.height <= large.y + large.height)
00844         {
00845                 return 1;
00846         }
00847         else
00848         {
00849                 return 0;
00850         }
00851 }
00852 
00853 void calc_labels(const vector<CvRect>& rects, const vector<outlet_feature_t>& keypts, vector<int>& labels)
00854 {
00855         for(vector<outlet_feature_t>::const_iterator it = keypts.begin(); it != keypts.end(); it++)
00856         {
00857                 CvPoint center = cvPoint(it->bbox.x + it->bbox.width/2, it->bbox.y + it->bbox.height/2);
00858 #if defined(_TRAIN)
00859                 int label = is_point_incenter_roi(rects, center);
00860 #else
00861                 int label = is_point_inside_roi(rects, center);
00862 #endif //_TRAIN
00863                 labels.push_back(label);
00864         }
00865 }
00866 
00867 void extract_intensity_features(IplImage* grey, const vector<outlet_feature_t>& keypts, CvMat** mat,
00868                                                                 int equalize_hist, const vector<int>& labels, const char* buf)
00869 {
00870         int start_row = 0;
00871 
00872         if(!(*mat))
00873         {
00874                 *mat = cvCreateMat(keypts.size(), feature_count, CV_32FC1);
00875         }
00876         else
00877         {
00878                 start_row = (*mat)->rows;
00879                 CvMat* _mat = cvCreateMat((*mat)->rows + keypts.size(), feature_count, CV_32FC1);
00880                 // copy mat to the beginning of _mat
00881                 for(int r = 0; r < (*mat)->rows; r++)
00882                 {
00883                         memcpy(_mat->data.ptr + _mat->step*r, (*mat)->data.ptr + (*mat)->step*r, sizeof(float)*_mat->cols);
00884                 }
00885 
00886                 // now free *mat
00887                 cvReleaseMat(mat);
00888                 *mat = _mat;
00889         }
00890 
00891         // prepare a temporary image
00892         IplImage* features = cvCreateImage(cvSize(xsize, ysize), IPL_DEPTH_8U, 1);
00893 
00894         // now extract intensity values and copy them to the matrix
00895         for(unsigned int r = 0; r < keypts.size(); r++)
00896         {
00897 //              CvPoint center = cvPoint(keypts[r].bbox.x + keypts[r].bbox.width/2,
00898 //                                                               keypts[r].bbox.y + keypts[r].bbox.height/2);
00899 //              int scale = keypts[r].bbox.width;
00900                 const float scale_factor = 2.0f;
00901 //              CvRect roi = cvRect(center.x - scale_factor*scale, center.y - scale_factor*scale,
00902 //                                                      2*scale_factor*scale, 2*scale_factor*scale);
00903                 CvRect roi = keypts[r].bbox;
00904                 roi = resize_rect(roi, scale_factor);
00905                 roi = fit_rect(roi, grey);
00906 
00907                 cvSetImageROI(grey, roi);
00908                 cvResize(grey, features);
00909                 if(equalize_hist)
00910                 {
00911                         cvEqualizeHist(features, features);
00912                 }
00913 #if 0
00914                 const float norm = 1;
00915 #else
00916                 float norm = cvSum(features).val[0];
00917 #endif
00918                 for(int y = 0; y < ysize; y++)
00919                 {
00920                         for(int x = 0; x < xsize; x++)
00921                         {
00922                                 cvmSet(*mat, start_row + r, y*xsize + x, float(features->imageData[features->widthStep*y + x])/norm);
00923                         }
00924                 }
00925                 cvResetImageROI(grey);
00926                 if(labels.size() == 0)
00927                 {
00928                         // do not save image patch
00929                         continue;
00930                 }
00931 
00932                 // save the feature to an image
00933                 char filename[1024];
00934                 char lab[1024];
00935                 if(labels[start_row + r] == 0)
00936                 {
00937                         continue;
00938                         strcpy(lab, "neg");
00939                 }
00940                 else
00941                 {
00942                         strcpy(lab, "pos");
00943                 }
00944 #if defined(_VERBOSE)
00945                 sprintf(filename, "../../rfsamples/%s/%s_%d.jpg", lab, buf, start_row + r);
00946                 cvSaveImage(filename, features);
00947 #endif
00948         }
00949 
00950         cvReleaseImage(&features);
00951 }
00952 
00953 CvMat* vector2mat(const vector<int>& vec)
00954 {
00955         CvMat* mat = cvCreateMat(vec.size(), 1, CV_32SC1);
00956         for(unsigned int i = 0; i < vec.size(); i++)
00957         {
00958                 *(int*)(mat->data.ptr + mat->step*i) = vec[i];
00959         }
00960 
00961         return mat;
00962 }
00963 
00964 void FilterPoints(IplImage* grey, vector<outlet_feature_t>& keypts, const CvRTrees* rtrees)
00965 {
00966 /*      IplImage* _temp = cvCreateImage(cvSize(grey->width, grey->height), IPL_DEPTH_8U, 3);
00967         for(int coi = 1; coi < 4; coi++)
00968         {
00969                 cvSetImageCOI(_temp, coi);
00970                 cvCopyImage(grey, _temp);
00971         }
00972         cvSetImageCOI(_temp, 0);
00973 */
00974         vector<outlet_feature_t> filtered;
00975         for(vector<outlet_feature_t>::const_iterator it = keypts.begin(); it != keypts.end(); it++)
00976         {
00977                 vector<outlet_feature_t> temp;
00978                 temp.push_back(*it);
00979                 CvMat* sample = 0;
00980                 extract_intensity_features(grey, temp, &sample);
00981                 float prob = rtrees->predict_prob(sample);
00982                 if(prob > 350.0f)
00983                 {
00984                         outlet_feature_t feature;
00985                         feature.bbox = it->bbox;
00986                         feature.weight = prob;
00987                         filtered.push_back(feature);
00988                 }
00989         }
00990 
00991 //      cvNamedWindow("1", 1);
00992 //      cvShowImage("1", _temp);
00993 //      cvWaitKey();
00994 
00995 //      cvReleaseImage(&_temp);
00996 
00997         keypts = filtered;
00998 }
00999 
01000 void filter_outlets(IplImage* grey, vector<outlet_t>& outlets, CvRTrees* rtrees)
01001 {
01002         vector<outlet_t> filtered_outlets;
01003         vector<outlet_t>::const_iterator max_it;
01004         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01005         {
01006                 vector<outlet_feature_t> features;
01007                 outlet_feature_t feature;
01008                 feature.bbox = outlet_rect(*it);
01009                 features.push_back(feature);
01010                 CvMat* sample = 0;
01011                 extract_intensity_features(grey, features, &sample, 1);
01012                 float prob = rtrees->predict_prob(sample);
01013                 printf("outlet center = %d %d, prob = %f\n", feature.bbox.x + feature.bbox.width/2,
01014                            feature.bbox.y + feature.bbox.height/2, prob);
01015 #if 1
01016                 if(prob > 0.0f)
01017                 {
01018                         outlet_t outlet = *it;
01019                         outlet.weight = prob;
01020                         filtered_outlets.push_back(outlet);
01021                 }
01022         }
01023 #else
01024                 if(prob > max_prob)
01025                 {
01026                         max_prob = prob;
01027                         max_it = it;
01028                 }
01029         }
01030 
01031         if(max_prob > 0)
01032         {
01033                 filtered_outlets.push_back(*max_it);
01034         }
01035 
01036 #endif
01037         outlets = filtered_outlets;
01038 }
01039 
01040 
01041 void find_outlet_features_fast(IplImage* src, vector<outlet_feature_t>& features, float hole_contrast,
01042                                const char* output_path, const char* filename)
01043 {
01044         const float min_intersect = 1;//0.2;
01045 
01046         //cvErode(src, src);
01047         IplImage* grey = 0;
01048 
01049         if(src->nChannels == 3)
01050         {
01051                 grey = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
01052 
01053 #if _USE_OUTLET_TUPLE
01054                 cvSetImageCOI(src, 3);
01055                 cvCopy(src, grey);
01056 //              cvConvertScale(grey, grey, 0.4);
01057 #else
01058                 cvCvtColor(src, grey, CV_RGB2GRAY);
01059 #endif
01060         }
01061         else
01062         {
01063                 grey = src;
01064         }
01065 
01066         cvSmooth(grey, grey);
01067 
01068         IplImage* mask = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
01069 
01070         IplImage* mask_black = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
01071         IplImage* mask_white = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
01072         IplImage* imgfeat = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
01073         cvSetZero(imgfeat);
01074 
01075         CvMemStorage* storage = cvCreateMemStorage();
01076 
01077         IplImage* imgholes = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 3);
01078         for(int coi = 1; coi < 4; coi++)
01079         {
01080                 cvSetImageCOI(imgholes, coi);
01081                 cvCopy(grey, imgholes);
01082         }
01083         cvSetImageCOI(imgholes, 0);
01084 
01085 #if !defined(_TUNING)
01086         for(int thresh = 20; thresh < 170; thresh += 20)
01087 #else
01088         for(int thresh = 30; thresh < 170; thresh += thresh < 20 ? 5: 10)
01089 #endif //_TUNING
01090                 {
01091                 cvSet(mask_black, cvScalar(255));
01092                 cvSet(mask_white, cvScalar(255));
01093                 IplImage* tempgrey = cvCloneImage(mask_white);
01094                 IplImage* tempmask = cvCloneImage(mask_white);
01095 
01096 #if 0
01097                 for(int coi = 1; coi < 4; coi++)
01098                 {
01099                         cvSetImageCOI(src, coi);
01100                         cvCopy(src, tempgrey);
01101                         cvThreshold(tempgrey, tempmask, thresh, 255, CV_THRESH_BINARY_INV);
01102                         cvAnd(mask_black, tempmask, mask_black);
01103 
01104                         cvThreshold(tempgrey, tempmask, thresh, 255, CV_THRESH_BINARY);
01105                         cvAnd(mask_white, tempmask, mask_white);
01106                 }
01107 #else
01108                 cvThreshold(grey, mask_white, thresh, 255, CV_THRESH_BINARY);
01109                 cvThreshold(grey, mask_black, thresh, 255, CV_THRESH_BINARY_INV);
01110 #endif
01111                 cvSetImageCOI(src, 0);
01112                 cvNot(mask_black, mask_black);
01113 
01114 #if 0
01115                 cvAnd(mask_white, mask_black, tempgrey);
01116 //              cvRectangle(tempgrey, cvPoint(0, 0), cvPoint(tempmask->width-1, tempmask->height-1),
01117 //                                      cvScalar(0), 50);
01118                 printf("Processing thresh = %d\n", thresh);
01119                 cvNamedWindow("1", 1);
01120                 cvShowImage("1", tempgrey);
01121                 cvWaitKey(0);
01122 #endif
01123                 //cvCopy(src, temp);
01124                 cvReleaseImage(&tempgrey);
01125 
01126                 cvAnd(mask_white, mask_black, tempmask);
01127 //              cvRectangle(tempmask, cvPoint(0, 0), cvPoint(tempmask->width-1, tempmask->height-1),
01128 //                                      cvScalar(0), 50);
01129                 CvSeq* first = 0;
01130                 cvFindContours(tempmask, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
01131 
01132                 for(CvSeq* seq = first; seq != 0; seq = seq->h_next)
01133                 {
01134 //                      if(seq->total < 20)
01135 //                      {
01136 //                              continue;
01137 //                      }
01138                         CvRect rect = cvBoundingRect(seq);
01139                         if(rect.width < 40 || rect.height < 40)
01140                         {
01141                                 continue;
01142                         }
01143 
01144                         CvSeq* outlet = seq;
01145 
01146                         int holes_count = 0;
01147                         for(CvSeq* seqhole = outlet->v_next; seqhole != NULL; seqhole = seqhole->h_next, holes_count++);
01148                         if(holes_count < 2)
01149                         {
01150                                 continue;
01151                         }
01152 
01153 
01154                         vector<CvSeq*> holes;
01155                         find_hole_candidates(grey, mask, outlet, hole_contrast, holes);
01156 
01157                         for(vector<CvSeq*>::iterator it = holes.begin(); it != holes.end(); it++)
01158                         {
01159                                 CvRect roi = cvBoundingRect(*it);
01160 
01161 #if 0
01162                                 if(abs(roi.x - 56) < 5 && abs(roi.y - 189) < 5)
01163                                 {
01164                                         int w = 1;
01165                                 }
01166 #endif
01167 
01168 //                              float scale_factor = MAX(2.0f, 2*min_pixel_area/roi.width);
01169 //                              roi = resize_rect(roi, scale_factor);
01170                                 cvSetImageROI(imgfeat, roi);
01171                                 float avg = cvAvg(imgfeat).val[0];
01172                                 cvResetImageROI(imgfeat);
01173                                 if(avg < min_intersect)
01174                                 {
01175                                         outlet_feature_t feature;
01176                                         feature.bbox = roi;
01177                                         features.push_back(feature);
01178 
01179                                         cvDrawContours(imgfeat, *it, cvScalar(255), cvScalar(255), 0, CV_FILLED);
01180                                 }
01181                         }
01182                         cvResetImageROI(imgfeat);
01183 
01184                         for(vector<outlet_feature_t>::iterator it = features.begin(); it != features.end(); it++)
01185                         {
01186                                 cvRectangle(imgholes, it->bbox, CV_RGB(0, 0, 255), 1);
01187                                 //cvCircle(imgholes, cvPoint(it->bbox.x, it->bbox.y), 2, CV_RGB(0, 0, 255));
01188                         }
01189 
01190                 }
01191 
01192 #if 0
01193                 cvNamedWindow("1", 1);
01194                 cvShowImage("1", imgholes);
01195                 cvWaitKey(0);
01196                 cvSaveImage("mask.jpg", imgholes);
01197 #endif
01198                 cvReleaseImage(&tempmask);
01199         }
01200         /*
01201          cvNamedWindow("1", 0);
01202          cvSImage("1", temp);
01203          cvWaitKey(0);
01204          */
01205 
01206         // filtering with canny
01207 #if 0
01208         filter_canny(grey, features);
01209 #endif
01210 
01211         char buf[1024];
01212 
01213 #if defined(_VERBOSE)
01214         if(output_path && filename)
01215         {
01216                 sprintf(buf, "%s/holes/%s", output_path, filename);
01217                 cvSaveImage(buf, imgholes);
01218         }
01219 #endif //_VERBOSE
01220 
01221         if(src->nChannels == 3)
01222         {
01223                 cvReleaseImage(&grey);
01224         }
01225         cvReleaseImage(&mask);
01226 
01227         cvReleaseImage(&mask_black);
01228         cvReleaseImage(&mask_white);
01229         cvReleaseImage(&imgholes);
01230         cvReleaseImage(&imgfeat);
01231         cvReleaseMemStorage(&storage);
01232 }
01233 
01234 int is_outlet_inside_roi(const outlet_roi_t& outlet_roi, outlet_t outlet, string img_name)
01235 {
01236         map<string, vector<CvRect> >::const_iterator it = outlet_roi.find(img_name);
01237         if(it == outlet_roi.end())
01238         {
01239                 // no element with such a name
01240                 return 0;
01241         }
01242 
01243         int ret1 = is_point_inside_roi(it->second, outlet.hole1);
01244         int ret2 = is_point_inside_roi(it->second, outlet.hole2);
01245 
01246         return ret1 && ret2;
01247 }
01248 
01249 int generate_outlet_samples(IplImage* grey, outlet_t outlet, int count, CvMat** predictors, const char* filename)
01250 {
01251         IplImage** patches = new IplImage*[count];
01252         CvRect roi = outlet_rect(outlet);
01253         cvSetImageROI(grey, roi);
01254         gen_random_homog_patches(grey, count, patches);
01255         cvResetImageROI(grey);
01256         save_image_array("../../patches", filename, count, patches);
01257 
01258         int outlet_count = 0;
01259         for(int i = 0; i < count; i++)
01260         {
01261 #if 0
01262                 outlet_feature_t feature;
01263                 feature.bbox = cvRect(0, 0, patches[i]->width, patches[i]->height);
01264                 vector<outlet_feature_t> features;
01265                 features.push_back(feature);
01266                 extract_intensity_features(patches[i], features, predictors);
01267 #else
01268                 vector<outlet_feature_t> features;
01269                 vector<outlet_t> outlets;
01270                 IplImage* color = cvCreateImage(cvSize(patches[i]->width, patches[i]->height), IPL_DEPTH_8U, 3);
01271                 cvCvtColor(patches[i], color, CV_GRAY2RGB);
01272                 detect_outlets(color, features, outlets, 0, 0, filename);
01273                 if(outlets.size() > 0)
01274                 {
01275                         outlet_feature_t feature;
01276                         feature.bbox = outlet_rect(outlets[0]);
01277                         vector<outlet_feature_t> features;
01278                         features.push_back(feature);
01279                         extract_intensity_features(patches[i], features, predictors);
01280                         outlet_count++;
01281                 }
01282                 else
01283                 {
01284                         continue;
01285                 }
01286 #endif
01287         }
01288 
01289 
01290         // releasing image patches
01291         for(int i = 0; i < count; i++)
01292         {
01293                 cvReleaseImage(&patches[i]);
01294         }
01295         delete []patches;
01296 
01297         return(outlet_count);
01298 }
01299 
01300 void train_outlet_model(const char* path, const char* config_filename,
01301                                                 const char* roi_filename, const char* forest_filename)
01302 {
01303         const int samples_per_outlet = 30;
01304         outlet_roi_t outlet_roi;
01305         read_outlet_roi(roi_filename, outlet_roi);
01306 
01307         CvMat* predictors = 0;
01308         vector<int> labels;
01309 
01310         FILE* fp = fopen(config_filename, "rt");
01311         char buf[1024];
01312         int class_id;
01313         int ret;
01314         while((ret=fscanf(fp, "%d %s\n", &class_id, buf)) > 0)
01315         {
01316                 printf("Processing file %s...", buf);
01317 
01318                 char filename[1024];
01319                 sprintf(filename, "%s/%s", path, buf);
01320                 IplImage* src = cvLoadImage(filename);
01321                 IplImage* grey = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
01322                 cvCvtColor(src, grey, CV_RGB2GRAY);
01323 
01324                 vector<outlet_feature_t> features;
01325                 vector<outlet_t> outlets;
01326                 detect_outlets(src, features, outlets, 0, 0, buf);
01327 
01328                 // now transform outlets into features and calculate labels
01329                 for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01330                 {
01331                         CvRect orect = outlet_rect(*it);
01332                         outlet_feature_t feature;
01333                         feature.bbox = orect;
01334                         vector<outlet_feature_t> f;
01335                         f.push_back(feature);
01336                         int outlet_count = generate_outlet_samples(grey, *it, samples_per_outlet, &predictors, buf);
01337 
01338                         int outlet_class = class_id == 1 && is_outlet_inside_roi(outlet_roi, *it, string(buf));
01339                         labels.insert(labels.end(), outlet_count, outlet_class);
01340                 }
01341 
01342 #if defined(_VERBOSE)
01343                 DrawKeypoints(src, features);
01344                 sprintf(filename, "../../keyout/%s", buf);
01345                 cvSaveImage(filename, src);
01346 #endif //_VERBOSE
01347 
01348                 cvReleaseImage(&grey);
01349                 cvReleaseImage(&src);
01350 
01351                 printf("done.\n");
01352         }
01353 
01354         CvMat* labels_mat = vector2mat(labels);
01355 
01356         printf("Training RF model...");
01357         CvRTrees* rtrees = train_rf(predictors, labels_mat);
01358         printf("done.\n");
01359 
01360         rtrees->save("../../outlet_forest.xml");
01361 }
01362 
01363 void write_pr(const char* pr_filename, const char* image_filename, const outlet_roi_t& outlet_roi,
01364         const vector<outlet_t>& outlets)
01365 {
01366         FILE* fp = fopen(pr_filename, "at");
01367 
01368         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01369         {
01370                 // determine outlet class
01371                 int class_id = is_outlet_inside_roi(outlet_roi, *it, image_filename);
01372                 float weight = MIN(it->feature1.weight, it->feature2.weight);//it->weight
01373                 fprintf(fp, "%s,%d,%f,%d,%d\n", image_filename, class_id, weight, (it->hole1.x + it->hole2.x)/2,
01374                                 (it->hole1.y + it->hole2.y)/2);
01375         }
01376 
01377         fclose(fp);
01378 }
01379 
01380 void filter_negative_samples(const vector<CvRect>& rects, vector<outlet_feature_t>& keypts, float fraction)
01381 {
01382         vector<int> labels;
01383         calc_labels(rects, keypts, labels);
01384         vector<outlet_feature_t> filtered_keypts;
01385         for(unsigned int i = 0; i < labels.size(); i++)
01386         {
01387                 if(labels[i] == 1 || float(rand())/RAND_MAX < fraction) // leaving fraction negative samples
01388                 {
01389                         filtered_keypts.push_back(keypts[i]);
01390                         continue;
01391                 }
01392         }
01393 
01394         keypts = filtered_keypts;
01395 }
01396 
01397 void calc_contrast_factor(IplImage* grey, CvRect rect, float& contrast, float& variation)
01398 {
01399         CvPoint center = cvPoint(rect.x + rect.width/2,
01400                                                          rect.y + rect.height/2);
01401         int scale = MAX(rect.width/2, rect.height/2);
01402         rect = cvRect(center.x - scale, center.y - scale, 2*scale, 2*scale);
01403         rect = resize_rect(rect, 1.5f);
01404         rect = fit_rect(rect, grey);
01405 
01406         int Ic = (unsigned char)grey->imageData[center.y*grey->widthStep + center.x];
01407         int I[4];
01408         I[0] = (unsigned char)grey->imageData[rect.y*grey->widthStep + rect.x];
01409         I[1] = (unsigned char)grey->imageData[(rect.y + rect.height)*grey->widthStep + rect.x];
01410         I[2] = (unsigned char)grey->imageData[(rect.y + rect.height)*grey->widthStep + rect.x + rect.width];
01411         I[3] = (unsigned char)grey->imageData[rect.y*grey->widthStep + rect.x + rect.width];
01412         int minI = 65535;
01413         int maxI = 0;
01414         int avgI = 0;
01415         for(int i = 0; i < 4; i++)
01416         {
01417                 minI = MIN(minI, I[i]);
01418                 maxI = MAX(maxI, I[i]);
01419                 avgI += I[i];
01420         }
01421         avgI /= 4;
01422 
01423         contrast = float(avgI)/Ic;
01424         variation = float(maxI - minI)/maxI;
01425 }
01426 
01427 bool outlet_orient_pred_greater(outlet_t outlet1, outlet_t outlet2)
01428 {
01429         return outlet1.weight_orient > outlet2.weight_orient;
01430 }
01431 
01432 bool outlet_orient_pred_dist_greater(outlet_t outlet1, outlet_t outlet2)
01433 {
01434         return outlet1.feature1.weight + outlet1.feature2.weight >
01435                 outlet2.feature1.weight + outlet2.feature2.weight;
01436 }
01437 
01438 void select_central_outlets(vector<outlet_t>& outlets, int count)
01439 {
01440         sort(outlets.begin(), outlets.end(), outlet_orient_pred_dist_greater);
01441         count = MIN(count, (int)outlets.size());
01442         outlets = vector<outlet_t>(outlets.begin(), outlets.begin() + count);
01443 }
01444 
01445 void select_orient_outlets(CvPoint2D32f orientation, vector<outlet_t>& outlets, int count)
01446 {
01447         // normalize the vector of horizontal direction
01448         float mod = sqrt(orientation.x*orientation.x + orientation.y*orientation.y);
01449         orientation.x /= mod;
01450         orientation.y /= mod;
01451 
01452         // filter out non-horizontal outlets
01453         vector<outlet_t> filtered_outlets;
01454         const float min_product = cos(pi*10/180);
01455         for(vector<outlet_t>::iterator it = outlets.begin(); it != outlets.end(); it++)
01456         {
01457                 CvPoint2D32f outlet_dir = cvPoint2D32f(it->hole2.x - it->hole1.x, it->hole2.y - it->hole1.y);
01458                 float outlet_mod = sqrt(outlet_dir.x*outlet_dir.x + outlet_dir.y*outlet_dir.y);
01459                 outlet_dir.x /= outlet_mod;
01460                 outlet_dir.y /= outlet_mod;
01461 
01462                 float product = outlet_dir.x*orientation.x + outlet_dir.y*orientation.y;
01463                 it->weight_orient = product;
01464                 if(count == 0 && product > min_product)
01465                 {
01466                         filtered_outlets.push_back(*it);
01467                 }
01468         }
01469 
01470         if(count == 0)
01471         {
01472                 outlets = filtered_outlets;
01473                 return;
01474         }
01475 
01476         sort(outlets.begin(), outlets.end(), outlet_orient_pred_greater);
01477         count = MIN(count, (int)outlets.size());
01478         outlets = vector<outlet_t>(outlets.begin(), outlets.begin() + count);
01479 }
01480 
01481 int select_orient_outlets_ex(IplImage* grey, vector<outlet_t>& outlets, const char* filename)
01482 {
01483 #if 0
01484         cvNamedWindow("1", 1);
01485         cvShowImage("1", grey);
01486         cvWaitKey(0);
01487 #endif
01488 
01489 #if 0
01490         int ret = cvFindChessboardCorners(grey, cvSize(board_width, board_height),
01491                                                                           corners, &corners_found);
01492 
01493         printf("ret = %d\n", ret);
01494         if(ret == 0)
01495         {
01496                 return 0;
01497         }
01498 
01499         // find horizonal direction
01500         CvPoint2D32f hor_dir = cvPoint2D32f(corners[4].x - corners[0].x, corners[4].y - corners[0].y);
01501 #else
01502         CvPoint2D32f hor_dir;
01503         char buf[1024];
01504         sprintf(buf, "../../../images/us_outlets_hr/%s", filename);
01505         strcpy(buf + strlen(buf) - 3, "txt");
01506         FILE* fp = fopen(buf, "rt");
01507         if(fp != 0)
01508         {
01509                 int xdir = -1, ydir = -1;
01510                 fscanf(fp, "%d %d\n", &xdir, &ydir);
01511                 fclose(fp);
01512                 hor_dir = cvPoint2D32f(xdir, ydir);
01513         }
01514         else
01515         {
01516                 printf("File %s not found...\n", buf);
01517                 return 0;
01518         }
01519 
01520 #endif
01521 
01522         select_orient_outlets(hor_dir, outlets);
01523 
01524         return 1;
01525 }
01526 
01527 void draw_outlets(IplImage* temp, const vector<outlet_t>& outlets)
01528 {
01529         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01530         {
01531         CvPoint hole1 = it->is_subpixel ? cvPoint(floor(it->hole1f.x), floor(it->hole1f.y)) : it->hole1;
01532         CvPoint hole2 = it->is_subpixel ? cvPoint(floor(it->hole2f.x), floor(it->hole2f.y)) : it->hole2;
01533         CvPoint hole_ground = it->is_subpixel ? CvPoint(it->hole_groundf) : it->ground_hole;
01534         CvScalar red_color = CV_RGB(255, 0, 0);
01535         CvScalar blue_color = CV_RGB(0, 0, 255);
01536 
01537                 cvCircle(temp, hole1, 1, it->hole1_detected ? red_color : blue_color, CV_FILLED);
01538                 cvCircle(temp, hole2, 1, it->hole2_detected ? red_color : blue_color, CV_FILLED);
01539         cvCircle(temp, hole_ground, 1, it->ground_hole_detected ? red_color : blue_color, CV_FILLED);
01540 //              cvLine(temp, hole1, hole2, CV_RGB(0, 0, 255), 2);
01541                 //CvRect orect = outlet_rect(*it);
01542                 //cvRectangle(temp, orect, CV_RGB(0, 255, 0), 2);
01543         }
01544 }
01545 
01546 void filter_canny(IplImage* grey, vector<outlet_feature_t>& features)
01547 {
01548         const int max_size = 100;
01549         const float min_dist = 10;
01550 
01551         IplImage* canny = cvCloneImage(grey);
01552         cvCanny(grey, canny, 20, 40);
01553 
01554         IplImage* canny1 = cvCloneImage(canny);
01555         CvMemStorage* storage = cvCreateMemStorage();
01556         CvSeq* first = 0;
01557         cvFindContours(canny1, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
01558         for(CvSeq* seq = first; seq != 0; seq = seq->h_next)
01559         {
01560                 CvRect rect = cvBoundingRect(seq);
01561                 if(MAX(rect.width, rect.height) < max_size && seq->total < max_size)
01562                 {
01563                         cvDrawContours(canny, seq, cvScalar(0), cvScalar(0), 0, CV_FILLED);
01564                 }
01565         }
01566 
01567 /*      cvCopy(canny, canny1);
01568         for(vector<outlet_feature_t>::const_iterator it = features.begin(); it != features.end(); it++)
01569         {
01570                 cvRectangle(canny1, it->bbox, cvScalar(255), 1);
01571         }
01572         cvNamedWindow("1", 1);
01573         cvShowImage("1", canny1);
01574         cvWaitKey(0);
01575 */
01576         for(int i = 0; i < min_dist; i++)
01577         {
01578                 cvDilate(canny, canny);
01579         }
01580         vector<outlet_feature_t> filtered;
01581         for(vector<outlet_feature_t>::const_iterator it = features.begin(); it != features.end(); it++)
01582         {
01583                 CvPoint center = cvPoint(it->bbox.x + it->bbox.width/2, it->bbox.y + it->bbox.height/2);
01584                 if(canny->imageData[center.y*canny->widthStep + center.x] == 0)
01585                 {
01586                         filtered.push_back(*it);
01587                 }
01588         }
01589 
01590         features = filtered;
01591 }
01592 
01593 IplImage* load_match_template_mask(const char* filename)
01594 {
01595         char buf[1024];
01596         sprintf(buf, "../../../rectify_outlets/mask/%s", filename);
01597         strcpy(buf + strlen(buf) - 3, "jpg");
01598         IplImage* mask = cvLoadImage(buf);
01599         return(mask);
01600 }
01601 
01602 int load_homography_map(const char* filename, CvMat** map_matrix)
01603 {
01604         char buf[1024];
01605         sprintf(buf, "../../../rectify_outlets/homography/%s", filename);
01606         strcpy(buf + strlen(buf) - 3, "xml");
01607         *map_matrix = (CvMat*)cvLoad(buf);
01608         if(*map_matrix == 0)
01609         {
01610                 return 0;
01611         }
01612         else
01613         {
01614                 return 1;
01615         }
01616 }
01617 
01618 void filter_outlets_templ_ex(vector<outlet_t>& outlets, CvMat* map_matrix, IplImage* mask)
01619 {
01620         const int outlet_width = 50; // hack, should be updated each time a template size is changed
01621         const int outlet_height = 25;
01622 
01623         vector<outlet_t> filtered;
01624         CvMat* src = cvCreateMat(1, 1, CV_32FC2);
01625         CvMat* dst = cvCreateMat(1, 1, CV_32FC2);
01626 
01627         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01628         {
01629                 CvPoint2D32f center = cvPoint2D32f((it->hole1.x + it->hole2.x)*0.5f, (it->hole1.y + it->hole2.y)*0.5f);
01630 
01631                 // map center point to the mask
01632                 src->data.fl[0] = center.x;
01633                 src->data.fl[1] = center.y;
01634                 cvPerspectiveTransform(src, dst, map_matrix);
01635                 CvPoint mapped_center = cvPoint((int)dst->data.fl[0] - outlet_width/2, (int)dst->data.fl[1] - outlet_height/2);
01636                 if(is_point_inside_rect(cvRect(0, 0, mask->width, mask->height), mapped_center) &&
01637                    mask->imageData[mapped_center.y*mask->widthStep + mapped_center.x])
01638                 {
01639                         filtered.push_back(*it);
01640                 }
01641 
01642         }
01643 
01644         cvReleaseMat(&src);
01645         cvReleaseMat(&dst);
01646 
01647         outlets = filtered;
01648 }
01649 
01650 // uses template matching, currently done offline
01651 int filter_outlets_templ(vector<outlet_t>& outlets, const char* filename)
01652 {
01653         // load mask and homography
01654         IplImage* mask = load_match_template_mask(filename);
01655         if(mask == 0)
01656         {
01657                 printf("Homography mask not found for image %s\n", filename);
01658                 return 0;
01659         }
01660         cvThreshold(mask, mask, 128, 255, CV_THRESH_BINARY);
01661         cvDilate(mask, mask, 0, 2);
01662 
01663         CvMat* map_matrix = 0;
01664         int ret = load_homography_map(filename, &map_matrix);
01665         if(ret == 0)
01666         {
01667                 printf("Matrix not found for image %s\n", filename);
01668                 return 0;
01669         }
01670 
01671         filter_outlets_templ_ex(outlets, map_matrix, mask);
01672 
01673         cvReleaseImage(&mask);
01674         cvReleaseMat(&map_matrix);
01675 
01676         return 1;
01677 }
01678 
01679 CvPoint3D32f map_point_rt(CvPoint3D32f point, CvMat* rotation_mat, CvMat* translation_vector)
01680 {
01681         CvMat* _point = cvCreateMat(3, 1, CV_32FC1);
01682         cvmSet(_point, 0, 0, point.x);
01683         cvmSet(_point, 1, 0, point.y);
01684         cvmSet(_point, 2, 0, point.z);
01685 
01686         CvMat* _res = cvCreateMat(3, 1, CV_32FC1);
01687 
01688         cvMatMulAdd(rotation_mat, _point, translation_vector, _res);
01689 
01690         CvPoint3D32f res = cvPoint3D32f(cvmGet(_res, 0, 0), cvmGet(_res, 1, 0), cvmGet(_res, 2, 0));
01691 
01692     cvReleaseMat(&_res);
01693     cvReleaseMat(&_point);
01694 
01695         return res;
01696 }
01697 
01698 void getImagePoints(const std::vector<outlet_t>& outlets, std::vector<cv::Point2f>& image_points, std::vector<bool>& is_detected)
01699 {
01700     const int point_count = outlets.size()*3;
01701     image_points.resize(point_count);
01702     is_detected.resize(point_count);
01703 
01704     for(size_t i = 0; i < outlets.size(); i++)
01705     {
01706         image_points[3*i] = outlets[i].is_subpixel ? outlets[i].hole1f : cv::Point2f(outlets[i].hole1);
01707         is_detected[3*i] = outlets[i].hole1_detected;
01708 
01709         image_points[3*i + 1] = outlets[i].is_subpixel ? outlets[i].hole2f : cv::Point2f(outlets[i].hole2);
01710         is_detected[3*i + 1] = outlets[i].hole2_detected;
01711 
01712         image_points[3*i + 2] = outlets[i].is_subpixel ? outlets[i].hole_groundf : cv::Point2f(outlets[i].ground_hole);
01713         is_detected[3*i + 2] = outlets[i].ground_hole_detected;
01714     }
01715 }
01716 
01717 void estimateCameraPosition(const vector<cv::Point2f>& image_points, const vector<cv::Point3f>& object_points,
01718                         CvMat* intrinsic_matrix, CvMat* distortion_params, CvMat* rotation_vector, CvMat* translation_vector)
01719 {
01720     int point_count = image_points.size();
01721     CvMat* object_mat = cvCreateMat(point_count, 3, CV_32FC1);
01722     CvMat* image_mat = cvCreateMat(point_count, 2, CV_32FC1);
01723 
01724     for(int i = 0; i < point_count; i++)
01725     {
01726         cvmSet(object_mat, i, 0, object_points[i].x);
01727         cvmSet(object_mat, i, 1, object_points[i].y);
01728         cvmSet(object_mat, i, 2, object_points[i].z);
01729 
01730         cvmSet(image_mat, i, 0, image_points[i].x);
01731         cvmSet(image_mat, i, 1, image_points[i].y);
01732     }
01733 
01734 
01735     cvFindExtrinsicCameraParams2(object_mat, image_mat, intrinsic_matrix, distortion_params,
01736                                  rotation_vector, translation_vector);
01737 
01738     cvReleaseMat(&object_mat);
01739     cvReleaseMat(&image_mat);
01740 }
01741 
01742 void calc_outlet_coords(CvMat* rotation_vector, CvMat* translation_vector, const vector<cv::Point3f>& object_points, vector<outlet_t>& outlets)
01743 {
01744     CvMat* rotation_mat = cvCreateMat(3, 3, CV_32FC1);
01745     cvRodrigues2(rotation_vector, rotation_mat);
01746 
01747     for(size_t j = 0; j < outlets.size(); j++)
01748     {
01749         outlets[j].coord_hole1 = map_point_rt(object_points[3*j], rotation_mat, translation_vector);
01750         outlets[j].coord_hole2 = map_point_rt(object_points[3*j + 1], rotation_mat, translation_vector);
01751         outlets[j].coord_hole_ground = map_point_rt(object_points[3*j + 2], rotation_mat, translation_vector);
01752     }
01753 
01754     cvReleaseMat(&rotation_mat);
01755 }
01756 
01757 void calc_outlet_coords(vector<outlet_t>& outlets, const outlet_template_t& outlet_template,
01758                         CvMat* intrinsic_matrix, CvMat* distortion_params)
01759 {
01760     int point_count = outlet_template.get_count()*3;
01761 
01762     std::vector<cv::Point3f> object_points;
01763     outlet_template.get_holes_3d(object_points);
01764 
01765     std::vector<cv::Point2f> image_points;
01766     std::vector<bool> is_detected;
01767     getImagePoints(outlets, image_points, is_detected);
01768 
01769     cv::Mat object_mat(point_count, 3, CV_32FC1);
01770     cv::Mat image_mat(point_count, 2, CV_32FC1);
01771 
01772     int row = 0;
01773     for(int i = 0; i < point_count; i++)
01774     {
01775         if(!is_detected[i]) continue;
01776         object_mat.at<float>(row, 0) = object_points[i].x;
01777         object_mat.at<float>(row, 1) = object_points[i].y;
01778         object_mat.at<float>(row, 2) = object_points[i].z;
01779 
01780         image_mat.at<float>(row, 0) = image_points[i].x;
01781         image_mat.at<float>(row, 1) = image_points[i].y;
01782 //        printf("image_points[%d]: %f,%f\n", i, image_points[i].x, image_points[i].y);
01783         row++;
01784     }
01785 
01786 
01787     cv::Mat rotation_vector(3, 1, CV_32FC1);
01788     CvMat _rotation_vector = rotation_vector;
01789     cv::Mat translation_vector(3, 1, CV_32FC1);
01790     CvMat _translation_vector = translation_vector;
01791 
01792     CvMat _object_mat = object_mat.rowRange(0, row);
01793     CvMat _image_mat = image_mat.rowRange(0, row);
01794     cvFindExtrinsicCameraParams2(&_object_mat, &_image_mat, intrinsic_matrix, distortion_params,
01795                                  &_rotation_vector, &_translation_vector);
01796 
01797     cv::Mat rotation_mat(3, 3, CV_32FC1);
01798     CvMat _rotation_mat = rotation_mat;
01799     cvRodrigues2(&_rotation_vector, &_rotation_mat);
01800 
01801     for(size_t j = 0; j < outlets.size(); j++)
01802     {
01803         outlets[j].coord_hole1 = map_point_rt(object_points[3*j], &_rotation_mat, &_translation_vector);
01804         outlets[j].coord_hole2 = map_point_rt(object_points[3*j + 1], &_rotation_mat, &_translation_vector);
01805         outlets[j].coord_hole_ground = map_point_rt(object_points[3*j + 2], &_rotation_mat, &_translation_vector);
01806 
01807     }
01808 }
01809 
01810 void calc_outlet_coords_ground(vector<outlet_t>& outlets, const outlet_template_t& outlet_template,
01811                         CvMat* intrinsic_matrix, CvMat* distortion_params)
01812 {
01813     int point_count = outlet_template.get_count()*3;
01814     CvPoint3D32f* object_points = new CvPoint3D32f[point_count];
01815     CvMat* object_mat = cvCreateMat(outlets.size(), 3, CV_32FC1);
01816     CvPoint2D32f* image_points = new CvPoint2D32f[point_count];
01817     CvMat* image_mat = cvCreateMat(outlets.size(), 2, CV_32FC1);
01818 
01819     outlet_template.get_holes_3d(object_points);
01820     for(int i = 2; i < point_count; i += 3)
01821     {
01822         cvmSet(object_mat, (i-2)/3, 0, object_points[i].x);
01823         cvmSet(object_mat, (i-2)/3, 1, object_points[i].y);
01824         cvmSet(object_mat, (i-2)/3, 2, object_points[i].z);
01825     }
01826 
01827     for(size_t j = 0; j < outlets.size(); j++)
01828     {
01829         cvmSet(image_mat, j, 0, outlets[j].ground_hole.x);
01830         cvmSet(image_mat, j, 1, outlets[j].ground_hole.y);
01831     }
01832 
01833     CvMat* rotation_vector = cvCreateMat(3, 1, CV_32FC1);
01834     CvMat* translation_vector = cvCreateMat(3, 1, CV_32FC1);
01835 
01836     cvFindExtrinsicCameraParams2(object_mat, image_mat, intrinsic_matrix, distortion_params,
01837                                  rotation_vector, translation_vector);
01838 
01839     CvMat* rotation_mat = cvCreateMat(3, 3, CV_32FC1);
01840     cvRodrigues2(rotation_vector, rotation_mat);
01841 
01842     for(size_t j = 0; j < outlets.size(); j++)
01843     {
01844         outlets[j].coord_hole1 = map_point_rt(object_points[3*j], rotation_mat, translation_vector);
01845         outlets[j].coord_hole2 = map_point_rt(object_points[3*j + 1], rotation_mat, translation_vector);
01846         outlets[j].coord_hole_ground = map_point_rt(object_points[3*j + 2], rotation_mat, translation_vector);
01847     }
01848 
01849     cvReleaseMat(&rotation_mat);
01850     cvReleaseMat(&rotation_vector);
01851     cvReleaseMat(&translation_vector);
01852     cvReleaseMat(&object_mat);
01853     cvReleaseMat(&image_mat);
01854     delete []object_points;
01855     delete []image_points;
01856 }
01857 
01858 
01859 int calc_outlet_coords(vector<outlet_t>& outlets, CvMat* map_matrix, CvPoint3D32f origin, CvPoint2D32f scale,
01860         CvMat* rotation_vector, CvMat* translation_vector, CvMat* inv_map_matrix)
01861 {
01862         // create rotation matrix
01863         CvMat* rotation_mat = cvCreateMat(3, 3, CV_32FC1);
01864         cvRodrigues2(rotation_vector, rotation_mat);
01865 
01866         // map outlets to rectified plane
01867         CvMat* src = cvCreateMat(1, 2, CV_32FC2);
01868         CvMat* dst = cvCreateMat(1, 2, CV_32FC2);
01869 
01870         for(vector<outlet_t>::iterator it = outlets.begin(); it != outlets.end(); it++)
01871         {
01872                 src->data.fl[0] = it->hole1.x;
01873                 src->data.fl[1] = it->hole1.y;
01874                 src->data.fl[2] = it->hole2.x;
01875                 src->data.fl[3] = it->hole2.y;
01876                 cvPerspectiveTransform(src, dst, map_matrix);
01877                 it->coord_hole1 = cvPoint3D32f((dst->data.fl[0] - origin.x)*scale.x,
01878                                                                            (dst->data.fl[1] - origin.y)*scale.y, -origin.z);
01879                 it->coord_hole2 = cvPoint3D32f((dst->data.fl[2] - origin.x)*scale.x,
01880                                                                            (dst->data.fl[3] - origin.y)*scale.y, -origin.z);
01881                 const float ground_hole_offset = 11.5; // mm
01882                 it->coord_hole_ground = cvPoint3D32f((it->coord_hole1.x + it->coord_hole2.x)*0.5f,
01883                                                                                          (it->coord_hole1.y + it->coord_hole2.y)*0.5f - ground_hole_offset,
01884                                                                                          0.0f);
01885 
01886 #if !defined(_GHT) // TBD somehow the inverse matrix here is corrupt when _GHT is defined
01887         if(inv_map_matrix)
01888         {
01889             // update ground hole image coordinates
01890             src->data.fl[0] = it->coord_hole_ground.x;
01891             src->data.fl[1] = it->coord_hole_ground.y;
01892             cvPerspectiveTransform(src, dst, inv_map_matrix);
01893             it->ground_hole = cvPoint(floor(dst->data.fl[0]), floor(dst->data.fl[1]));
01894         }
01895 #endif //_GHT
01896 
01897                 it->coord_hole1 = map_point_rt(it->coord_hole1, rotation_mat, translation_vector);
01898                 it->coord_hole2 = map_point_rt(it->coord_hole2, rotation_mat, translation_vector);
01899                 it->coord_hole_ground = map_point_rt(it->coord_hole_ground, rotation_mat, translation_vector);
01900         }
01901 
01902         cvReleaseMat(&src);
01903         cvReleaseMat(&dst);
01904 
01905         cvReleaseMat(&rotation_mat);
01906 
01907         return 1;
01908 }
01909 
01910 void calc_outlet_dist_stat(const vector<outlet_t>& outlets, float& mean, float& stddev)
01911 {
01912         float sum = 0;
01913         float sum2 = 0;
01914         // calculate the average distance between the holes
01915         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01916         {
01917                 float diff = length(it->coord_hole2 - it->coord_hole1);
01918                 sum += diff;
01919                 sum2 += diff*diff;
01920         }
01921         mean = sum/outlets.size();
01922         stddev = sqrt(sum2/outlets.size() - mean*mean);
01923 }
01924 
01925 void calc_outlet_tuple_dist_stat(const vector<outlet_t>& outlets, float& ground_dist_x1,
01926                                                                  float& ground_dist_x2, float& ground_dist_y)
01927 {
01928         if(outlets.size() < 4) return;
01929 
01930 //      CvPoint2D32f ground_holes[4];
01931 //      for(int i = 0; i < 4; i++)
01932 //      {
01933 //              CvPoint3D32f point = outlets[i].coord_hole_ground;
01934 //              ground_holes[i] = cvPoint2D32f(point.x, point.y);
01935 //      }
01936 
01937 //      order_tuple2(ground_holes); outlets are ordered before, no need to do it here!
01938 
01939         ground_dist_x1 = length(outlets[1].coord_hole_ground - outlets[0].coord_hole_ground);
01940         ground_dist_x2 = length(outlets[2].coord_hole_ground - outlets[3].coord_hole_ground);
01941         ground_dist_y = length(outlets[2].coord_hole_ground - outlets[1].coord_hole_ground);
01942 }
01943 
01944 int find_origin_chessboard(IplImage* src, CvMat* map_matrix, CvPoint3D32f& origin, float bar_length)
01945 {
01946         const int board_width = 6;
01947         const int board_height = 9;
01948         const int corners_count = 6*9;
01949         CvPoint2D32f corners[corners_count];
01950         int found_corners = 0;
01951         cvFindChessboardCorners(src, cvSize(board_width, board_height), corners, &found_corners);
01952         if(found_corners < 4*board_width)
01953         {
01954                 return 0;
01955         }
01956 
01957         CvMat* _src = cvCreateMat(1, 2, CV_32FC2);
01958         CvMat* _dst = cvCreateMat(1, 2, CV_32FC2);
01959         _src->data.fl[0] = corners[3*board_width].x;
01960         _src->data.fl[1] = corners[3*board_width].y;
01961         _src->data.fl[2] = corners[3*board_width + board_width - 1].x;
01962         _src->data.fl[3] = corners[3*board_width + board_width - 1].y;
01963         cvPerspectiveTransform(_src, _dst, map_matrix);
01964         origin = cvPoint3D32f(_dst->data.fl[0], _dst->data.fl[1], 0);
01965         bar_length = (_dst->data.fl[2] - _dst->data.fl[0])/(board_width - 1);
01966 
01967         return 0;
01968 }
01969 
01970 void filter_outlets_mask(vector<outlet_t>& outlets, IplImage* mask)
01971 {
01972         vector<outlet_t> filtered;
01973         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
01974         {
01975                 const outlet_t outlet = *it;
01976                 if(mask->imageData[it->hole1.y*mask->widthStep + it->hole1.x] != 0 &&
01977                    mask->imageData[it->hole2.y*mask->widthStep + it->hole2.x] != 0)
01978                 {
01979                         filtered.push_back(*it);
01980                 }
01981         }
01982 
01983         outlets = filtered;
01984 }
01985 
01986 void filter_features_mask(vector<outlet_feature_t>& features, IplImage* mask)
01987 {
01988         vector<outlet_feature_t> filtered;
01989         for(vector<outlet_feature_t>::const_iterator it = features.begin(); it != features.end(); it++)
01990         {
01991                 CvPoint center = cvPoint(it->bbox.x + it->bbox.width/2, it->bbox.y + it->bbox.height/2);
01992                 if(mask->imageData[mask->widthStep*center.y + center.x] != 0)
01993                 {
01994                         filtered.push_back(*it);
01995                 }
01996         }
01997 
01998         features = filtered;
01999 }
02000 
02001 IplImage* calc_tuple_distance_map(IplImage* tuple_mask)
02002 {
02003         IplImage* mask = cvCloneImage(tuple_mask);
02004 
02005         // create an image with tuple boundaries
02006 
02007         cvCopy(tuple_mask, mask);
02008 
02009         // calculate distance map
02010         IplImage* dist = cvCreateImage(cvSize(mask->width, mask->height), IPL_DEPTH_32F, 1);
02011         cvDistTransform(mask, dist);
02012 
02013         double minval, maxval;
02014         cvMinMaxLoc(dist, &minval, &maxval);
02015 
02016         cvReleaseImage(&mask);
02017 
02018         return dist;
02019 }
02020 
02021 void filter_features_distance_mask(vector<outlet_feature_t>& features, IplImage* distance_map)
02022 {
02023         vector<outlet_feature_t> filtered;
02024 
02025         const double dist_factor = 0.5;
02026         double dist_max = 0;
02027         cvMinMaxLoc(distance_map, 0, &dist_max);
02028         double dist_min = dist_max*dist_factor;
02029 
02030         for(vector<outlet_feature_t>::iterator it = features.begin(); it != features.end(); it++)
02031         {
02032                 CvPoint center = feature_center(*it);
02033                 float dist = *((float*)(distance_map->imageData + distance_map->widthStep*center.y) + center.x);
02034                 if(dist > dist_min)
02035                 {
02036                         it->weight = dist;
02037                         filtered.push_back(*it);
02038                 }
02039 
02040 #if 0
02041                 if(abs(center.x - 207) < 5 && abs(center.y - 185) < 5)
02042                 {
02043                         int w = 1;
02044                 }
02045 #endif
02046 
02047         }
02048 
02049         features = filtered;
02050 }
02051 
02052 int find_outlet_position(outlet_t outlet, IplImage* tuple_mask)
02053 {
02054         int idx1 = (unsigned char)tuple_mask->imageData[outlet.hole1.y*tuple_mask->widthStep + outlet.hole1.x];
02055         int idx2 = (unsigned char)tuple_mask->imageData[outlet.hole2.y*tuple_mask->widthStep + outlet.hole2.x];
02056 
02057         if(idx1 == idx2)
02058         {
02059                 return idx1;
02060         }
02061         else
02062         {
02063                 return -1;
02064         }
02065 }
02066 
02067 void filter_outlets_tuple(vector<outlet_t>& outlets, IplImage* tuple_mask, CvPoint2D32f hor_dir)
02068 {
02069         vector<outlet_t> filtered;
02070         vector<int> outlets_idx;
02071 
02072         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
02073         {
02074                 int idx = find_outlet_position(*it, tuple_mask);
02075                 outlets_idx.push_back(idx);
02076         }
02077 
02078         for(int i = 0; i < 4; i++)
02079         {
02080                 vector<outlet_t> candidates;
02081                 for(unsigned int j = 0; j < outlets.size(); j++)
02082                 {
02083                         if(outlets_idx[j] == i + 1)
02084                         {
02085                                 candidates.push_back(outlets[j]);
02086                         }
02087                 }
02088 
02089                 if(candidates.size() > 0)
02090                 {
02091 #if 0
02092                         select_orient_outlets(hor_dir, candidates, 2);
02093                         int idx = candidates[0].feature1.weight + candidates[0].feature2.weight >
02094                                 candidates[1].feature1.weight + candidates[1].feature2.weight ? 0 : 1;
02095                         filtered.push_back(candidates[0]);
02096 #else
02097                         select_central_outlets(candidates, 1);
02098                         filtered.push_back(candidates[0]);
02099 #endif
02100                 }
02101         }
02102 
02103         outlets = filtered;
02104 }
02105 
02106 void get_outlet_coordinates(const outlet_t& outlet, CvPoint3D32f* points)
02107 {
02108         points[1] = outlet.coord_hole1;
02109         points[2] = outlet.coord_hole2;
02110         points[0] = outlet.coord_hole_ground;
02111 }
02112 
02113 void filter_outlets_size(vector<outlet_t>& outlets)
02114 {
02115         const float outlet_length = 12.0f;
02116         const float outlet_length_min = outlet_length*0.8f;
02117         const float outlet_length_max = outlet_length/0.8f;
02118 
02119         vector<outlet_t> filtered;
02120         for(vector<outlet_t>::const_iterator it = outlets.begin(); it != outlets.end(); it++)
02121         {
02122                 float dist = length(it->coord_hole1 - it->coord_hole2);
02123                 if(dist > outlet_length_min && dist < outlet_length_max)
02124                 {
02125                         filtered.push_back(*it);
02126                 }
02127         }
02128 
02129         outlets = filtered;
02130 }
02131 
02132 CvRect getOutletROI(const vector<outlet_t>& outlets)
02133 {
02134     CvPoint pmin = cvPoint(1e10, 1e10);
02135     CvPoint pmax = cvPoint(-1e10, -1e10);
02136 
02137     for(size_t i = 0; i < outlets.size(); i++)
02138     {
02139         pmin.x = MIN(pmin.x, MIN(outlets[i].hole1.x, MIN(outlets[i].hole2.x,
02140           outlets[i].ground_hole.x)));
02141         pmin.y = MIN(pmin.y, MIN(outlets[i].hole1.y, MIN(outlets[i].hole2.y,
02142           outlets[i].ground_hole.y)));
02143         pmax.x = MAX(pmax.x, MAX(outlets[i].hole1.x, MAX(outlets[i].hole2.x,
02144           outlets[i].ground_hole.x)));
02145         pmax.y = MAX(pmax.y, MAX(outlets[i].hole1.y, MAX(outlets[i].hole2.y,
02146           outlets[i].ground_hole.y)));
02147     }
02148 
02149     CvRect roi = cvRect(pmin.x, pmin.y, pmax.x - pmin.x + 1, pmax.y - pmin.y + 1);
02150     return(roi);
02151 }
02152 
02153 void findPreciseOutletLocations(IplImage* grey, const outlet_template_t& outlet_template, vector<outlet_t>& outlets)
02154 {
02155     if(outlets.size() != 2)
02156     {
02157         printf("findPreciseHoleLocations: unsupported number of outlets\n");
02158         return;
02159     }
02160 
02161     const float outlet_hole_length_r = 9;
02162     const float outlet_hole_length_l = 7;
02163 
02164     std::vector<cv::Point3f> template_holes;
02165     outlet_template.get_holes_3d(template_holes);
02166     float holes_vert_dist_3d = length(template_holes[4] - template_holes[1]);
02167     cv::Point2f dir_l = cv::Point2f(outlets[0].hole1) - cv::Point2f(outlets[1].hole1);
02168     cv::Point2f dir_r = cv::Point2f(outlets[0].hole2) - cv::Point2f(outlets[1].hole2);
02169 
02170     dir_l = dir_l*(outlet_hole_length_l/holes_vert_dist_3d);
02171     dir_r = dir_r*(outlet_hole_length_r/holes_vert_dist_3d);
02172 
02173     float hole_width = 5;
02174     cv::Point2f dir_l_perp = cv::Point2f(-dir_l.y, dir_l.x)*(hole_width/outlet_hole_length_l);
02175     cv::Point2f dir_r_perp = cv::Point2f(-dir_r.y, dir_r.x)*(hole_width/outlet_hole_length_r);
02176 
02177     for(size_t i = 0; i < 2; i++)
02178     {
02179         cv::Point2f hole;
02180 
02181         findPrecisePowerHoleLocation(grey, outlets[i].hole1, dir_l, dir_l_perp, outlets[i].hole1f);
02182 
02183         findPrecisePowerHoleLocation(grey, outlets[i].hole2, dir_r, dir_r_perp, outlets[i].hole2f);
02184 
02185         findPreciseGroundHoleLocation(grey, outlets[i].ground_hole, outlets[i].hole_groundf);
02186 
02187         outlets[i].is_subpixel = true;
02188     }
02189 }
02190 
02191 float avgLine(IplImage* grey, cv::Point2f* line_ends)
02192 {
02193     CvLineIterator line_it;
02194     int count = cvInitLineIterator(grey, cv::Point(line_ends[0].x, line_ends[0].y), cv::Point(line_ends[1].x, line_ends[1].y), &line_it);
02195 
02196     float sum = 0;
02197     for(int i = 0; i < count; i++)
02198     {
02199         sum += line_it.ptr[0];
02200         CV_NEXT_LINE_POINT(line_it);
02201     }
02202 
02203     return sum/count;
02204 }
02205 
02206 void findPrecisePowerHoleLocation(IplImage* grey, cv::Point2f center, cv::Point2f dir, cv::Point2f dir_perp, cv::Point2f& hole)
02207 {
02208     const float d_step = 0.05f;
02209     const float d_perp_step = 0.2f;
02210     center += cv::Point2f(0.5f, 0.5f);
02211 
02212     float min_sum = 1e10;
02213     for(float d = 0; d < 1; d += d_step)
02214     {
02215         for(float d_perp = 0; d_perp < 1; d_perp += d_perp_step)
02216         {
02217             cv::Point2f p = center + dir*(d - 0.5f) + dir_perp*(d_perp - 0.5f);
02218             cv::Point2f line_ends[2];
02219             line_ends[0] = p - dir*0.5f;
02220             line_ends[1] = p + dir*0.5f;
02221 
02222             float sum = avgLine(grey, line_ends);
02223             if(sum < min_sum)
02224             {
02225                 min_sum = sum;
02226                 hole = p;
02227             }
02228         }
02229     }
02230 }
02231 
02232 void findPreciseGroundHoleLocation(IplImage* grey, cv::Point2f center, cv::Point2f& hole)
02233 {
02234 #if 0
02235     // for now, just return the original hole -- I didn't see any jitter in ground hole positions
02236     hole = center + cv::Point2f(0.5f, 0.5f);
02237 #else
02238     cv::Mat mask(grey->height + 2, grey->width + 2, CV_8UC1);
02239     IplImage _mask = mask;
02240     cvSetZero(&_mask);
02241     CvConnectedComp comp;
02242     const int color_offset = 10;
02243     CvRect roi = cvGetImageROI(&_mask);
02244 
02245     cvFloodFill(grey, CvPoint(center), cvScalar(255), cvScalar(color_offset), cvScalar(color_offset), &comp, 4 | CV_FLOODFILL_MASK_ONLY, &_mask);
02246     hole = cv::Point2f(comp.rect.x + float(comp.rect.width)/2, comp.rect.y + float(comp.rect.height)/2);
02247 #endif
02248 }
02249 
02250 void findPreciseOutletLocationsAvg(IplImage* grey, const outlet_template_t& outlet_template, vector<outlet_t>& outlets)
02251 {
02252     CvRect roi = cvGetImageROI(grey);
02253     cv::Mat mat(roi.height, roi.width, CV_8UC1);
02254     IplImage _mat = mat;
02255     CvRNG rng = cvRNG(0xffffffff);
02256 
02257     for(size_t i = 0; i < outlets.size(); i++)
02258     {
02259         outlets[i].hole1f = cv::Point2f(0.0f, 0.0f);
02260         outlets[i].hole2f = cv::Point2f(0.0f, 0.0f);
02261         outlets[i].hole_groundf = cv::Point2f(0.0f, 0.0f);
02262     }
02263 
02264     const int count = 50;
02265     vector<outlet_t> _outlets = outlets;
02266     for(int k = 0; k < count; k++)
02267     {
02268         cvRandArr(&rng, &_mat, CV_RAND_UNI, cvScalar(0), cvScalar(100));
02269 //        CvRect roi1 = cvGetImageROI(grey);
02270 //        CvRect roi2 = cvGetImageROI(&_mat);
02271 //        printf("roi input: %d,%d,%d,%d, roi rand: %d,%d,%d,%d\n",
02272 //            roi1.x, roi1.y, roi1.width, roi1.height,
02273 //            roi2.x, roi2.y, roi2.width, roi2.height);
02274         cvAdd(&_mat, grey, &_mat);
02275 
02276         findPreciseOutletLocations(&_mat, outlet_template, _outlets);
02277 
02278         for(size_t i = 0; i < outlets.size(); i++)
02279         {
02280             outlets[i].hole1f += _outlets[i].hole1f;
02281             outlets[i].hole2f += _outlets[i].hole2f;
02282             outlets[i].hole_groundf += _outlets[i].hole_groundf;
02283         }
02284     }
02285 
02286     for(size_t i = 0; i < outlets.size(); i++)
02287     {
02288         outlets[i].hole1f *= 1.0f/count;
02289         outlets[i].hole2f *= 1.0f/count;
02290         outlets[i].hole_groundf *= 1.0f/count;
02291 
02292         outlets[i].is_subpixel = true;
02293     }
02294 }
02295 
02296 cv::Point3f flipVector(cv::Point3f vec, cv::Point3f center)
02297 {
02298   double center_length = length(center);
02299   cv::Point3f flipped = vec - center*float((center.dot(vec - center)/(center_length*center_length)));
02300   return flipped;
02301 }
02302 
02303 void flipOutlet(std::vector<outlet_t>& outlets)
02304 {
02305   if(outlets.size() != 2) return; // implemented for 2x1 outlet tuple only
02306   if(length(outlets[0].coord_hole_ground) < length(outlets[1].coord_hole_ground)) return; // the pose is correct
02307 
02308   //printf("FLIPPING OUTLET POSE\n");
02309   // otherwise, flip outlet pose
02310   cv::Point3f center(0.0, 0.0, 0.0);
02311 #if 0
02312   for(size_t i = 0; i < outlets.size(); i++)
02313   {
02314     center = center + outlets[i].coord_hole1 + outlets[i].coord_hole2 + outlets[i].coord_hole_ground;
02315   }
02316   center = center*(1.0f/3/outlets.size());
02317 #else
02318   center = outlets[0].coord_hole_ground;
02319 #endif
02320 
02321   for(size_t i = 0; i < outlets.size(); i++)
02322   {
02323 //    int sign = i == 0 ? -1 : 1;
02324     outlets[i].coord_hole_ground = flipVector(outlets[i].coord_hole_ground, center);
02325     outlets[i].coord_hole1 = flipVector(outlets[i].coord_hole1, center);
02326     outlets[i].coord_hole2 = flipVector(outlets[i].coord_hole2, center);
02327   }
02328 }


outlet_pose_estimation
Author(s): Patrick Mihelich
autogenerated on Mon Dec 2 2013 13:21:49