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