Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

BallDetectionGenerator.cc

Go to the documentation of this file.
00001 #include "BallDetectionGenerator.h"
00002 #include "Events/EventRouter.h"
00003 #include "Shared/Util.h"
00004 #include "Wireless/Wireless.h"
00005 #include "Shared/Config.h"
00006 #include "Events/VisionObjectEvent.h"
00007 #include "Shared/Profiler.h"
00008 
00009 #include "Vision/SegmentedColorGenerator.h"
00010 #include "Vision/RegionGenerator.h"
00011 typedef RegionGenerator::region region; //!< shorthand - using CMVision regions
00012 typedef SegmentedColorGenerator::color_class_state color_class_state; //!< shorthand - using CMVision color structs
00013 
00014 BallDetectionGenerator::BallDetectionGenerator(unsigned int mysid, const RegionGenerator * rg, unsigned int colorIdx, unsigned int threshmapChan, unsigned int noiseFiltering, float confidence)
00015   : EventGeneratorBase("BallDetectionGenerator",EventBase::visObjEGID,mysid,rg->getGeneratorID(),rg->getSourceID(),EventBase::statusETID), clrIdx(colorIdx), tmIdx(threshmapChan), ball(), present(false), count(0), noiseThreshold(noiseFiltering), confidenceThreshold(confidence)
00016 {}
00017 
00018 void
00019 BallDetectionGenerator::doEvent() {
00020   PROFSECTION("BallDetection::doEvent()",*mainProfiler);
00021   EventGeneratorBase::doEvent();
00022   if(event->getGeneratorID()!=getListenGeneratorID() || event->getSourceID()!=getListenSourceID())
00023     return;
00024 
00025   const SegmentedColorFilterBankEvent * segev=dynamic_cast<const SegmentedColorFilterBankEvent*>(event);
00026   if(NULL==segev) {
00027     serr->printf("BallDetectionGenerator's event %s was not a SegmentedColorFilterBankEvent",event->getName().c_str());
00028     return;
00029   }
00030   
00031   static const bool debug_ball = false;
00032   static const bool debug_conf = false;
00033 
00034   static int frame_cnt=0;
00035   static const int print_period=1;
00036 
00037   if(debug_ball)
00038     frame_cnt = (frame_cnt + 1) % print_period;
00039 
00040   unsigned int layer=segev->getNumLayers()-config->vision.resolution-1;
00041   if(segev->getNumColors()<=clrIdx) {
00042     serr->printf("BallDetectionGenerator::clrIdx %d is invalid (only %d available)\n",clrIdx,segev->getNumColors());
00043     return;
00044   }
00045   if(segev->getNumChannels()<=tmIdx) {
00046     serr->printf("BallDetectionGenerator::tmIdx %d is invalid (only %d available)\n",tmIdx,segev->getNumChannels());
00047     return;
00048   }
00049   if(segev->getNumLayers()<=layer) {
00050     serr->printf("BallDetectionGenerator's selected layer %d is invalid (only %d available)\n",layer,segev->getNumLayers());
00051     return;
00052   }
00053   if(segev->getImage(layer,tmIdx)==NULL) {
00054     serr->printf("BallDetectionGenerator source's getImage returned NULL!\n");
00055     return;
00056   }
00057   const color_class_state& ballCCS=reinterpret_cast<const color_class_state*>(segev->getImage(layer,tmIdx))[clrIdx];
00058 
00059   ball.confidence = 0;
00060   region * ball_region=NULL;
00061 
00062   region * or_reg=ballCCS.list; //head of linked list of regions of target color. or_reg= original region (without noise removal)
00063   if(!or_reg){
00064     count++;
00065     // The next 3 lines could be cleared if no dimensions are sent with the deactivation events
00066     float dim=segev->getWidth(layer);
00067     //the max width and height of scaled dimensions
00068     float cw=segev->getWidth(layer)/dim;
00069     float ch=segev->getHeight(layer)/dim; 
00070     unsigned int frame_number=segev->getFrameNumber();
00071     if (present && count>noiseThreshold) {  // If there are no regions a number of frames and ball was present
00072       count=0;
00073       present=false; // Ball is not present
00074       createEvent(EventBase::deactivateETID,0,0,0,0,0,cw,ch,frame_number); // Deactivation Events
00075     }
00076     return;
00077   }
00078   
00079   unsigned int n = 0;
00080   while(or_reg && n<NUM_CHECK) {
00081     //float conf,conf0,conf_square_bbox,conf_area,conf_green,conf_area_bonus;
00082     //float conf_red_v_area;
00083     //int edge;
00084 
00085     int w = or_reg->x2 - or_reg->x1 + 1;
00086     int h = or_reg->y2 - or_reg->y1 + 1;
00087     
00088     int edge = calcEdgeMask(or_reg->x1,or_reg->x2,or_reg->y1,or_reg->y2,segev->getWidth(layer),segev->getHeight(layer));
00089     float conf0 = (w >= 3) * (h >= 3) * (or_reg->area >= 7);
00090     float conf_square_bbox = 
00091       edge ?
00092       gaussian_with_min(pct_from_mean(w,h) / .6f, 1e-3f) :
00093       gaussian_with_min(pct_from_mean(w,h) / .2f, 1e-3f);
00094     float conf_area =
00095       edge ?
00096       gaussian_with_min(pct_from_mean(((float)M_PI)*w*h/4.0f,or_reg->area) / .6f, 1e-3f) :
00097       gaussian_with_min(pct_from_mean(((float)M_PI)*w*h/4.0f,or_reg->area) / .2f, 1e-3f);
00098     float conf_area_bonus = or_reg->area / 1000.0f;
00099 
00100     float conf = conf0*conf_square_bbox*conf_area + conf_area_bonus;
00101 
00102     if(conf > 1.0) conf = 1.0f;
00103     
00104     if(debug_conf && frame_cnt == 0) {
00105       printf("conf0 %g conf_square_bbox %g conf_area %g conf_area_bonus %g final %g\n",
00106              conf0,conf_square_bbox,conf_area,conf_area_bonus,conf);
00107     }
00108     
00109     /*
00110       float green_f;
00111       if(conf > ball->confidence) {
00112       if(debug_ball &&
00113       (frame_cnt == 0 ||
00114       frame_cnt == 1)) {
00115       printf("%s ball n%d cen (%f,%f) area %d bbox (%d,%d)-(%d,%d) conf %f\n", (ball_color==COLOR_PINK)?"Pink":"Orange",
00116       n,or_reg->cen_x,or_reg->cen_y,or_reg->area,
00117       or_reg->x1,or_reg->y1,or_reg->x2,or_reg->y2,
00118       conf);
00119       }
00120 
00121       int sx[2],sy[2]; // scan bounding coordinates;
00122       bool edge_x[2],edge_y[2]; // true if scan coordinate went off edge
00123       static const int scan_distance = 3;
00124       static int color_cnts[num_colors];
00125       int scan_pixels;
00126       int good_value;
00127     
00128       sx[0] = or_reg->x1 - scan_distance;
00129       edge_x[0] = (sx[0] < 0);
00130       if(edge_x[0]) sx[0] = 0;
00131       sx[1] = or_reg->x2 + scan_distance;
00132       edge_x[1] = (sx[1] > width-1);
00133       if(edge_x[1]) sx[1] = width-1;
00134       sy[0] = or_reg->y1 - scan_distance;
00135       edge_y[0] = (sy[0] < 0);
00136       if(edge_y[0]) sy[0] = 0;
00137       sy[1] = or_reg->y2 + scan_distance;
00138       edge_y[1] = (sy[1] > height-1);
00139       if(edge_y[1]) sy[1] = height-1;
00140 
00141       scan_pixels = 0;
00142       for(int color_idx=0; color_idx<MAX_COLORS; color_idx++)
00143       color_cnts[color_idx]=0;
00144     
00145       // do horizontal strips
00146       for(int side=0; side<2; side++) {
00147       if(!edge_y[side]) {
00148       scan_pixels+=addToHistHorizStrip(sy[side],sx[0],sx[1],color_cnts);
00149       }
00150       }
00151     
00152       // do vertical strips
00153       for(int side=0; side<2; side++) {
00154       if(!edge_x[side]) {
00155       scan_pixels+=addToHistVertStrip(sx[side],sy[0],sy[1],color_cnts);
00156       }
00157       }
00158 
00159       int non_robot_fringe=0;
00160       non_robot_fringe += 5*color_cnts[getColor("blue")];
00161       non_robot_fringe -=   color_cnts[getColor("green")];
00162 
00163       conf_red_v_area = 1 + non_robot_fringe / or_reg->area;
00164       conf_red_v_area = bound(conf_red_v_area,0.0,1.0);
00165       
00166       good_value = 0;
00167       good_value += 2*color_cnts[getColor("blue")];
00168       good_value += 3*color_cnts[getColor("green")]/2;
00169 
00170       green_f = std::max(good_value+1,1) / (scan_pixels + 1.0);
00171       green_f = bound(green_f,0.0,1.0);
00172       conf_green = green_f;
00173     
00174       conf = 
00175       conf0 *
00176       conf_square_bbox *
00177       conf_area *
00178       + conf_area_bonus;
00179     
00180       if(conf > 1.0) conf = 1.0;
00181       }*/
00182     
00183     if(conf > ball.confidence) {
00184       /*
00185         d = sqrt((FocalDist * FocalDist * YPixelSize) * (M_PI * BallRadius * BallRadius) /
00186         (or_reg->area));
00187     
00188         vector3d ball_dir; // direction of ball from camera in robot coordinates
00189         ball_dir = getPixelDirection(or_reg->cen_x,or_reg->cen_y);
00190     
00191         // Reject if ball above level plane
00192         //      if(atan2(ball_dir.z,hypot(ball_dir.x,ball_dir.y)) <= (5*(M_PI/180))) {
00193         ball->edge = calcEdgeMask(or_reg);
00194         
00195         vector3d intersect_ball_loc,pixel_size_ball_loc;
00196 
00197         bool intersects=false;
00198         vector3d intersection_pt(0.0,0.0,0.0);
00199         intersects=GVector::intersect_ray_plane(camera_loc,ball_dir,
00200         vector3d(0.0,0.0,BallRadius),vector3d(0.0,0.0,1.0),
00201         intersection_pt);
00202         if(intersects) {
00203         intersect_ball_loc = intersection_pt;
00204         }
00205 
00206         pixel_size_ball_loc = camera_loc + ball_dir * d;
00207 
00208         vector3d ball_loc,alt_ball_loc;
00209         if(ball->edge!=0 && intersects) {
00210         ball_loc     = intersect_ball_loc;
00211         alt_ball_loc = pixel_size_ball_loc;
00212         } else {
00213         alt_ball_loc = intersect_ball_loc;
00214         ball_loc     = pixel_size_ball_loc;
00215         }
00216       */ 
00217 
00218       ball.confidence = conf;
00219         
00220       //        ball->loc = ball_loc;
00221         
00222       //        ball->distance = hypot(ball_loc.x,ball_loc.y);
00223         
00224       //        findSpan(ball->left,ball->right,or_reg->x1,or_reg->x2,or_reg->y1,or_reg->y2);
00225 
00226       ball_region = or_reg;
00227 
00228       /*        if(debug_ball &&
00229                 frame_cnt==0) {
00230                 printf("###found ball, conf %g loc (%g,%g,%g) alt (%g,%g,%g) dist %g left %g right %g edge %d\n",
00231                 ball->confidence,
00232                 ball->loc.x,ball->loc.y,ball->loc.z,
00233                 alt_ball_loc.x,alt_ball_loc.y,alt_ball_loc.z,
00234                 ball->distance,ball->left,ball->right,ball->edge);
00235                 }*/
00236       // }
00237     }
00238 
00239     or_reg = or_reg->next;
00240     n++;
00241   }
00242   //return (ball_color==getColor("red"))?generateEvent (VisionObjectEvent::RedBallSID, ball->confidence, ball_region->cen_x, ball_region->cen_y):generateEvent(VisionObjectEvent::PinkBallSID,ball->confidence,ball_region->cen_x,ball_region->cen_y);
00243   
00244   testSendEvent(*segev,(float)ball.confidence,(int)ball_region->x1,(int)ball_region->x2,(int)ball_region->y1,(int)ball_region->y2,(int)ball_region->area); 
00245 }
00246 
00247 void
00248 BallDetectionGenerator::testSendEvent(const FilterBankEvent& ev, float conf, int regX1,int regX2,int regY1,int regY2, int area) {
00249   unsigned int layer=ev.getNumLayers()-config->vision.resolution-1;
00250 
00251   // x will be scaled to [-1,1], y scaled correspondingly to [ -1/aspectRatio , 1/aspectRatio ]
00252   float dim=ev.getWidth(layer);
00253 
00254   //the max width and height of scaled dimensions
00255   float cw=config->vision.x_range;
00256   float ch=config->vision.y_range;
00257 
00258   //scale the dimensions
00259   float cx1=2.0f*regX1/dim - cw;
00260   float cx2=2.0f*(regX2+1)/dim - cw;
00261   float cy1=2.0f*regY1/dim - ch;
00262   float cy2=2.0f*(regY2+1)/dim - ch;
00263   float carea=4.0f*area/(dim*dim);
00264   unsigned int frame_number=ev.getFrameNumber();  
00265 
00266   if (conf>confidenceThreshold) {
00267     if (present) {
00268       count=0;
00269       createEvent(EventBase::statusETID,cx1,cx2,cy1,cy2,carea,cw,ch,frame_number);
00270     } else {
00271       count++;
00272       if (count>noiseThreshold) {
00273         count=0;
00274         present=true;
00275         createEvent(EventBase::activateETID,cx1,cx2,cy1,cy2,carea,cw,ch,frame_number);
00276       }
00277     }
00278   } else {
00279     if (!present) {
00280       count=0;
00281     } else {
00282       count++;
00283       if (count>noiseThreshold) {
00284         count=0;
00285         present=false;
00286         createEvent(EventBase::deactivateETID,0,0,0,0,carea,cw,ch,frame_number);
00287       } else {
00288         createEvent(EventBase::statusETID,cx1,cx2,cy1,cy2,carea,cw,ch,frame_number);
00289       }
00290     }
00291   }
00292 }
00293 
00294 void
00295 BallDetectionGenerator::createEvent(EventBase::EventTypeID_t etid, float bbX1,float bbX2,float bbY1,float bbY2,float area,float rx,float ry,unsigned int frame) const {
00296   VisionObjectEvent vo(mySourceID,etid,bbX1,bbX2,bbY1,bbY2,area,rx,ry,frame);
00297   vo.setName(getName());
00298   erouter->postEvent(vo);
00299 }
00300 
00301 int
00302 BallDetectionGenerator::calcEdgeMask(int x1,int x2,int y1,int y2, int width, int height) {
00303   static const int boundary_pixel_size=1;
00304 
00305   int edge = 0;
00306   if(x1 <= 0       +boundary_pixel_size) edge |= OFF_EDGE_LEFT  ;
00307   if(x2 >= width -1-boundary_pixel_size) edge |= OFF_EDGE_RIGHT ;
00308   if(y1 <= 0       +boundary_pixel_size) edge |= OFF_EDGE_TOP   ;
00309   if(y2 >= height-1-boundary_pixel_size) edge |= OFF_EDGE_BOTTOM;
00310 
00311   return edge;
00312 }
00313 
00314 /*! @file 
00315  * @brief Implements BallDetectionGenerator, which uses segmented color region information to detect round objects
00316  * @author alokl (Creator)
00317  * @author ejt (reorganized)
00318  * @author Ignacio Herrero Reder < nhr at dte uma es > (VisionObjectInfo Boundary Box - bug 74)
00319  *
00320  * History is old, may have grown from CMPack (CMU Robosoccer) roots?
00321  * I think if there's any of their code left, it's probably *mostly*
00322  * the commented out stuff I (ejt) left for posterity when
00323  * reorganizing.  But alokl didn't flag this as CMPack's prior to
00324  * inital release, and they didn't request credit for it when they
00325  * reviewed the code, so I guess it's all ours...
00326  */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:36 2016 by Doxygen 1.6.3