Rectangle.H

Go to the documentation of this file.
00001 /*!@file Image/Rectangle.H A basic rectangle class */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/Rectangle.H $
00035 // $Id: Rectangle.H 13892 2010-09-08 16:49:40Z lior $
00036 //
00037 
00038 #ifndef RECTANGLE_H_DEFINED
00039 #define RECTANGLE_H_DEFINED
00040 
00041 #include "Image/Dims.H"
00042 #include "Image/Point2D.H"
00043 #include "Util/Assert.H"
00044 
00045 #include <algorithm>
00046 #include <string> // for string conversions
00047 
00048 //! A basic rectangle class
00049 /*! This is a shorthand class to represent a 2D rectangle, as defined
00050     by integer top, left, bottom and right coordinates.  The goal of
00051     this object is not to have to check if left < right, etc...  for
00052     each function using a Rectangle. The object checks for that at its
00053     creation, and is always internally coherent.  Image convention:
00054     top < bottom, left < right.
00055 
00056     There is often some ambiguity about how to represent the
00057     left-right and top-bottom ranges involved in a rectangle. Imagine
00058     a pixel grid like this:
00059 
00060     +---+---+---+---+
00061     |   |   |   |   |
00062     |   |   |   |   |
00063     +---+---+---+---+
00064     |   |   |   |   |
00065     |   |   |   |   |
00066     +---+---+---+---+
00067     |   |   |   |   |
00068     |   |   |   |   |
00069     +---+---+---+---+
00070     |   |   |   |   |
00071     |   |   |   |   |
00072     +---+---+---+---+
00073 
00074 
00075     If we want a Rectangle that covers this whole 4x4 grid, how should
00076     we represent the coordinates? Clearly the upper left corner is
00077     (0,0), but what about the bottom right corner? One answer would be
00078     that the lower right corner is (4,4), in which we imagine the
00079     coordinate numbers falling between the cracks of the pixels:
00080 
00081     . 0...1...2...3...4
00082     0 +---+---+---+---+
00083     . |   |   |   |   |
00084     . |   |   |   |   |
00085     1 +---+---+---+---+
00086     . |   |   |   |   |
00087     . |   |   |   |   |
00088     2 +---+---+---+---+
00089     . |   |   |   |   |
00090     . |   |   |   |   |
00091     3 +---+---+---+---+
00092     . |   |   |   |   |
00093     . |   |   |   |   |
00094     4 +---+---+---+---+
00095 
00096     Another answer is that the lower right corner should be labeled as
00097     (3,3), if we envision the coordinate numbers labeling the pixel
00098     centers, and this approach is more natural if we want to draw a
00099     line just inside the border of the rectangle as shown by the '*'
00100     here:
00101 
00102     . ..0...1...2...3..
00103     . +---+---+---+---+
00104     0 |***|***|***|***|
00105     . |***|***|***|***|
00106     . +---+---+---+---+
00107     1 |***|   |   |***|
00108     . |***|   |   |***|
00109     . +---+---+---+---+
00110     2 |***|   |   |***|
00111     . |***|   |   |***|
00112     . +---+---+---+---+
00113     3 |***|***|***|***|
00114     . |***|***|***|***|
00115     . +---+---+---+---+
00116 
00117     In the Rectangle class we support both approaches; the (4,4)
00118     coords are called 'outer' coordinates and corresponding functions
00119     have a 'O' suffix (bottomO(), right(), and tlbrO()), while the
00120     (3,3) coords are called 'inner' coordinates and corresponding
00121     functions have an 'I' suffix (bottomI(), rightI(), and tlbrI()).
00122 
00123     The internal representation of Rectangle is based on outer
00124     coordinates, but this has no effect on users of the class who are
00125     free to user whichever of inner or outer coords are more
00126     convenient for their purposes.
00127 
00128     Outer coordinates are more natural for uniformly scaling a
00129     rectangle up or down by a factor. For example, if we want to scale
00130     the 4x4 rect up by a factor of 2 giving an 8x8 rect, then in outer
00131     coords we just do newright=right*2=4*2=8 and
00132     newbottom=bottom*2=4*2=8. But with inner coords we can't just
00133     multiply by 2: the inner bottom-right coords are (3,3), and if we
00134     scale those by 2 we get (6,6) which represents a 7x7 rectangle
00135     rather than the correct 8x8 result.
00136 
00137     HISTORICAL NOTE (2007-Mar-20): The Rectangle class previously used
00138     only inner coordinates both for its implementation and in its
00139     public interface. This lead to clunky code in some places where
00140     many -1 or +1 offsets were needed to handle rectangle coordinates.
00141 */
00142 
00143 class Rectangle {
00144 
00145   //! Private constructor; use the tlbrO() pseudo-constructor if you want to call this publicly
00146   inline Rectangle(int tt, int ll, int bb1, int rr1);
00147 
00148 public:
00149   // ############################################################
00150   // ##### Constructors & Destructors:
00151   // ############################################################
00152 
00153   //! Build from 4 coordinates (top, left, inner-bottom, inner-right)
00154   static inline Rectangle tlbrI(int tt, int ll, int bb, int rr);
00155 
00156   //! Build from 4 coordinates (top, left, outer-bottom, outer-right)
00157   static inline Rectangle tlbrO(int tt, int ll, int bb, int rr);
00158 
00159   //! Build from center loc and dims
00160   static inline Rectangle centerDims(const Point2D<int>& center, const Dims& dims);
00161 
00162   //! Build from a top-left corner and some dims
00163   inline Rectangle(const Point2D<int>& topleft, const Dims& dims);
00164 
00165   //! Copy constructor
00166   inline Rectangle(const Rectangle& rect);
00167 
00168   //! Uninitialized constructor (useful for arrays).
00169   inline Rectangle();
00170 
00171   // Default assignment operator ok
00172 
00173   // ############################################################
00174   // ##### Access functions:
00175   // ############################################################
00176 
00177   //! get overlap between this rectangle and passed in rectangle
00178   inline Rectangle getOverlap(const Rectangle& r2) const;
00179 
00180   //! compute overlap as area of intersection / area of union
00181   inline double getOverlapRatio(const Rectangle& r2) const;
00182 
00183   //! check if point p is within rectangle
00184   /*! CAUTION: boundaries are included. */
00185   inline bool contains(const Point2D<int>& p) const;
00186 
00187   //! check if this rect contains another
00188   /*! The boundaries are allowed to coincide, such that by this
00189       definition a rectangle "contains" itself. */
00190   inline bool contains(const Rectangle& r) const;
00191 
00192   inline int top() const;     //!< get (inner) top coordinate
00193   inline int bottomI() const; //!< get inner bottom coordinate (=top+height-1)
00194   inline int bottomO() const; //!< get outer bottom coordinate (=top+height)
00195   inline int left() const;    //!< get (inner) left coordinate
00196   inline int rightI() const;  //!< get inner right coordinate (=left+width-1)
00197   inline int rightO() const;  //!< get outer right coordinate (=left+width)
00198 
00199   inline Point2D<int> topLeft() const;     //!< Get (outer) top left corner point
00200   inline Point2D<int> topRight() const;    //!< Get (outer) top right corner point
00201   inline Point2D<int> bottomLeft() const;  //!< Get (outer) bottom left corner point
00202   inline Point2D<int> bottomRight() const; //!< Get (outer) bottom right corner point
00203 
00204   //! Get the rectangle's width, height
00205   inline Dims dims() const;
00206 
00207   //! Access some metric info
00208   inline int width() const;
00209   //! Access some metric info
00210   inline int height() const;
00211   //! Access some metric info
00212   inline int area() const;
00213   //! Access some metric info
00214   inline float aspect() const;
00215 
00216   //!The center of the rectangle
00217   inline Point2D<int> center() const;
00218 
00219   //! whether the rectangle is valid
00220   inline bool isValid() const;
00221 
00222 private:
00223   inline void tlbrInitOuter(int tt, int ll, int bb1, int rr1);
00224 
00225   bool valid;       //!< True if Rectangle contains something coherent
00226   int t, b1, l, r1;   //!< top, bottom, left, right
00227 };
00228 
00229 
00230 // ######################################################################
00231 // Rectangle FREE FUNCTIONS:
00232 // ######################################################################
00233 
00234 // ######################################################################
00235 //! Rectangle overload: format is "<int>,<int>,<int>,<int>"
00236 /*! Format corresponds to "xtopleft,ytopleft,xbottomright,ybottomright" */
00237 std::string convertToString(const Rectangle& val);
00238 
00239 // ######################################################################
00240 //! Rectangle overload: format is "<int>,<int>,<int>,<int>"
00241 void convertFromString(const std::string& str, Rectangle& val);
00242 
00243 
00244 // ######################################################################
00245 //! Return a new rectangle that is a constrained version of the input.
00246 /*! @param in The original rectangle on which to base the constrained
00247     output.
00248 
00249     @param bounds The output rectangle will be constrained to be
00250     contained within these bounds.
00251 
00252     @param minw The minimum width for the output rectangle. Caller
00253     must ensure minw>=0. If the output rectangle would naturally be
00254     narrower than this width, then it will be widened to the smaller
00255     of minw and bounds.width().
00256 
00257     @param maxw The maximum width for the output rectangle. Caller
00258     must ensure maxw>=minw. If the output rectangle would naturally be
00259     wider than this width, then it will be narrowed to the smaller of
00260     maxw and bounds.width().
00261 
00262     @param minh The minimum height for the output rectangle. Caller
00263     must ensure minh>=0. If the output rectangle would naturally be
00264     shorter than this height, then it will be lengthened to the
00265     smaller of minh and bounds.height().
00266 
00267     @param maxh The maximum height for the output rectangle. Caller
00268     must ensure maxh>=minh. If the output rectangle would naturally be
00269     taller than this height, then it will be shortened to the smaller
00270     of maxh and bounds.height().
00271 
00272     @return The result is guaranteed to be such that the following
00273     conditions are all true:
00274     \code
00275     bounds.contains(result);
00276     result.width() >= std::min(minw, bounds.width());
00277     result.width() <= std::min(maxw, bounds.width());
00278     result.height() >= std::min(minh, bounds.height());
00279     result.height() <= std::min(maxh, bounds.height());
00280     \endcode
00281 */
00282 Rectangle constrainRect(const Rectangle& in,
00283                         const Rectangle& bounds,
00284                         int minw, int maxw,
00285                         int minh, int maxh);
00286 
00287 
00288 // ######################################################################
00289 //! Like the main constrainRect(), but use the same limits for width as for height
00290 inline Rectangle constrainRect(const Rectangle& in,
00291                                const Rectangle& bounds,
00292                                int minsz, int maxsz)
00293 {
00294   return constrainRect(in, bounds, minsz, maxsz, minsz, maxsz);
00295 }
00296 
00297 // ######################################################################
00298 inline bool operator==(const Rectangle& r1, const Rectangle& r2)
00299 {
00300   if (!r1.isValid() || !r2.isValid()) return r1.isValid() == r2.isValid();
00301 
00302   return (r1.top() == r2.top() &&
00303           r1.bottomO() == r2.bottomO() &&
00304           r1.left() == r2.left() &&
00305           r1.rightO() == r2.rightO());
00306 }
00307 
00308 // ######################################################################
00309 inline Rectangle operator*(const Rectangle& r, const double s)
00310 {
00311   if (!r.isValid())
00312     return Rectangle();
00313   else
00314     return Rectangle::tlbrO(int(r.top() * s),
00315                             int(r.left() * s),
00316                             int(r.bottomO() * s),
00317                             int(r.rightO() * s));
00318 }
00319 
00320 // ######################################################################
00321 inline Rectangle operator*(const Rectangle& r, const int s)
00322 {
00323   if (!r.isValid())
00324     return Rectangle();
00325   else
00326     return Rectangle::tlbrO(r.top() * s,
00327                             r.left() * s,
00328                             r.bottomO() * s,
00329                             r.rightO() * s);
00330 }
00331 
00332 // ######################################################################
00333 inline Rectangle operator/(const Rectangle& r, const int div)
00334 {
00335   if (!r.isValid() || div == 0)
00336     return Rectangle();
00337   else
00338     return Rectangle::tlbrO(r.top() / div,
00339                             r.left() / div,
00340                             r.bottomO() / div,
00341                             r.rightO() / div);
00342 }
00343 
00344 // ######################################################################
00345 inline Rectangle operator+(const Rectangle& r, const Point2D<int>& p)
00346 {
00347   return Rectangle::tlbrO(r.top() + p.j,
00348                           r.left() + p.i,
00349                           r.bottomO() + p.j,
00350                           r.rightO() + p.i);
00351 }
00352 
00353 // ######################################################################
00354 inline Rectangle& operator+=(Rectangle& r, const Point2D<int>& p)
00355 {
00356   return (r = r + p);
00357 }
00358 
00359 // ######################################################################
00360 inline Rectangle operator-(const Rectangle& r, const Point2D<int>& p)
00361 {
00362   return Rectangle::tlbrO(r.top() - p.j,
00363                           r.left() - p.i,
00364                           r.bottomO() - p.j,
00365                           r.rightO() - p.i);
00366 }
00367 
00368 // ######################################################################
00369 inline Rectangle& operator-=(Rectangle& r, const Point2D<int>& p)
00370 {
00371   return (r = r - p);
00372 }
00373 
00374 // ######################################################################
00375 // Rectangle INLINE MEMBER FUNCTIONS:
00376 // ######################################################################
00377 
00378 // ######################################################################
00379 inline Rectangle::Rectangle(int tt, int ll, int bb1, int rr1)
00380 { tlbrInitOuter(tt, ll, bb1, rr1); }
00381 
00382 // ######################################################################
00383 inline Rectangle Rectangle::tlbrI(int tt, int ll, int bb, int rr)
00384 { return Rectangle(tt, ll, bb+1, rr+1); }
00385 
00386 // ######################################################################
00387 inline Rectangle Rectangle::tlbrO(int tt, int ll, int bb, int rr)
00388 { return Rectangle(tt, ll, bb, rr); }
00389 
00390 // ######################################################################
00391 inline Rectangle Rectangle::centerDims(const Point2D<int>& center, const Dims& d)
00392 { return Rectangle(Point2D<int>(center.i - d.w()/2, center.j - d.h()/2), d); }
00393 
00394 // ######################################################################
00395 inline Rectangle::Rectangle(const Point2D<int>& topleft, const Dims& d)
00396   : valid(true),
00397     t(topleft.j), b1(topleft.j+d.h()),
00398     l(topleft.i), r1(topleft.i+d.w())
00399 {}
00400 
00401 // ######################################################################
00402 inline Rectangle::Rectangle(const Rectangle& rect)
00403   : valid(rect.valid), t(rect.t), b1(rect.b1), l(rect.l), r1(rect.r1)
00404 {}
00405 
00406 // ######################################################################
00407 inline Rectangle::Rectangle()
00408   : valid(false), t(-1), b1(-1), l(-1), r1(-1)
00409 {}
00410 
00411 // ######################################################################
00412 inline void Rectangle::tlbrInitOuter(int tt, int ll, int bb1, int rr1)
00413 {
00414   if (bb1 - tt < 0) { t = bb1; b1 = tt; } else { t = tt; b1 = bb1; }
00415   if (rr1 - ll < 0) { l = rr1; r1 = ll; } else { l = ll; r1 = rr1; }
00416   valid = true;
00417 }
00418 
00419 // ######################################################################
00420 inline Rectangle Rectangle::getOverlap(const Rectangle& r2) const
00421 {
00422   if (!this->isValid() || !r2.isValid()) return Rectangle();
00423 
00424   const int le = std::max(l, r2.left());
00425   const int ri = std::min(r1, r2.rightO());
00426   const int to = std::max(t, r2.top());
00427   const int bo = std::min(b1, r2.bottomO());
00428 
00429   if (le >= ri || to >= bo) return Rectangle();
00430   else return Rectangle::tlbrO(to, le, bo, ri);
00431 }
00432 
00433 // ######################################################################
00434 inline double Rectangle::getOverlapRatio(const Rectangle& r2) const
00435 {
00436 
00437   Rectangle ovR = getOverlap(r2);
00438 
00439   double ov = 0;
00440   if (ovR.isValid())
00441   {
00442     //compute overlap as area of intersection / area of union
00443     double ua = (area()+1) + (r2.area()+1) - ovR.area();
00444     ov = (double)ovR.area()/ua;
00445   }
00446  
00447   return ov;
00448 }
00449 
00450 // ######################################################################
00451 inline int Rectangle::area() const
00452 {
00453   return width() * height();
00454 }
00455 
00456 // ######################################################################
00457 inline float Rectangle::aspect() const
00458 {
00459   return (float)width() / (float)height();
00460 }
00461 
00462 // ######################################################################
00463 inline Point2D<int> Rectangle::center() const
00464 {
00465   return Point2D<int>(l+(r1-l)/2, t+(b1-t)/2);
00466   //int t, b1, l, r1;   //!< top, bottom, left, right
00467 }
00468 
00469 // ######################################################################
00470 inline bool Rectangle::contains(const Point2D<int>& p) const
00471 {
00472   return (p.i >= l && p.i < r1 && p.j >= t && p.j < b1);
00473 }
00474 
00475 // ######################################################################
00476 inline bool Rectangle::contains(const Rectangle& r) const
00477 {
00478   return (   r.l >= this->l
00479           && r.t >= this->t
00480           && r.r1 <= this->r1
00481           && r.b1 <= this->b1);
00482 }
00483 
00484 // ######################################################################
00485 inline int Rectangle::top() const
00486 { ASSERT(valid); return t; }
00487 
00488 inline int Rectangle::bottomI() const
00489 { ASSERT(valid); return b1-1; }
00490 
00491 inline int Rectangle::bottomO() const
00492 { ASSERT(valid); return b1; }
00493 
00494 inline int Rectangle::left() const
00495 { ASSERT(valid); return l; }
00496 
00497 inline int Rectangle::rightI() const
00498 { ASSERT(valid); return r1-1; }
00499 
00500 inline int Rectangle::rightO() const
00501 { ASSERT(valid); return r1; }
00502 
00503 inline Point2D<int> Rectangle::topLeft() const
00504 { ASSERT(valid); return Point2D<int>(l, t); }
00505 
00506 inline Point2D<int> Rectangle::topRight() const
00507 { ASSERT(valid); return Point2D<int>(r1, t); }
00508 
00509 inline Point2D<int> Rectangle::bottomLeft() const
00510 { ASSERT(valid); return Point2D<int>(l, b1); }
00511 
00512 inline Point2D<int> Rectangle::bottomRight() const
00513 { ASSERT(valid); return Point2D<int>(r1, b1); }
00514 
00515 inline Dims Rectangle::dims() const
00516 {
00517   ASSERT(valid);
00518   return Dims(r1 - l, b1 - t); // *** CAUTION: BOUNDARIES ARE INCLUDED
00519 }
00520 
00521 inline int Rectangle::width() const
00522 { ASSERT(valid); return r1 - l; } // *** CAUTION: BOUNDARIES ARE INCLUDED
00523 
00524 inline int Rectangle::height() const
00525 { ASSERT(valid); return b1 - t; } // *** CAUTION: BOUNDARIES ARE INCLUDED
00526 
00527 inline bool Rectangle::isValid() const
00528 { return valid; }
00529 
00530 #endif
00531 
00532 // ######################################################################
00533 /* So things look consistent in everyone's emacs... */
00534 /* Local Variables: */
00535 /* indent-tabs-mode: nil */
00536 /* End: */
Generated on Sun May 8 08:40:57 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3