model_blobfinder.cc
Go to the documentation of this file.
1 //
3 // File: model_blobfinder.c
4 // Author: Richard Vaughan
5 // Date: 10 June 2004
6 //
7 // CVS info:
8 // $Source: /home/tcollett/stagecvs/playerstage-cvs/code/stage/libstage/model_blobfinder.cc,v $
9 // $Author: rtv $
10 // $Revision$
11 //
13 
14 //#define DEBUG
15 
16 #include <sys/time.h>
17 
18 #include "stage.hh"
19 #include "option.hh"
20 #include "worldfile.hh"
21 using namespace Stg;
22 
23 static const watts_t DEFAULT_BLOBFINDERWATTS = 2.0;
24 static const meters_t DEFAULT_BLOBFINDERRANGE = 12.0;
25 static const radians_t DEFAULT_BLOBFINDERFOV = M_PI/3.0;
26 static const radians_t DEFAULT_BLOBFINDERPAN = 0.0;
27 static const unsigned int DEFAULT_BLOBFINDERINTERVAL_MS = 100;
28 static const unsigned int DEFAULT_BLOBFINDERRESOLUTION = 1;
29 static const unsigned int DEFAULT_BLOBFINDERSCANWIDTH = 80;
30 static const unsigned int DEFAULT_BLOBFINDERSCANHEIGHT = 60;
31 
32 
83  Model* parent,
84  const std::string& type ) :
85  Model( world, parent, type ),
86  vis( world ),
87  blobs(),
88  colors(),
89  fov( DEFAULT_BLOBFINDERFOV ),
90  pan( DEFAULT_BLOBFINDERPAN ),
91  range( DEFAULT_BLOBFINDERRANGE ),
92  scan_height( DEFAULT_BLOBFINDERSCANHEIGHT ),
93  scan_width( DEFAULT_BLOBFINDERSCANWIDTH )
94 {
95  PRINT_DEBUG2( "Constructing ModelBlobfinder %d (%s)\n",
96  id, typestr );
97  ClearBlocks();
98 
99  AddVisualizer( &this->vis, true );
100 }
101 
102 
104 {
105 }
106 
107 static bool blob_match( Model* candidate,
108  Model* finder,
109  const void* dummy )
110 {
111  (void)dummy; // avoid warning about unused var
112 
113  return( ! finder->IsRelated( candidate ));
114 }
115 
116 
117 static bool ColorMatchIgnoreAlpha( Color a, Color b )
118 {
119  double epsilon = 1e-5; // small
120  return( fabs(a.r - b.r) < epsilon &&
121  fabs(a.g - b.g) < epsilon &&
122  fabs(a.b - b.b) < epsilon );
123 }
124 
125 void ModelBlobfinder::ModelBlobfinder::AddColor( Color col )
126 {
127  colors.push_back( col );
128 }
129 
132 {
133  FOR_EACH( it, colors )
134  {
135  if( (*it) == col )
136  it = colors.erase(it);
137  }
138 }
139 
143 {
144  colors.clear();
145 }
146 
148 {
149  Model::Load();
150 
152 
153  wf->ReadTuple( wf_entity, "image", 0, 2, "uu", &scan_width, &scan_height );
154 
155  range = wf->ReadFloat( wf_entity, "range", range );
156  fov = wf->ReadAngle( wf_entity, "fov", fov );
157  pan = wf->ReadAngle( wf_entity, "pan", pan );
158 
159  if( wf->PropertyExists( wf_entity, "colors" ) )
160  {
161  RemoveAllColors(); // empty the color list to start from scratch
162 
163  unsigned int count = wf->ReadInt( wf_entity, "colors_count", 0 );
164 
165  for( unsigned int c=0; c<count; c++ )
166  {
167  char* colorstr = NULL;
168  wf->ReadTuple( wf_entity, "colors", c, 1, "s", &colorstr );
169 
170  if( ! colorstr )
171  break;
172  else
173  AddColor( Color( colorstr ));
174  }
175  }
176 }
177 
178 
180 {
181  // generate a scan for post-processing into a blob image
182 
183  RaytraceResult* samples = new RaytraceResult[scan_width];
184 
185  Raytrace( pan, range, fov, blob_match, NULL, samples, scan_width, false );
186 
187  // now the colors and ranges are filled in - time to do blob detection
188  double yRadsPerPixel = fov / scan_height;
189 
190  blobs.clear();
191 
192  // scan through the samples looking for color blobs
193  for(unsigned int s=0; s < scan_width; s++ )
194  {
195  if( samples[s].mod == NULL )
196  continue; // we saw nothing
197 
198  unsigned int right = s;
199  Color blobcol = samples[s].color;
200 
201  //printf( "blob start %d color %X\n", blobleft, blobcol );
202 
203  // loop until we hit the end of the blob
204  // there has to be a gap of >1 pixel to end a blob
205  // this avoids getting lots of crappy little blobs
206  while( s < scan_width && samples[s].mod &&
207  ColorMatchIgnoreAlpha( samples[s].color, blobcol) )
208  {
209  //printf( "%u blobcol %X block %p %s color %X\n", s, blobcol, samples[s].block, samples[s].block->Model()->Token(), samples[s].block->Color() );
210  s++;
211  }
212 
213  unsigned int left = s - 1;
214 
215  //if we have color filters in place, check to see if we're looking for this color
216  if( colors.size() )
217  {
218  bool found = false;
219 
220  for( unsigned int c=0; c<colors.size(); c++ )
221  if( ColorMatchIgnoreAlpha( blobcol, colors[c]))
222  {
223  found = true;
224  break;
225  }
226  if( ! found )
227  continue; // continue scanning array for next blob
228  }
229 
230  //printf( "blob end %d %X\n", blobright, blobcol );
231 
232  double robotHeight = 0.6; // meters
233 
234  // find the average range to the blob;
235  meters_t range = 0;
236  for( unsigned int t=right; t<=left; t++ )
237  range += samples[t].range;
238  range /= left-right + 1;
239 
240  double startyangle = atan2( robotHeight/2.0, range );
241  double endyangle = -startyangle;
242  int blobtop = scan_height/2 - (int)(startyangle/yRadsPerPixel);
243  int blobbottom = scan_height/2 -(int)(endyangle/yRadsPerPixel);
244 
245  blobtop = std::max( blobtop, 0 );
246  blobbottom = std::min( blobbottom, (int)scan_height );
247 
248  // fill in an array entry for this blob
249  Blob blob;
250  blob.color = blobcol;
251  blob.left = scan_width - left - 1;
252  blob.top = blobtop;
253  blob.right = scan_width - right - 1;;
254  blob.bottom = blobbottom;
255  blob.range = range;
256 
257  //printf( "Robot %p sees %d xpos %d ypos %d\n",
258  // mod, blob.color, blob.xpos, blob.ypos );
259 
260  // add the blob to our stash
261  //g_array_append_val( blobs, blob );
262  blobs.push_back( blob );
263  }
264 
265  delete [] samples;
266 
267  Model::Update();
268 }
269 
270 
272 {
273  Model::Startup();
274 
275  PRINT_DEBUG( "blobfinder startup" );
276 
277  // start consuming power
279 }
280 
282 {
283 
284  PRINT_DEBUG( "blobfinder shutdown" );
285 
286  // stop consuming power
287  SetWatts( 0 );
288 
289  // clear the data - this will unrender it too
290  blobs.clear();
291 
292  Model::Shutdown();
293 }
294 
295 //******************************************************************************
296 // visualization
297 
298 //TODO make instance attempt to register an option (as customvisualizations do)
299 // Option ModelBlobfinder::showBlobData( "Show Blobfinder", "show_blob", "", true, NULL );
300 
302  : Visualizer( "Blobfinder", "blobfinder_vis" )
303 {
304 
305  //world->RegisterOption( &showArea );
306  //world->RegisterOption( &showStrikes );
307  //world->RegisterOption( &showFov );
308  //world->RegisterOption( &showBeams );
309 }
310 
312 {
313  ModelBlobfinder* bf( dynamic_cast<ModelBlobfinder*>(mod) );
314 
315  if( bf->debug )
316  {
317  // draw the FOV
318  GLUquadric* quadric = gluNewQuadric();
319 
320  bf->PushColor( 0,0,0,0.2 );
321 
322  gluQuadricDrawStyle( quadric, GLU_SILHOUETTE );
323  gluPartialDisk( quadric,
324  0,
325  bf->range,
326  20, // slices
327  1, // loops
328  rtod( M_PI/2.0 + bf->fov/2.0 - bf->pan), // start angle
329  rtod(-bf->fov) ); // sweep angle
330 
331  gluDeleteQuadric( quadric );
332  bf->PopColor();
333  }
334 
335  if( bf->subs < 1 )
336  return;
337 
338  glPushMatrix();
339 
340  // return to global rotation frame
341  Pose gpose( bf->GetGlobalPose() );
342  glRotatef( rtod(-gpose.a),0,0,1 );
343 
344  // place the "screen" a little away from the robot
345  glTranslatef( -2.5, -1.5, 0.5 );
346 
347  // rotate to face screen
348  float yaw, pitch;
349  pitch = - cam->pitch();
350  yaw = - cam->yaw();
351  float robotAngle = -rtod(bf->pose.a);
352  glRotatef( robotAngle - yaw, 0,0,1 );
353  glRotatef( -pitch, 1,0,0 );
354 
355  // convert blob pixels to meters scale - arbitrary
356  glScalef( 0.025, 0.025, 1 );
357 
358  // draw a white screen with a black border
359  bf->PushColor( 1,1,1,1 );
360  glRectf( 0,0, bf->scan_width, bf->scan_height );
361  bf->PopColor();
362 
363  glTranslatef(0,0,0.01 );
364 
365  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
366  bf->PushColor( 1,0,0,1 );
367  glRectf( 0,0, bf->scan_width, bf->scan_height );
368  bf->PopColor();
369  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
370 
371  // draw the blobs on the screen
372  for( unsigned int s=0; s<bf->blobs.size(); s++ )
373  {
374  Blob* b = &bf->blobs[s];
375  //blobfinder_blob_t* b =
376  //&g_array_index( blobs, blobfinder_blob_t, s);
377 
378  bf->PushColor( b->color );
379  glRectf( b->left, b->top, b->right, b->bottom );
380 
381  //printf( "%u l %u t%u r %u b %u\n", s, b->left, b->top, b->right, b->bottom );
382  bf->PopColor();
383  }
384 
385  glPopMatrix();
386 }
387 
388 
unsigned int scan_height
Definition: stage.hh:2516
virtual void PushColor(Color col)
Definition: stage.hh:2189
Model class
Definition: stage.hh:1742
Worldfile * GetWorldFile()
Definition: stage.hh:1123
static const radians_t DEFAULT_BLOBFINDERFOV
std::vector< Blob > blobs
Definition: stage.hh:2506
void AddColor(Color col)
int subs
the number of subscriptions to this model
Definition: stage.hh:1959
static const meters_t DEFAULT_BLOBFINDERRANGE
World class
Definition: stage.hh:814
The Stage library uses its own namespace.
Definition: canvas.hh:8
int ReadTuple(const int entity, const char *name, const unsigned int first, const unsigned int num, const char *format,...)
Definition: worldfile.cc:1506
std::vector< Color > colors
Definition: stage.hh:2507
#define PRINT_DEBUG2(m, a, b)
Definition: stage.hh:668
static const unsigned int DEFAULT_BLOBFINDERSCANHEIGHT
double yaw(void) const
Definition: stage.hh:1378
virtual void PopColor()
Definition: stage.hh:2191
RaytraceResult Raytrace(const Pose &pose, const meters_t range, const ray_test_func_t func, const void *arg, const bool ztest=true)
Definition: model.cc:475
float s
Definition: glutgraphics.cc:58
Worldfile * wf
Definition: stage.hh:2015
ModelBlobfinder(World *world, Model *parent, const std::string &type)
static const watts_t DEFAULT_BLOBFINDERWATTS
void RemoveColor(Color col)
double watts_t
Definition: stage.hh:195
bool IsRelated(const Model *testmod) const
Definition: model.cc:570
int wf_entity
Definition: stage.hh:2016
double r
Definition: stage.hh:200
Pose GetGlobalPose() const
Definition: model.cc:1379
bool PropertyExists(int section, const char *token)
Definition: worldfile.cc:1324
double rtod(double r)
Definition: stage.hh:148
double meters_t
Definition: stage.hh:174
static bool blob_match(Model *candidate, Model *finder, const void *dummy)
Color color
the color struck by this beam
Definition: stage.hh:747
static const unsigned int DEFAULT_BLOBFINDERRESOLUTION
void AddVisualizer(Visualizer *custom_visual, bool on_by_default)
Definition: model_draw.cc:322
virtual void Startup()
Definition: model.cc:707
double b
Definition: stage.hh:200
static uint32_t count
Definition: stage.hh:1758
virtual void Update()
Definition: model.cc:735
double g
Definition: stage.hh:200
virtual void Visualize(Model *mod, Camera *cam)
static const unsigned int DEFAULT_BLOBFINDERSCANWIDTH
static const unsigned int DEFAULT_BLOBFINDERINTERVAL_MS
virtual void Load()
Definition: model.cc:1422
double pitch(void) const
Definition: stage.hh:1379
Pose pose
Definition: stage.hh:1916
double ReadFloat(int entity, const char *name, double value)
Definition: worldfile.cc:1434
bool debug
Definition: stage.hh:691
void SetWatts(watts_t watts)
Definition: model.cc:1338
World * world
Definition: stage.hh:2017
static const radians_t DEFAULT_BLOBFINDERPAN
int ReadInt(int entity, const char *name, int value)
Definition: worldfile.cc:1398
virtual void Shutdown()
Definition: model.cc:723
#define FOR_EACH(I, C)
Definition: stage.hh:616
radians_t a
rotation about the z axis.
Definition: stage.hh:252
#define PRINT_DEBUG(m)
Definition: stage.hh:666
Stg::ModelBlobfinder::Vis vis
Color color
Definition: stage.hh:1859
double ReadAngle(int entity, const char *name, double value)
Definition: worldfile.hh:116
ModelBlobfinder class
Definition: stage.hh:2483
double radians_t
Definition: stage.hh:177
static bool ColorMatchIgnoreAlpha(Color a, Color b)
void ClearBlocks()
Definition: model.cc:421
unsigned int scan_width
Definition: stage.hh:2517


stage
Author(s): Richard Vaughan , Brian Gerkey , Reed Hedges , Andrew Howard , Toby Collett , Pooya Karimian , Jeremy Asher , Alex Couture-Beil , Geoff Biggs , Rich Mattes , Abbas Sadat
autogenerated on Mon Jun 10 2019 15:06:09