roi.cpp

00001
00002 /***************************************************************************
00003  *  roi.cpp - Implementation for Region Of Interest (ROI) representation
00004  *
00005  *  Generated: Thu Jul 14 12:01:58 2005
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <fvutils/base/roi.h>
00025
00026 #include <cstdlib>
00027
00028 using namespace fawkes;
00029 
00030 /** @class ROI <fvutils/base/roi.h>
00031  * Region of interest.
00032  * The ROI class is central to FireVision. All image processing is concentrated
00033  * on the pre-classified interesting parts of the image, denoted by the
00034  * regions of interest (ROIs).
00035  *
00036  * A ROI is a rectangular area of the image. Its start is denoted by the upper
00037  * left corner of this rectangle and the size is given by its width and height.
00038  *
00039  * @author Tim Niemueller
00040  */
00041
00042 ROI* ROI::roi_full_image = NULL;
00043
00044 
00045 /** Constructor. */
00046 ROI::ROI()
00047 {
00048   num_hint_points = 1;
00049   start.x = start.y = width = height = image_width = image_height = line_step = pixel_step = 0;
00050 }
00051
00052 
00053 /** Constructor.
00054  * @param start_x Upper left corner of ROI X coordinate
00055  * @param start_y Upper left corner of ROI y coordinate
00056  * @param width Width of extent of ROI
00057  * @param height height of extent of ROI
00058  * @param image_width width of full image this ROI belongs to
00059  * @param image_height height of full image this ROI belongs to
00060  */
00061 ROI::ROI(unsigned int start_x, unsigned int start_y,
00062          unsigned int width, unsigned int height,
00063          unsigned int image_width, unsigned int image_height)
00064 {
00065   num_hint_points = 1;
00066   start.x = start_x;
00067   start.y = start_y;
00068   this->width = width;
00069   this->height = height;
00070   this->image_width = image_width;
00071   this->image_height = image_height;
00072   line_step = image_width;
00073   pixel_step = 1;
00074 }
00075
00076 
00077 /** Copy constructor.
00078  * @param roi reference to ROI to copy
00079  */
00080 ROI::ROI(const ROI &roi)
00081 {
00082   start           = roi.start;
00083   width           = roi.width;
00084   height          = roi.height;
00085   image_width     = roi.image_width;
00086   image_height    = roi.image_height;
00087   line_step       = roi.line_step;
00088   pixel_step      = roi.pixel_step;
00089   hint            = roi.hint;
00090   num_hint_points = roi.num_hint_points;
00091 }
00092
00093 
00094 /** Copy constructor.
00095  * @param roi pointer to ROI to copy
00096  */
00097 ROI::ROI(const ROI *roi)
00098 {
00099   start           = roi->start;
00100   width           = roi->width;
00101   height          = roi->height;
00102   image_width     = roi->image_width;
00103   image_height    = roi->image_height;
00104   line_step       = roi->line_step;
00105   pixel_step      = roi->pixel_step;
00106   hint            = roi->hint;
00107   num_hint_points = roi->num_hint_points;
00108 }
00109
00110 
00111 /** Set upper left corner of ROI.
00112  * @param p point
00113  */
00114 void
00115 ROI::set_start(point_t p)
00116 {
00117   start.x = p.x;
00118   start.y = p.y;
00119 }
00120
00121 
00122 /** Set upper left corner.
00123  * @param x x coordinate in image
00124  * @param y y coordinate in image
00125  */
00126 void
00127 ROI::set_start(unsigned int x, unsigned int y)
00128 {
00129   start.x = x;
00130   start.y = y;
00131 }
00132
00133 
00134 /** Set width of ROI.
00135  * @param width new width
00136  */
00137 void
00138 ROI::set_width(unsigned int width)
00139 {
00140   this->width = width;
00141 }
00142
00143 
00144 /** Get width of ROI.
00145  * @return width
00146  */
00147 unsigned int
00148 ROI::get_width() const
00149 {
00150   return width;
00151 }
00152
00153 
00154 /** Set height of ROI.
00155  * @param height new height
00156  */
00157 void
00158 ROI::set_height(unsigned int height)
00159 {
00160   this->height = height;
00161 }
00162
00163 
00164 /** Get height of ROI.
00165  * @return height
00166  */
00167 unsigned int
00168 ROI::get_height() const
00169 {
00170   return height;
00171 }
00172
00173 
00174 /** Set full image width.
00175  * Set the width of the image that contains this ROI.
00176  * @param image_width full width of image.
00177  */
00178 void
00179 ROI::set_image_width(unsigned int image_width)
00180 {
00181   this->image_width = image_width;
00182 }
00183
00184 
00185 /** Get full image width.
00186  * Get the width of the image that contains this ROI.
00187  * @return full width of image.
00188  */
00189 unsigned int
00190 ROI::get_image_width() const
00191 {
00192   return image_width;
00193 }
00194
00195 
00196 /** Set full image height
00197  * Set the height of the image that contains this ROI.
00198  * @param image_height full height of image.
00199  */
00200 void
00201 ROI::set_image_height(unsigned int image_height)
00202 {
00203   this->image_height = image_height;
00204 }
00205
00206 
00207 /** Get full image height.
00208  * Get the height of the image that contains this ROI.
00209  * @return full height of image.
00210  */
00211 unsigned int
00212 ROI::get_image_height() const
00213 {
00214   return image_height;
00215 }
00216
00217 
00218 /** Set linestep.
00219  * The linestep is the offset in bytes from the beginning of one line
00220  * in the buffer to the beginning of the next line.
00221  * @param step new line step
00222  */
00223 void
00224 ROI::set_line_step(unsigned int step)
00225 {
00226   line_step = step;
00227 }
00228
00229 
00230 /** Get linestep.
00231  * @return line step
00232  * @see setLineStep()
00233  */
00234 unsigned int
00235 ROI::get_line_step() const
00236 {
00237   return line_step;
00238 }
00239
00240 
00241 /** Set pixel step.
00242  * The pixel step is the offset in bytes to get from one pixel to the next
00243  * in the buffer.
00244  * @param step new pixel step.
00245  */
00246 void
00247 ROI::set_pixel_step(unsigned int step)
00248 {
00249   pixel_step = step;
00250 }
00251
00252 
00253 /** Get pixel step.
00254  * @return pixel step.
00255  * @see setPixelStep()
00256  */
00257 unsigned int
00258 ROI::get_pixel_step() const
00259 {
00260   return pixel_step;
00261 }
00262
00263 
00264 /** Get hint.
00265  * The hint gives an intuition what is in the ROI. In most cases this will
00266  * depend on the color that the classifier used.
00267  * @return hint
00268  */
00269 hint_t
00270 ROI::get_hint() const
00271 {
00272   return hint;
00273 }
00274
00275 
00276 /** Set hint.
00277  * @param hint new hint
00278  * @see getHint()
00279  */
00280 void
00281 ROI::set_hint(hint_t hint)
00282 {
00283   this->hint = hint;
00284 }
00285
00286 
00287 /** Check if this ROI contains the given coordinates.
00288  * @param x x coordinate in image
00289  * @param y y coordinate in image
00290  * @return true if this ROI contains the given point, false otherwise
00291  */
00292 bool
00293 ROI::contains(unsigned int x, unsigned int y)
00294 {
00295   if ( (x >= start.x) &&
00296        (x <= start.x+width) &&
00297        (y >= start.y) &&
00298        (y <= start.y+height) ) {
00299
00300     num_hint_points += 1;
00301     return true;
00302   } else {
00303     return false;
00304   }
00305 }
00306
00307 
00308 /** Check if this ROI neighbours a pixel.
00309  * This checks if the given pixel is close to this ROI considered with
00310  * the given margin.
00311  * @param x x coordinate in image
00312  * @param y y coordinate in image
00313  * @param margin margin
00314  * @return true if this ROI is a neigbour of the given pixel, false otherwise
00315  */
00316 bool
00317 ROI::neighbours(unsigned int x, unsigned int y, unsigned int margin) const
00318 {
00319   return ( (static_cast<int>(x) >= static_cast<int>(start.x) - static_cast<int>(margin)) &&
00320            (x <= start.x + width + margin) &&
00321            (static_cast<int>(y) >= static_cast<int>(start.y) - static_cast<int>(margin)) &&
00322            (y <= start.y + height + margin) );
00323 }
00324
00325 
00326 /** Check if this ROI neighbours another ROI.
00327  * This checks if the given ROI is close to this ROI considered with
00328  * the given margin.
00329  * @param roi ROI
00330  * @param margin margin
00331  * @return true if this ROI is a neigbour of the given ROI, false otherwise
00332  */
00333 bool
00334 ROI::neighbours(ROI *roi, unsigned int margin) const
00335 {
00336   //Testing only x -> y test returns always true
00337   bool overlapping_x = neighbours(roi->start.x, start.y, margin)
00338     || neighbours(roi->start.x + roi->width, start.y, margin)
00339     || roi->neighbours(start.x, roi->start.y, margin)
00340     || roi->neighbours(start.x + width, roi->start.y, margin);
00341
00342   //Testing only y -> x test returns always true
00343   bool overlapping_y = roi->neighbours(roi->start.x, start.y, margin)
00344     || roi->neighbours(roi->start.x, start.y + height, margin)
00345     || neighbours(start.x, roi->start.y, margin)
00346     || neighbours(start.x, roi->start.y + roi->height, margin);
00347
00348   return overlapping_x && overlapping_y;
00349 }
00350
00351 
00352 /** Extend ROI to include given pixel.
00353  * @param x x coordinate of pixel to include
00354  * @param y y coordinate of pixel to include
00355  */
00356 void
00357 ROI::extend(unsigned int x, unsigned int y)
00358 {
00359
00360   if (x < start.x) { width  += start.x - x; start.x = x; }
00361   if (y < start.y) { height += start.y - y; start.y = y; }
00362   if (x > start.x + width)  { width  += (x - (start.x + width)); }
00363   if (y > start.y + height) { height += (y - (start.y + height)); }
00364
00365   num_hint_points += 1;
00366 }
00367
00368 
00369 /** Grow this ROI by a given margin.
00370  * @param margin margin to grow by
00371  */
00372 void
00373 ROI::grow(unsigned int margin)
00374 {
00375   if (start.x < margin) {
00376     start.x = 0;
00377   } else {
00378     start.x -= margin;
00379   }
00380
00381   if (start.y < margin) {
00382     start.y = 0;
00383   } else {
00384     start.y -= margin;
00385   }
00386
00387   if ((start.x + width + margin) > image_width) {
00388     width += (image_width - (start.x + width));
00389   } else {
00390     width += margin;
00391   }
00392
00393   if ((start.y + height + margin) > image_height) {
00394     height += (image_height - (start.y + height));
00395   } else {
00396     height += margin;
00397   }
00398
00399 }
00400
00401 
00402 /** Merge two ROIs.
00403  * This ROI will be extended in any direction necessary to fully include the given
00404  * ROI.
00405  * @param roi ROI to include
00406  * @return this instance
00407  */
00408 ROI&
00409 ROI::operator+=(ROI &roi)
00410 {
00411
00412   if (roi.start.x < start.x) { width  += start.x - roi.start.x; start.x = roi.start.x; }
00413   if (roi.start.y < start.y) { height += start.y - roi.start.y; start.y = roi.start.y; }
00414   if (roi.start.x + roi.width  > start.x + width)  { width  += roi.start.x + roi.width  - (start.x + width); }
00415   if (roi.start.y + roi.height > start.y + height) { height += roi.start.y + roi.height - (start.y + height); }
00416
00417   num_hint_points += roi.num_hint_points;
00418
00419   return *this;
00420 }
00421
00422 
00423 /** Check if this ROI contains less hint points than the given ROI.
00424  * @param roi ROI to compare to.
00425  * @return true, if the this ROI is smaller, false otherwise
00426  */
00427 bool
00428 ROI::operator<(const ROI &roi) const
00429 {
00430   return (num_hint_points < roi.num_hint_points);
00431 }
00432
00433 
00434 /** Check if this ROI contains more hint points than the given ROI.
00435  * @param roi ROI to compare to.
00436  * @return true, if the this ROI is greater, false otherwise
00437  */
00438 bool
00439 ROI::operator>(const ROI &roi) const
00440 {
00441   return (num_hint_points > roi.num_hint_points);
00442 }
00443
00444 
00445 /** Check if this ROI marks the same region for the same object
00446  * and an image of the same base size and step parameters like the
00447  * given ROI.
00448  * @param roi ROI to compare to
00449  * @return true, if ROIs are similar, false otherwise
00450  */
00451 bool
00452 ROI::operator==(const ROI &roi) const
00453 {
00454   return  (start.x == roi.start.x) &&
00455           (start.y == roi.start.y) &&
00456           (width == roi.width) &&
00457           (height == roi.height) &&
00458           (image_width == roi.image_width) &&
00459           (image_height == roi.image_height) &&
00460           (line_step == roi.line_step) &&
00461           (pixel_step == roi.pixel_step) &&
00462           (hint == roi.hint) &&
00463           (num_hint_points == roi.num_hint_points);
00464 }
00465
00466 
00467 /** Check if this ROI does not mark the same region for the same object
00468  * and an image of the same base size and step parameters like the
00469  * given ROI.
00470  * @param roi ROI to compare to
00471  * @return true, if ROIs are not similar, false otherwise
00472  */
00473 bool
00474 ROI::operator!=(const ROI &roi) const
00475 {
00476   return (num_hint_points != roi.num_hint_points);
00477 }
00478
00479 
00480 /** Assign the given ROI data to this ROI.
00481  * @param roi ROI to copy
00482  * @return this instance
00483  */
00484 ROI&
00485 ROI::operator=(const ROI &roi)
00486 {
00487   this->start.x         = roi.start.x;
00488   this->start.y         = roi.start.y;
00489   this->width           = roi.width;
00490   this->height          = roi.height;
00491   this->image_width     = roi.image_width;
00492   this->image_height    = roi.image_height;
00493   this->line_step       = roi.line_step;
00494   this->pixel_step      = roi.pixel_step;
00495   this->hint            = roi.hint;
00496   this->num_hint_points = roi.num_hint_points;
00497
00498   return *this;
00499 }
00500 
00501 /** Get ROI buffer start.
00502  * This uses the ROI's step and start data to calculate where
00503  * the ROI starts in the given buffer.
00504  * @param buffer buffer
00505  * @return pointer into buffer where the ROI starts
00506  */
00507 unsigned char*
00508 ROI::get_roi_buffer_start(unsigned char *buffer) const
00509 {
00510   return (buffer + (start.y * line_step) + (start.x * pixel_step));
00511 }
00512
00513 
00514 /** Gives an estimate of the number of points in this ROI that
00515  * are classified to the given hint
00516  * It is: num_hint_points <= total_num_of_scanline_points
00517  * If you call contains and the point is actually included in
00518  * this ROI this number is incremented. So you need to make
00519  * sure to only call contains() for a point of the given hint
00520  * class. This should always be the case anyway.
00521  * If you extend the region by one very point the number will
00522  * be incremented by one although the region may grow by more
00523  * than just one point of the hint class.
00524  * If you merge to ROIs by using the += operator this region
00525  * adds the number of hint points of the region being merged
00526  * to its own number. The region may grow by more than this
00527  * number of points though.
00528  * @return an estimate of the number of points of the hint class
00529  *
00530  */
00531 unsigned int
00532 ROI::get_num_hint_points() const
00533 {
00534   return num_hint_points;
00535 }
00536
00537 
00538 /** Get full image ROI for given size.
00539  * Shortcut to get a full size ROI. This ROI is a static member so this
00540  * method is not thread-safe or reentrant. It is also only valid until the
00541  * next call to full_image() with different parameters. Line step is assumed
00542  * to be the image width, the pixel step is assumed to be one. So this is
00543  * only useful for b/w or planar images.
00544  * @param width image width
00545  * @param height image height
00546  * @return full image ROI
00547  */
00548 ROI *
00549 ROI::full_image(unsigned int width, unsigned int height)
00550 {
00551   if (roi_full_image == NULL) {
00552     roi_full_image = new ROI();
00553     roi_full_image->start.x      = 0;
00554     roi_full_image->start.y      = 0;
00555     roi_full_image->pixel_step   = 1;
00556   }
00557   roi_full_image->width        = width;
00558   roi_full_image->height       = height;
00559   roi_full_image->image_width  = roi_full_image->width;
00560   roi_full_image->image_height = roi_full_image->height;
00561   roi_full_image->line_step    = roi_full_image->width;
00562
00563   return roi_full_image;
00564 }