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