Homepage Demos Overview Downloads Tutorials Reference
Credits

Vision.cc

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <math.h>
00003 
00004 #include <MCOOP.h>
00005 
00006 #include "Shared/Config.h"
00007 #include "Shared/mathutils.h"
00008 #include "Events/EventRouter.h"
00009 #include "cmv_region.h"
00010 #include "Vision.h"
00011 #include "Shared/WorldState.h"
00012 #include "Events/VisionEvent.h"
00013 #include "Shared/get_time.h"
00014 #include "Shared/SystemUtility.h"
00015 #include "VisionSerializer.h"
00016 #include "Wireless/Wireless.h"
00017 
00018 Vision *vision=NULL;
00019 
00020 using namespace mathutils;
00021 using namespace VisionEventNS;
00022 
00023 Vision::Vision() : frameTimestamp(0UL), frame_count(0), cmap(NULL), tmap(NULL),
00024                    rmap(NULL), rmap2(NULL), reg(NULL), width(0), height(0),
00025                    max_width(0), max_height(0), max_runs(0), max_regions(0),
00026                    num_colors(0), num_runs(0), num_regions(0), body_angle(0.0),
00027                    body_height(100.0), vis_markers(0), obj_info(NULL),
00028                    imageLayer(ofbkimageLAYER_H), vser(NULL)
00029 {
00030   initialize();
00031   vser=new VisionSerializer();
00032 }
00033 
00034 void Vision::setCameraParams()
00035 {
00036   static OPrimitiveID fbkID = 0;
00037       
00038   if(fbkID == 0){
00039     if(OPENR::OpenPrimitive("PRM:/r1/c1/c2/c3/i1-FbkImageSensor:F1", &fbkID) != oSUCCESS){
00040       cout << "Open FbkImageSensor failure." << endl;
00041     }
00042   }
00043 
00044   longword wb=config->vision.white_balance;
00045   longword gain=config->vision.gain;
00046   longword shutter=config->vision.shutter_speed;
00047 
00048   /* White Balance */
00049   OPrimitiveControl_CameraParam owb(wb);
00050   if(OPENR::ControlPrimitive(fbkID, oprmreqCAM_SET_WHITE_BALANCE, &owb, sizeof(owb), 0, 0) != oSUCCESS){
00051     cout << "CAM_SET_WHITE_BALANCE : Failed!" << endl;
00052   }
00053 
00054   /* Gain */
00055   OPrimitiveControl_CameraParam ogain(gain);
00056   if(OPENR::ControlPrimitive(fbkID, oprmreqCAM_SET_GAIN, &ogain, sizeof(ogain), 0, 0) != oSUCCESS){
00057     cout << "CAM_SET_GAIN : Failed!" << endl;
00058   }
00059 
00060   /* Shutter Speed */
00061   OPrimitiveControl_CameraParam oshutter(shutter);
00062   if(OPENR::ControlPrimitive(fbkID,oprmreqCAM_SET_SHUTTER_SPEED, &oshutter, sizeof(oshutter), 0, 0) != oSUCCESS){
00063     cout << "CAM_SET_SHUTTER_SPEED : Failed!" << endl;
00064   }
00065 }
00066 
00067 void Vision::setResolution()
00068 {
00069   switch(config->vision.resolution) {
00070     case 2:
00071       width=88;
00072       height=72;
00073       imageLayer=ofbkimageLAYER_M;
00074       break;
00075     case 3:
00076       width=44;
00077       height=36;
00078       imageLayer=ofbkimageLAYER_L;
00079       break;
00080     default:
00081       width=176;
00082       height=144;
00083       imageLayer=ofbkimageLAYER_H;
00084       break;
00085   }
00086 
00087   max_width  = width;
00088   max_height = height;
00089 
00090   int size = width * height;
00091   max_runs = size / MIN_EXP_RUN_LENGTH;
00092   max_regions = size / MIN_EXP_REGION_SIZE;
00093   size = max_width * max_height;
00094 
00095   if (cmap!=NULL) { DeleteLarge(cmap); cmap=NULL; }
00096   NewLarge(&cmap,size+1); // +1 to store EncodeRuns terminator value
00097   if(!cmap) {
00098     cout << "Couldn't allocate cmap\n\xFF" << endl;
00099     *((long *)0xDEADCC44)=1;
00100   }
00101   if (rmap!=NULL) { DeleteLarge(rmap); rmap=NULL; }
00102   NewLarge(&rmap,max_runs);
00103   if(!rmap) {
00104     cout << "Couldn't allocate rmap\n\xFF" << endl;
00105     *((long *)0xDEAD7744)=1;
00106   }
00107   if (rmap2!=NULL) { DeleteLarge(rmap2); rmap2=NULL; }
00108   NewLarge(&rmap2,max_runs);
00109   if(!rmap2) {
00110     cout << "Couldn't allocate rmap2\n\xFF" << endl;
00111     *((long *)0xDEAD7745)=1;
00112   }
00113   if (reg!=NULL) { DeleteLarge(reg); reg=NULL; }
00114   NewLarge(&reg,max_regions);
00115   if(!reg) {
00116     cout << "Couldn't allocate reg\n" << endl;
00117     *((long *)0xDEAD7E66)=1;
00118   }
00119 }
00120 
00121 void Vision::setColors()
00122 {
00123   color_names.clear();
00124   num_colors =
00125     CMVision::LoadColorInformation(color,MAX_COLORS,config->vision.colors,
00126                                    color_names);
00127   if(num_colors > 0){
00128     printf("  Loaded %d colors.\n",num_colors);
00129   }else{
00130     printf("  ERROR: Could not load colors file:%s\n", config->vision.colors);
00131   }
00132 
00133   int num_y,num_u,num_v;
00134   int size = 1 << (bits_y + bits_u + bits_v);
00135   num_y = 1 << bits_y;
00136   num_u = 1 << bits_u;
00137   num_v = 1 << bits_v;
00138 
00139   memset(tmap,0,size*sizeof(cmap_t));
00140 
00141   if(!CMVision::LoadThresholdFile(tmap,num_y,num_u,num_v,
00142                                   config->vision.thresh)) {
00143     printf("  ERROR: Could not load threshold file '%s'.\n",
00144            config->vision.thresh);
00145   }
00146   int remapped=CMVision::CheckTMapColors(tmap,num_y,num_u,num_v,num_colors,0);
00147   printf("remapped %d colors in threshold file '%s'\n",
00148          remapped, config->vision.thresh);
00149 }
00150 
00151 int Vision::getColor(const char* color) {
00152   hash_map<const char*, int, hash<const char*>, hashcmp_eqstr>::iterator i;
00153   i=color_names.find(color);
00154   if (i==color_names.end()) return -1;
00155   return i->second;
00156 }
00157 
00158 void Vision::initialize()
00159 {
00160   int result;
00161   int size = 1 << (bits_y + bits_u + bits_v);
00162 
00163   obj_info=new ObjectInfo;
00164 
00165   setResolution();
00166 
00167   // Set up threshold
00168 
00169 #ifdef PLATFORM_APERIOS
00170   result = NewRegion(size, reinterpret_cast<void**>(&tmap));
00171   if (result != sSUCCESS)
00172     printf("Unable to allocate tmap buffer of size %d\n",size);
00173 #else
00174   tmap = new cmap_t[size];
00175 #endif
00176 
00177   setColors();
00178 
00179 
00180   initializeEventSpecs();
00181   setCameraParams();
00182 }
00183 
00184 void Vision::initializeEventSpecs() {
00185   for(int event_idx=0; event_idx<NUM_VEVENTS; event_idx++) {
00186     vevent_spec[event_idx].listeners = 0; // disable events
00187     vevent_spec[event_idx].filter = 0; // disable noise removal
00188     vevent_spec[event_idx].count = 0;
00189     vevent_spec[event_idx].cx = 0;
00190     vevent_spec[event_idx].cy = 0;
00191     vevent_spec[event_idx].present = false;
00192   }
00193   vevent_spec[RedBallSID].confidence=0.7;
00194   vevent_spec[PinkBallSID].confidence=0.7;
00195   vevent_spec[HandSID].confidence=0.5;
00196   vevent_spec[ThumbsupSID].confidence=0.45;
00197   vevent_spec[ThingSID].confidence=0.5;
00198   vevent_spec[MarkersSID].confidence=1.0001;  // disabled
00199 }
00200 
00201 void Vision::enableEvents(int vevent) {
00202   vevent_spec[vevent].listeners++;
00203 }
00204 
00205 void Vision::enableEvents(int vevent, int noise) {
00206   enableEvents(vevent);
00207   setNoiseThreshold(vevent, noise);
00208 }
00209 
00210 void Vision::disableEvents(int vevent) {
00211   if (vevent_spec[vevent].listeners>0)
00212     vevent_spec[vevent].listeners--;
00213 }
00214 
00215 void Vision::setNoiseThreshold(int vevent, int noise) {
00216   vevent_spec[vevent].filter=noise;
00217 }
00218 
00219 bool Vision::generateEvent(int vevent, double conf, int cenX, int cenY) {
00220   float cx, cy;
00221   if (conf>vevent_spec[vevent].confidence) {  
00222     cx=(cenX-88.0)/88.0;
00223     cy=(cenY-72.0)/72.0;
00224     vevent_spec[vevent].cx=cx;
00225     vevent_spec[vevent].cy=cy;
00226 
00227     if (vevent_spec[vevent].present) {
00228       vevent_spec[vevent].count=0;
00229       createEvent(EventBase::statusETID,vevent,cx,cy);
00230     } else {
00231       vevent_spec[vevent].count++;
00232       if (vevent_spec[vevent].count>vevent_spec[vevent].filter) {
00233         vevent_spec[vevent].count=0;
00234         vevent_spec[vevent].present=true;
00235         createEvent(EventBase::activateETID,vevent,cx,cy);
00236       }
00237     }
00238     return true;
00239   } else {
00240     if (!vevent_spec[vevent].present) {
00241       vevent_spec[vevent].count=0;
00242     } else {
00243       vevent_spec[vevent].count++;
00244       if (vevent_spec[vevent].count>vevent_spec[vevent].filter) {
00245         vevent_spec[vevent].count=0;
00246         vevent_spec[vevent].present=false;
00247         createEvent(EventBase::deactivateETID,vevent,0,0);
00248       } else {
00249         createEvent(EventBase::statusETID,vevent,cx,cy);
00250       }
00251     }
00252     return false;
00253   }
00254 }
00255 
00256 bool Vision::close()
00257 {
00258   DeleteLarge(tmap);
00259   DeleteLarge(cmap);
00260   DeleteLarge(rmap);
00261   DeleteLarge(rmap2);
00262   DeleteLarge(reg);
00263 
00264   tmap = NULL;
00265   cmap = NULL;
00266   rmap = NULL;
00267   rmap2 = NULL;
00268   reg  = NULL;
00269 
00270   max_width  = 0;
00271   max_height = 0;
00272 
00273   return(true);
00274 }
00275 
00276 inline double pct_from_mean(double a,double b) {
00277   double s = (a - b) / (a + b);
00278   return fabs(s);
00279 }
00280 
00281 int Vision::calcEdgeMask(int x1,int x2,int y1,int y2)
00282 {
00283   static const int boundary_pixel_size=1;
00284 
00285   int edge;
00286 
00287   edge = 0;
00288   if(x1 <= 0       +boundary_pixel_size) edge |= OFF_EDGE_LEFT  ;
00289   if(x2 >= width -1-boundary_pixel_size) edge |= OFF_EDGE_RIGHT ;
00290   if(y1 <= 0       +boundary_pixel_size) edge |= OFF_EDGE_TOP   ;
00291   if(y2 >= height-1-boundary_pixel_size) edge |= OFF_EDGE_BOTTOM;
00292 
00293   return edge;
00294 }
00295 
00296 int Vision::addToHistHorizStrip(int y, int x1, int x2, int *color_cnt)
00297 {
00298   int x;
00299 
00300   y  = bound(y ,0,height-1);
00301   x1 = bound(x1,0,width -1);
00302   x2 = bound(x2,0,width -1);
00303 
00304   for(x=x1; x<=x2; x++) {
00305     color_cnt[getColorUnsafe(x,y)]++;
00306   }
00307 
00308   return x2-x1+1;
00309 }
00310 
00311 int Vision::addToHistVertStrip(int x, int y1, int y2, int *color_cnt)
00312 {
00313   int y;
00314 
00315   x  = bound(x ,0,width -1);
00316   y1 = bound(y1,0,height-1);
00317   y2 = bound(y2,0,height-1);
00318 
00319   for(y=y1; y<=y2; y++) {
00320     color_cnt[getColorUnsafe(x,y)]++;
00321   }
00322 
00323   return y2-y1+1;
00324 }
00325 
00326 bool Vision::findHand(VObject *hand, VisionObjectInfo *hand_info)
00327 {
00328   if (vevent_spec[HandSID].listeners==0) return false;
00329 
00330   color_class_state *skin;
00331   int n;
00332   double conf;
00333 
00334   skin=&color[getColor("skin")];
00335 
00336   region *or_reg; // hand region(s)
00337 
00338   or_reg=skin->list;
00339 
00340   hand->confidence = 0.0;
00341 
00342   if(!or_reg) return false;
00343 
00344   n = 0;
00345   while(or_reg && n<10) {
00346     conf = ((double)or_reg->area/500);
00347 
00348     if(conf > 1.0) conf = 1.0;
00349     
00350     if(conf > hand->confidence) {
00351         hand->confidence = conf;
00352         hand_info->reg = or_reg;
00353     }
00354 
00355     or_reg = or_reg->next;
00356     n++;
00357   }
00358 
00359   return generateEvent (HandSID, hand->confidence, hand_info->reg->cen_x, hand_info->reg->cen_y);
00360 }
00361 
00362 bool Vision::findBall(int ball_color, VObject *ball,VisionObjectInfo *ball_info) {
00363   if ((ball_color==getColor("red") && vevent_spec[RedBallSID].listeners==0)
00364       ||(ball_color==getColor("pink") && vevent_spec[PinkBallSID].listeners==0)) return false;
00365 
00366   static const bool debug_ball = false;
00367   static const bool debug_conf = false;
00368 
00369   static int frame_cnt=0;
00370   static const int print_period=1;
00371 
00372   if(debug_ball)
00373     frame_cnt = (frame_cnt + 1) % print_period;
00374 
00375   color_class_state *pink;
00376   int n;
00377   int w,h;
00378   double conf;
00379   double green_f;
00380 
00381   pink=&color[ball_color];
00382 
00383   region *or_reg; // pink region
00384 
00385   or_reg=pink->list;
00386 
00387   ball->confidence = 0.0;
00388 
00389   if(!or_reg) return false;
00390 
00391   n = 0;
00392   while(or_reg && n<10) {
00393     double conf0,conf_square_bbox,conf_area,conf_green,conf_area_bonus;
00394     double conf_red_v_area;
00395     int edge;
00396 
00397     w = or_reg->x2 - or_reg->x1 + 1;
00398     h = or_reg->y2 - or_reg->y1 + 1;
00399     
00400     edge = calcEdgeMask(or_reg);
00401     conf0 = (w >= 3) * (h >= 3) * (or_reg->area >= 7);
00402     conf_square_bbox = 
00403       edge ?
00404       gaussian_with_min(pct_from_mean(w,h) / .6, 1e-3) :
00405       gaussian_with_min(pct_from_mean(w,h) / .2, 1e-3);
00406     conf_area =
00407       edge ?
00408       gaussian_with_min(pct_from_mean(M_PI*w*h/4.0,or_reg->area) / .6, 1e-3) :
00409       gaussian_with_min(pct_from_mean(M_PI*w*h/4.0,or_reg->area) / .2, 1e-3);
00410     conf_red_v_area = 1.0;
00411     conf_green = 1.0;
00412     conf_area_bonus = ((double)or_reg->area / 1000);
00413 
00414     conf = 
00415       conf0 *
00416       conf_square_bbox *
00417       conf_area *
00418       conf_red_v_area *
00419       conf_green +
00420       conf_area_bonus;
00421 
00422     if(conf > 1.0) conf = 1.0;
00423     
00424     if(debug_conf &&
00425          frame_cnt == 0) {
00426       printf("conf0 %g conf_square_bbox %g conf_area %g conf_area_bonus %g final %g\n",
00427               conf0,conf_square_bbox,conf_area,conf_area_bonus,conf);
00428     }
00429     
00430 /*
00431     if(conf > ball->confidence) {
00432       if(debug_ball &&
00433        (frame_cnt == 0 ||
00434         frame_cnt == 1)) {
00435         printf("%s ball n%d cen (%f,%f) area %d bbox (%d,%d)-(%d,%d) conf %f\n", (ball_color==COLOR_PINK)?"Pink":"Orange",
00436                 n,or_reg->cen_x,or_reg->cen_y,or_reg->area,
00437                 or_reg->x1,or_reg->y1,or_reg->x2,or_reg->y2,
00438                 conf);
00439       }
00440 
00441       int sx[2],sy[2]; // scan bounding coordinates;
00442       bool edge_x[2],edge_y[2]; // true if scan coordinate went off edge
00443       static const int scan_distance = 3;
00444       static int color_cnts[num_colors];
00445       int scan_pixels;
00446       int good_value;
00447     
00448       sx[0] = or_reg->x1 - scan_distance;
00449       edge_x[0] = (sx[0] < 0);
00450       if(edge_x[0]) sx[0] = 0;
00451       sx[1] = or_reg->x2 + scan_distance;
00452       edge_x[1] = (sx[1] > width-1);
00453       if(edge_x[1]) sx[1] = width-1;
00454       sy[0] = or_reg->y1 - scan_distance;
00455       edge_y[0] = (sy[0] < 0);
00456       if(edge_y[0]) sy[0] = 0;
00457       sy[1] = or_reg->y2 + scan_distance;
00458       edge_y[1] = (sy[1] > height-1);
00459       if(edge_y[1]) sy[1] = height-1;
00460 
00461       scan_pixels = 0;
00462       for(int color_idx=0; color_idx<MAX_COLORS; color_idx++)
00463         color_cnts[color_idx]=0;
00464     
00465       // do horizontal strips
00466       for(int side=0; side<2; side++) {
00467         if(!edge_y[side]) {
00468           scan_pixels+=addToHistHorizStrip(sy[side],sx[0],sx[1],color_cnts);
00469         }
00470       }
00471     
00472       // do vertical strips
00473       for(int side=0; side<2; side++) {
00474         if(!edge_x[side]) {
00475           scan_pixels+=addToHistVertStrip(sx[side],sy[0],sy[1],color_cnts);
00476         }
00477       }
00478 
00479       int non_robot_fringe=0;
00480       non_robot_fringe += 5*color_cnts[getColor("blue")];
00481       non_robot_fringe -=   color_cnts[getColor("green")];
00482 
00483       conf_red_v_area = 1 + non_robot_fringe / or_reg->area;
00484       conf_red_v_area = bound(conf_red_v_area,0.0,1.0);
00485       
00486       good_value = 0;
00487       good_value += 2*color_cnts[getColor("blue")];
00488       good_value += 3*color_cnts[getColor("green")]/2;
00489 
00490       green_f = std::max(good_value+1,1) / (scan_pixels + 1.0);
00491       green_f = bound(green_f,0.0,1.0);
00492       conf_green = green_f;
00493     
00494       conf = 
00495         conf0 *
00496         conf_square_bbox *
00497         conf_area *
00498         + conf_area_bonus;
00499     
00500       if(conf > 1.0) conf = 1.0;
00501     }*/
00502     
00503     if(conf > ball->confidence) {
00504       /*
00505       d = sqrt((FocalDist * FocalDist * YPixelSize) * (M_PI * BallRadius * BallRadius) /
00506                (or_reg->area));
00507     
00508       vector3d ball_dir; // direction of ball from camera in robot coordinates
00509       ball_dir = getPixelDirection(or_reg->cen_x,or_reg->cen_y);
00510     
00511       // Reject if ball above level plane
00512 //      if(atan2(ball_dir.z,hypot(ball_dir.x,ball_dir.y)) <= (5*(M_PI/180))) {
00513         ball->edge = calcEdgeMask(or_reg);
00514         
00515         vector3d intersect_ball_loc,pixel_size_ball_loc;
00516 
00517         bool intersects=false;
00518         vector3d intersection_pt(0.0,0.0,0.0);
00519         intersects=GVector::intersect_ray_plane(camera_loc,ball_dir,
00520                                                 vector3d(0.0,0.0,BallRadius),vector3d(0.0,0.0,1.0),
00521                                                 intersection_pt);
00522         if(intersects) {
00523           intersect_ball_loc = intersection_pt;
00524         }
00525 
00526         pixel_size_ball_loc = camera_loc + ball_dir * d;
00527 
00528         vector3d ball_loc,alt_ball_loc;
00529         if(ball->edge!=0 && intersects) {
00530           ball_loc     = intersect_ball_loc;
00531           alt_ball_loc = pixel_size_ball_loc;
00532         } else {
00533           alt_ball_loc = intersect_ball_loc;
00534           ball_loc     = pixel_size_ball_loc;
00535         }*/ 
00536 
00537         ball->confidence = conf;
00538         
00539 //        ball->loc = ball_loc;
00540         
00541 //        ball->distance = hypot(ball_loc.x,ball_loc.y);
00542         
00543 //        findSpan(ball->left,ball->right,or_reg->x1,or_reg->x2,or_reg->y1,or_reg->y2);
00544 
00545         ball_info->reg = or_reg;
00546 
00547 /*        if(debug_ball &&
00548            frame_cnt==0) {
00549           printf("###found ball, conf %g loc (%g,%g,%g) alt (%g,%g,%g) dist %g left %g right %g edge %d\n",
00550                   ball->confidence,
00551                   ball->loc.x,ball->loc.y,ball->loc.z,
00552                   alt_ball_loc.x,alt_ball_loc.y,alt_ball_loc.z,
00553                   ball->distance,ball->left,ball->right,ball->edge);
00554         }*/
00555      // }
00556     }
00557 
00558     or_reg = or_reg->next;
00559     n++;
00560   }
00561   return (ball_color==getColor("red"))?generateEvent (RedBallSID, ball->confidence, ball_info->reg->cen_x, ball_info->reg->cen_y):generateEvent(PinkBallSID,ball->confidence,ball_info->reg->cen_x,ball_info->reg->cen_y);
00562 }
00563 
00564 bool Vision::findThing(VObject *thing, VisionObjectInfo *thing_info) {
00565   if (vevent_spec[ThingSID].listeners==0) return false;
00566   thing->confidence=0;
00567   return generateEvent (ThingSID, thing->confidence, thing_info->reg->cen_x, thing_info->reg->cen_y);
00568 }
00569 
00570 int Vision::isIn(region *r1, region *r2) {
00571   int r1w=r1->x2-r1->x1;
00572   int r1h=r1->y2-r1->y1;
00573 
00574   if ((((r2->x1 < r1->x1) && (r2->x2 > r1->x1+r1w*0.75)) ||
00575        ((r2->x2 > r1->x2) && (r2->x1 < r1->x2-r1w*0.75)))
00576       && (((r2->y1 < r1->y1) && (r2->y2 > r1->y1+r1h*0.75)) ||
00577          ((r2->y2 > r1->y2) && (r2->y1 < r1->y2-r1h*0.75))))
00578     return 1;
00579   return 0;
00580 }
00581 
00582 int Vision::isAdjacent(region *r1, region *r2) {
00583   // bounding boxes <= two pixels apart
00584   if (r1->x1 < r2->x1)
00585     return r1->x2>(r2->x1-2);
00586   else if (r1->x2 > r2->x2)
00587     return r1->x1<(r2->x2+2);
00588   return 0;
00589 }
00590 
00591 int Vision::identifyMarker(int color1, int color2, int color3) {
00592   static const int marker_colors[27]={
00593       -1, -1, -1, MARKER_GOG, -1, MARKER_GOP, MARKER_GPG, MARKER_GPO, -1,
00594       -1, MARKER_OGO, MARKER_OGP, -1, -1, -1, MARKER_OPG, MARKER_OPO, -1,
00595       -1, MARKER_PGO, MARKER_PGP, MARKER_POG, -1, MARKER_POP, -1, -1, -1 };
00596   int markeridx=0;
00597   switch (color1) {
00598     case COLOR_ORANGE:
00599       markeridx+=9;
00600       break;
00601     case COLOR_PURPLE:
00602       markeridx+=18;
00603       break;
00604   }
00605   switch (color2) {
00606     case COLOR_ORANGE:
00607       markeridx+=3;
00608       break;
00609     case COLOR_PURPLE:
00610       markeridx+=6;
00611       break;
00612   }
00613   switch (color3) {
00614     case COLOR_ORANGE:
00615       markeridx+=1;
00616       break;
00617     case COLOR_PURPLE:
00618       markeridx+=2;
00619       break;
00620   }
00621   return marker_colors[markeridx];
00622 }
00623 
00624 bool Vision::findMarkers() {
00625   if (vevent_spec[MarkersSID].listeners==0) return false;
00626 
00627   const bool debug_markers    = false;
00628   static int frame_cnt=0;
00629 
00630   static const int print_period=30;
00631 
00632   if(debug_markers)
00633     frame_cnt = (frame_cnt + 1) % print_period;
00634 
00635   region *or_reg, *gr_reg, *pu_reg;
00636 
00637   or_reg = color[getColor("orange")].list;
00638   gr_reg = color[getColor("bgreen")].list;
00639   pu_reg = color[getColor("purple")].list;
00640 
00641   region* marker_regs[9];
00642   int num_regs=0;
00643 
00644   for (int i=0; i<9; i++) marker_regs[i]=NULL;
00645 
00646   while (num_regs<9) {
00647     int rarea=0;
00648 
00649     if (or_reg) {
00650       marker_regs[num_regs]=or_reg;
00651       rarea=or_reg->area;
00652     }
00653     if (gr_reg && gr_reg->area>rarea) {
00654       marker_regs[num_regs]=gr_reg;
00655       rarea=gr_reg->area;
00656     }
00657     if (pu_reg && pu_reg->area>rarea) {
00658       marker_regs[num_regs]=pu_reg;
00659       rarea=pu_reg->area;
00660     }
00661     if (rarea<30) break;
00662 
00663     switch(marker_regs[num_regs]->color) {
00664       case COLOR_ORANGE:
00665         or_reg=or_reg->next;
00666         break;
00667       case COLOR_BGREEN:
00668         gr_reg=gr_reg->next;
00669         break;
00670       case COLOR_PURPLE:
00671         pu_reg=pu_reg->next;
00672         break;
00673     }
00674     num_regs++;
00675   }
00676 
00677   vis_markers=0;
00678 
00679   for (int i=0;  i<num_regs/3; i++) {
00680     int j;
00681     for (j=0; j<3; j++) markers[vis_markers].regs[j]=NULL;
00682     for (j=i; j<num_regs; j++)
00683       if (marker_regs[j]) break;
00684     markers[vis_markers].regs[0]=marker_regs[j];
00685     marker_regs[j]=NULL;
00686     for (j++; j<num_regs; j++) {
00687       if (marker_regs[j]) {
00688         if (isAdjacent(markers[vis_markers].regs[0],marker_regs[j])) {
00689           markers[vis_markers].regs[1]=marker_regs[j];
00690           marker_regs[j]=NULL;
00691           break;
00692         }
00693       }
00694     }
00695     if (!markers[vis_markers].regs[1]) continue;
00696     for (j=i+1; j<num_regs; j++) {
00697       if (marker_regs[j]) {
00698         if (isAdjacent(markers[vis_markers].regs[0],marker_regs[j])
00699             && isAdjacent(markers[vis_markers].regs[1],marker_regs[j])) {
00700           markers[vis_markers].regs[2]=markers[vis_markers].regs[1];
00701           markers[vis_markers].regs[1]=marker_regs[j];
00702           marker_regs[j]=NULL;
00703           break;
00704         } else if (isAdjacent(markers[vis_markers].regs[0],marker_regs[j])) {
00705           markers[vis_markers].regs[2]=markers[vis_markers].regs[1];
00706           markers[vis_markers].regs[1]=markers[vis_markers].regs[0];
00707           markers[vis_markers].regs[0]=marker_regs[j];
00708           marker_regs[j]=NULL;
00709           break;
00710         } else if (isAdjacent(markers[vis_markers].regs[1],marker_regs[j])) {
00711           markers[vis_markers].regs[2]=marker_regs[j];
00712           marker_regs[j]=NULL;
00713           break;
00714         }
00715       }
00716     }
00717     if (!markers[vis_markers].regs[2]) continue;
00718     if (markers[vis_markers].regs[0]->cen_x>markers[vis_markers].regs[2]->cen_x) {
00719       region* t_marker=markers[vis_markers].regs[0];
00720       markers[vis_markers].regs[0]=markers[vis_markers].regs[2];
00721       markers[vis_markers].regs[2]=t_marker;
00722     }
00723     markers[vis_markers].cen_x=markers[vis_markers].regs[1]->cen_x;
00724     markers[vis_markers].cen_y=markers[vis_markers].regs[1]->cen_y;
00725     markers[vis_markers].marker=identifyMarker(markers[vis_markers].regs[0]->color, markers[vis_markers].regs[1]->color,markers[vis_markers].regs[2]->color);
00726     if (markers[vis_markers].marker<0) continue;
00727 
00728     if (debug_markers && frame_cnt==0)
00729       printf("marker colors: %d%d%d, id: %d\n",markers[vis_markers].regs[0]->color, markers[vis_markers].regs[1]->color, markers[vis_markers].regs[2]->color,markers[vis_markers].marker);
00730     vis_markers++;
00731   }
00732   for (int i=0; i<vis_markers; i++) {
00733 #ifdef PLATFORM_APERIOS
00734     VisionEvent *mevent=new VisionEvent(EventBase::statusETID,MarkersSID,
00735                                      markers[i].cen_x, markers[i].cen_y);
00736     mevent->setProperty(markers[i].marker);
00737     erouter->postEvent(mevent);
00738 #endif
00739   }
00740   return (vis_markers>0);
00741 }
00742 
00743 bool Vision::findGesture(VisionObjectInfo *hand_info) {
00744   if (vevent_spec[ThumbsupSID].listeners==0) return false;
00745   if (hand_info->reg->cen_y>=144) return false;
00746 
00747   int thumbsup=0, thumbx=0;
00748   int idx=hand_info->reg->run_start;
00749   int parent=rmap[idx].parent;
00750 
00751   int i=0, y=0;
00752 
00753   while (y<=hand_info->reg->cen_y) {
00754     int r=0;
00755     int xl=0;
00756     while (rmap[i].y<=y) {
00757       if (r>0) {
00758         if (rmap[i].parent==parent
00759             && rmap[i].width>5
00760             && rmap[i].x > xl+10) {
00761           thumbsup++;
00762           thumbx+=xl+(rmap[i].x-xl)/2;
00763         } else {
00764           xl=rmap[i].x+rmap[i].width;
00765         }
00766       } else if (r==0) {
00767         if (rmap[i].parent==parent
00768             && rmap[i].width>5) {
00769           r=i;
00770           xl=rmap[i].x+rmap[i].width;
00771         }
00772       }
00773       i++;
00774       if (i>=num_runs) break;
00775     }
00776     if (i>=num_runs) break;
00777     y=rmap[i].y;
00778   }
00779   
00780   return generateEvent (ThumbsupSID, limitRange(thumbsup/20.00,0.0,1.0), hand_info->reg->cen_x, hand_info->reg->cen_y);
00781 }
00782 
00783 void Vision::createEvent(unsigned int tid, unsigned int sid,
00784                          float cenX, float cenY) {
00785 #ifdef PLATFORM_APERIOS
00786   erouter->postEvent(new VisionEvent((EventBase::EventTypeID_t)tid,sid,cenX,cenY));
00787 #endif
00788 }
00789 
00790 bool Vision::runHighLevelVision(ObjectInfo *obj_info) {
00791   for(int obj_idx=0; obj_idx<NUM_VISION_OBJECTS; obj_idx++) {
00792     vobj_info[obj_idx].reg = NULL;
00793   }
00794 
00795 
00796 //  findMarkers();
00797 //  bool rball_exist=findBall(getColor("red"),&obj_info->rball,&vobj_info[RBALL]);
00798   if (getColor("red")>=0)
00799     bool pball_exist=findBall(getColor("red"),&obj_info->pball,&vobj_info[PBALL]);
00800   /*
00801   bool hand_exist=findHand(&obj_info->hand,&vobj_info[HAND]);
00802   if (hand_exist
00803       && !(rball_exist && isIn(vobj_info[RBALL].reg,vobj_info[HAND].reg))
00804       && !(pball_exist && isIn(vobj_info[PBALL].reg,vobj_info[HAND].reg)))
00805       // hand exists and hand is not holding ball
00806     findGesture(&vobj_info[HAND]);*/
00807   return true;
00808 }
00809 
00810 bool Vision::thresholdImage(CMVision::image_idx<rgb> &img) {
00811   static rgb rgb_colors[MAX_COLORS];
00812   static bool initted=false;
00813 
00814   if(!initted) {
00815     for(int color_idx=0; color_idx<MAX_COLORS; color_idx++)
00816       rgb_colors[color_idx]=color[color_idx].color;
00817     initted=true;
00818   }
00819 
00820   CMVision::RgbToIndex(cmap,img.buf,width,height,rgb_colors,MAX_COLORS);
00821 
00822   return true;
00823 }
00824 
00825 bool Vision::thresholdImage(CMVision::image_yuv<const uchar> &img) {
00826   CMVision::ThresholdImageYUVPlanar<cmap_t,CMVision::image_yuv<const uchar>,const uchar,bits_y,bits_u,bits_v>(cmap,img,tmap);
00827 
00828   return true;
00829 }
00830 
00831 //#define ENABLE_JOIN_NEARBY
00832 
00833 #ifdef ENABLE_JOIN_NEARBY
00834 
00835 //#define DEBUG_JOIN
00836 
00837 #endif /* ENABLE_JOIN_NEARBY */
00838 
00839 //#define CHECK_REGIONS
00840 
00841 template<class image>
00842 bool Vision::runLowLevelVision(image &img)
00843 {
00844   static int frame_cnt=-1;
00845   frame_cnt++;
00846 
00847 #ifdef ENABLE_JOIN_NEARBY
00848   int num_runs_old;
00849 #endif
00850   int max_area;
00851 
00852   width  = img.width;
00853   height = img.height;
00854 
00855   thresholdImage(img);
00856   num_runs = CMVision::EncodeRuns(rmap,cmap,img.width,img.height,max_runs);
00857 
00858 #ifdef ENABLE_JOIN_NEARBY
00859   num_runs_old = num_runs;
00860 #endif
00861 
00862 #ifdef ENABLE_JOIN_NEARBY
00863   num_runs = CMVision::JoinNearbyRuns(rmap,rmap2,num_runs,width,height);
00864 #ifdef DEBUG_JOIN_PARANOID
00865   {
00866     bool ok=CMVision::CheckRuns(rmap2+1,num_runs-2,width,height);
00867     if(!ok) {
00868       printf("error in run data, consistency check failed\n");
00869     }
00870   }
00871 #endif
00872 #endif
00873 
00874 #ifdef ENABLE_JOIN_NEARBY
00875   memcpy(rmap,rmap2,sizeof(*rmap2)*max_runs);
00876 #endif
00877 
00878 #ifdef DEBUG_JOIN
00879   {
00880     bool ok=CMVision::CheckRuns(rmap+1,num_runs-2,width,height);
00881     if(!ok) {
00882       printf("error in run data, consistency check failed\n");
00883     }
00884   }
00885 #endif
00886 
00887   CMVision::ConnectComponents(rmap,num_runs);
00888 
00889   num_regions = CMVision::ExtractRegions(reg,max_regions,rmap,num_runs);
00890 
00891   //printf("runs:%6d (%6d) regions:%6d (%6d)\n",
00892   //        num_runs,max_runs,
00893   //        num_regions,max_regions);
00894 
00895   max_area = CMVision::SeparateRegions(color,num_colors,reg,num_regions);
00896   CMVision::SortRegions(color,num_colors,max_area);
00897 
00898   CMVision::MergeRegions(color,num_colors,rmap);
00899 
00900   for(int i=0; i<num_colors; i++)
00901     color[i].total_area = -1;
00902 
00903 #ifdef CHECK_REGIONS
00904   {
00905     bool ok=CMVision::CheckRegions(color,num_colors,rmap);
00906     if(!ok) {
00907       printf("CheckRegions failed\n");
00908     }
00909   }
00910 #endif
00911 
00912 //   CMVision::CreateRunIndex(yindex,rmap,num_runs);
00913   return(true);
00914 }
00915 
00916 bool Vision::processFrame(const uchar *data_y, const uchar *data_u, const uchar *data_v, int width, int height, int skip) {
00917   frameTimestamp = get_time();
00918   frame_count++;
00919 
00920   img.buf_y=data_y;
00921   img.buf_u=data_u;
00922   img.buf_v=data_v;
00923 
00924   img.width=width;
00925   img.height=height;
00926   //img.row_stride=3*width;
00927   img.row_stride=skip+width;
00928 
00929   bool ok=true;
00930 
00931   if(ok) ok=runLowLevelVision(img);
00932   if(ok) ok=runHighLevelVision(obj_info);
00933 
00934   vser->serialize();
00935 
00936   return ok;
00937 }
00938 
00939 int WritePPM(char *filename,rgb *img,int width,int height)
00940 {
00941   FILE *out;
00942   int wrote;
00943 
00944   out = fopen(filename,"wb");
00945   if(!out) return(0);
00946 
00947   fprintf(out,"P6\n%d %d\n%d\n",width,height,255);
00948   wrote = fwrite(img,sizeof(rgb),width*height,out);
00949   fclose(out);
00950 
00951   return(wrote);
00952 }
00953 
00954 bool Vision::saveThresholdImage(char *filename)
00955 {
00956   rgb *buf;
00957   int wrote;
00958 
00959   buf = new rgb[width * height];
00960   if(!buf) return(false);
00961 
00962   CMVision::IndexToRgb<cmap_t,color_class_state>(buf,cmap,width,height,color,num_colors);
00963   wrote = WritePPM(filename,buf,width,height);
00964   delete(buf);
00965 
00966   return(wrote > 0);
00967 }
00968 
00969 vector3d Vision::getPixelDirection(double x, double y) {
00970 /*  vector3d img_pixel_dir; // direction vector of pixel in image coordinates
00971                                                                                 
00972   img_pixel_dir.set((x+.5-width/2.0),(height/2.0-(y+.5))*YPixelSize,FocalDist);
00973                                                                                 
00974   vector3d robot_pixel_dir; // direction vector of pixel in robot coordinates
00975   robot_pixel_dir =
00976     camera_dir  *img_pixel_dir.z +
00977     camera_up   *img_pixel_dir.y +
00978     camera_right*img_pixel_dir.x;
00979                                                                                 
00980   robot_pixel_dir = robot_pixel_dir.norm();
00981                                                                                 
00982   return robot_pixel_dir;*/
00983 }
00984 
00985 /*! @file
00986  * @brief Does majority of vision processing
00987  * @author CMU RoboSoccer 2001-2002 (Creator)
00988  * @author alokl (ported)
00989  * 
00990  * @verbinclude CMPack_license.txt
00991  *
00992  * $Author: ejt $
00993  * $Name: tekkotsu-1_5 $
00994  * $Revision: 1.15 $
00995  * $State: Rel $
00996  * $Date: 2003/10/10 05:38:25 $
00997  */

Tekkotsu v1.5
Generated Fri Oct 10 15:52:00 2003 by Doxygen 1.3.4