
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 10908 2009-02-22 16:16:28Z 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 a top-left corner and some dims 00160 inline Rectangle(const Point2D<int>& topleft, const Dims& dims); 00161 00162 //! Copy constructor 00163 inline Rectangle(const Rectangle& rect); 00164 00165 //! Uninitialized constructor (useful for arrays). 00166 inline Rectangle(); 00167 00168 // Default assignment operator ok 00169 00170 // ############################################################ 00171 // ##### Access functions: 00172 // ############################################################ 00173 00174 //! get overlap between this rectangle and passed in rectangle 00175 inline Rectangle getOverlap(const Rectangle& r2) const; 00176 00177 //! check if point p is within rectangle 00178 /*! CAUTION: boundaries are included. */ 00179 inline bool contains(const Point2D<int>& p) const; 00180 00181 //! check if this rect contains another 00182 /*! The boundaries are allowed to coincide, such that by this 00183 definition a rectangle "contains" itself. */ 00184 inline bool contains(const Rectangle& r) const; 00185 00186 inline int top() const; //!< get (inner) top coordinate 00187 inline int bottomI() const; //!< get inner bottom coordinate (=top+height-1) 00188 inline int bottomO() const; //!< get outer bottom coordinate (=top+height) 00189 inline int left() const; //!< get (inner) left coordinate 00190 inline int rightI() const; //!< get inner right coordinate (=left+width-1) 00191 inline int rightO() const; //!< get outer right coordinate (=left+width) 00192 00193 inline Point2D<int> topLeft() const; //!< Get (outer) top left corner point 00194 inline Point2D<int> topRight() const; //!< Get (outer) top right corner point 00195 inline Point2D<int> bottomLeft() const; //!< Get (outer) bottom left corner point 00196 inline Point2D<int> bottomRight() const; //!< Get (outer) bottom right corner point 00197 00198 //! Get the rectangle's width, height 00199 inline Dims dims() const; 00200 00201 //! Access some metric info 00202 inline int width() const; 00203 //! Access some metric info 00204 inline int height() const; 00205 //! Access some metric info 00206 inline int area() const; 00207 //! Access some metric info 00208 inline float aspect() const; 00209 00210 //!The center of the rectangle 00211 inline Point2D<int> center() const; 00212 00213 //! whether the rectangle is valid 00214 inline bool isValid() const; 00215 00216 private: 00217 inline void tlbrInitOuter(int tt, int ll, int bb1, int rr1); 00218 00219 bool valid; //!< True if Rectangle contains something coherent 00220 int t, b1, l, r1; //!< top, bottom, left, right 00221 }; 00222 00223 00224 // ###################################################################### 00225 // Rectangle FREE FUNCTIONS: 00226 // ###################################################################### 00227 00228 // ###################################################################### 00229 //! Rectangle overload: format is "<int>,<int>,<int>,<int>" 00230 /*! Format corresponds to "xtopleft,ytopleft,xbottomright,ybottomright" */ 00231 std::string convertToString(const Rectangle& val); 00232 00233 // ###################################################################### 00234 //! Rectangle overload: format is "<int>,<int>,<int>,<int>" 00235 void convertFromString(const std::string& str, Rectangle& val); 00236 00237 00238 // ###################################################################### 00239 //! Return a new rectangle that is a constrained version of the input. 00240 /*! @param in The original rectangle on which to base the constrained 00241 output. 00242 00243 @param bounds The output rectangle will be constrained to be 00244 contained within these bounds. 00245 00246 @param minw The minimum width for the output rectangle. Caller 00247 must ensure minw>=0. If the output rectangle would naturally be 00248 narrower than this width, then it will be widened to the smaller 00249 of minw and bounds.width(). 00250 00251 @param maxw The maximum width for the output rectangle. Caller 00252 must ensure maxw>=minw. If the output rectangle would naturally be 00253 wider than this width, then it will be narrowed to the smaller of 00254 maxw and bounds.width(). 00255 00256 @param minh The minimum height for the output rectangle. Caller 00257 must ensure minh>=0. If the output rectangle would naturally be 00258 shorter than this height, then it will be lengthened to the 00259 smaller of minh and bounds.height(). 00260 00261 @param maxh The maximum height for the output rectangle. Caller 00262 must ensure maxh>=minh. If the output rectangle would naturally be 00263 taller than this height, then it will be shortened to the smaller 00264 of maxh and bounds.height(). 00265 00266 @return The result is guaranteed to be such that the following 00267 conditions are all true: 00268 \code 00269 bounds.contains(result); 00270 result.width() >= std::min(minw, bounds.width()); 00271 result.width() <= std::min(maxw, bounds.width()); 00272 result.height() >= std::min(minh, bounds.height()); 00273 result.height() <= std::min(maxh, bounds.height()); 00274 \endcode 00275 */ 00276 Rectangle constrainRect(const Rectangle& in, 00277 const Rectangle& bounds, 00278 int minw, int maxw, 00279 int minh, int maxh); 00280 00281 00282 // ###################################################################### 00283 //! Like the main constrainRect(), but use the same limits for width as for height 00284 inline Rectangle constrainRect(const Rectangle& in, 00285 const Rectangle& bounds, 00286 int minsz, int maxsz) 00287 { 00288 return constrainRect(in, bounds, minsz, maxsz, minsz, maxsz); 00289 } 00290 00291 // ###################################################################### 00292 inline bool operator==(const Rectangle& r1, const Rectangle& r2) 00293 { 00294 if (!r1.isValid() || !r2.isValid()) return r1.isValid() == r2.isValid(); 00295 00296 return (r1.top() == r2.top() && 00297 r1.bottomO() == r2.bottomO() && 00298 r1.left() == r2.left() && 00299 r1.rightO() == r2.rightO()); 00300 } 00301 00302 // ###################################################################### 00303 inline Rectangle operator*(const Rectangle& r, const double s) 00304 { 00305 if (!r.isValid()) 00306 return Rectangle(); 00307 else 00308 return Rectangle::tlbrO(int(r.top() * s), 00309 int(r.left() * s), 00310 int(r.bottomO() * s), 00311 int(r.rightO() * s)); 00312 } 00313 00314 // ###################################################################### 00315 inline Rectangle operator*(const Rectangle& r, const int s) 00316 { 00317 if (!r.isValid()) 00318 return Rectangle(); 00319 else 00320 return Rectangle::tlbrO(r.top() * s, 00321 r.left() * s, 00322 r.bottomO() * s, 00323 r.rightO() * s); 00324 } 00325 00326 // ###################################################################### 00327 inline Rectangle operator/(const Rectangle& r, const int div) 00328 { 00329 if (!r.isValid() || div == 0) 00330 return Rectangle(); 00331 else 00332 return Rectangle::tlbrO(r.top() / div, 00333 r.left() / div, 00334 r.bottomO() / div, 00335 r.rightO() / div); 00336 } 00337 00338 // ###################################################################### 00339 inline Rectangle operator+(const Rectangle& r, const Point2D<int>& p) 00340 { 00341 return Rectangle::tlbrO(r.top() + p.j, 00342 r.left() + p.i, 00343 r.bottomO() + p.j, 00344 r.rightO() + p.i); 00345 } 00346 00347 // ###################################################################### 00348 inline Rectangle& operator+=(Rectangle& r, const Point2D<int>& p) 00349 { 00350 return (r = r + p); 00351 } 00352 00353 // ###################################################################### 00354 inline Rectangle operator-(const Rectangle& r, const Point2D<int>& p) 00355 { 00356 return Rectangle::tlbrO(r.top() - p.j, 00357 r.left() - p.i, 00358 r.bottomO() - p.j, 00359 r.rightO() - p.i); 00360 } 00361 00362 // ###################################################################### 00363 inline Rectangle& operator-=(Rectangle& r, const Point2D<int>& p) 00364 { 00365 return (r = r - p); 00366 } 00367 00368 // ###################################################################### 00369 // Rectangle INLINE MEMBER FUNCTIONS: 00370 // ###################################################################### 00371 00372 // ###################################################################### 00373 inline Rectangle::Rectangle(int tt, int ll, int bb1, int rr1) 00374 { tlbrInitOuter(tt, ll, bb1, rr1); } 00375 00376 // ###################################################################### 00377 inline Rectangle Rectangle::tlbrI(int tt, int ll, int bb, int rr) 00378 { return Rectangle(tt, ll, bb+1, rr+1); } 00379 00380 // ###################################################################### 00381 inline Rectangle Rectangle::tlbrO(int tt, int ll, int bb, int rr) 00382 { return Rectangle(tt, ll, bb, rr); } 00383 00384 // ###################################################################### 00385 inline Rectangle::Rectangle(const Point2D<int>& topleft, const Dims& d) 00386 : valid(true), 00387 t(topleft.j), b1(topleft.j+d.h()), 00388 l(topleft.i), r1(topleft.i+d.w()) 00389 {} 00390 00391 // ###################################################################### 00392 inline Rectangle::Rectangle(const Rectangle& rect) 00393 : valid(rect.valid), t(rect.t), b1(rect.b1), l(rect.l), r1(rect.r1) 00394 {} 00395 00396 // ###################################################################### 00397 inline Rectangle::Rectangle() 00398 : valid(false), t(-1), b1(-1), l(-1), r1(-1) 00399 {} 00400 00401 // ###################################################################### 00402 inline void Rectangle::tlbrInitOuter(int tt, int ll, int bb1, int rr1) 00403 { 00404 if (bb1 - tt < 0) { t = bb1; b1 = tt; } else { t = tt; b1 = bb1; } 00405 if (rr1 - ll < 0) { l = rr1; r1 = ll; } else { l = ll; r1 = rr1; } 00406 valid = true; 00407 } 00408 00409 // ###################################################################### 00410 inline Rectangle Rectangle::getOverlap(const Rectangle& r2) const 00411 { 00412 if (!this->isValid() || !r2.isValid()) return Rectangle(); 00413 00414 const int le = std::max(l, r2.left()); 00415 const int ri = std::min(r1, r2.rightO()); 00416 const int to = std::max(t, r2.top()); 00417 const int bo = std::min(b1, r2.bottomO()); 00418 00419 if (le >= ri || to >= bo) return Rectangle(); 00420 else return Rectangle::tlbrO(to, le, bo, ri); 00421 } 00422 00423 // ###################################################################### 00424 inline int Rectangle::area() const 00425 { 00426 return width() * height(); 00427 } 00428 00429 // ###################################################################### 00430 inline float Rectangle::aspect() const 00431 { 00432 return (float)width() / (float)height(); 00433 } 00434 00435 // ###################################################################### 00436 inline Point2D<int> Rectangle::center() const 00437 { 00438 return Point2D<int>(l+(r1-l)/2, t+(b1-t)/2); 00439 //int t, b1, l, r1; //!< top, bottom, left, right 00440 } 00441 00442 // ###################################################################### 00443 inline bool Rectangle::contains(const Point2D<int>& p) const 00444 { 00445 return (p.i >= l && p.i < r1 && p.j >= t && p.j < b1); 00446 } 00447 00448 // ###################################################################### 00449 inline bool Rectangle::contains(const Rectangle& r) const 00450 { 00451 return ( r.l >= this->l 00452 && r.t >= this->t 00453 && r.r1 <= this->r1 00454 && r.b1 <= this->b1); 00455 } 00456 00457 // ###################################################################### 00458 inline int Rectangle::top() const 00459 { ASSERT(valid); return t; } 00460 00461 inline int Rectangle::bottomI() const 00462 { ASSERT(valid); return b1-1; } 00463 00464 inline int Rectangle::bottomO() const 00465 { ASSERT(valid); return b1; } 00466 00467 inline int Rectangle::left() const 00468 { ASSERT(valid); return l; } 00469 00470 inline int Rectangle::rightI() const 00471 { ASSERT(valid); return r1-1; } 00472 00473 inline int Rectangle::rightO() const 00474 { ASSERT(valid); return r1; } 00475 00476 inline Point2D<int> Rectangle::topLeft() const 00477 { ASSERT(valid); return Point2D<int>(l, t); } 00478 00479 inline Point2D<int> Rectangle::topRight() const 00480 { ASSERT(valid); return Point2D<int>(r1, t); } 00481 00482 inline Point2D<int> Rectangle::bottomLeft() const 00483 { ASSERT(valid); return Point2D<int>(l, b1); } 00484 00485 inline Point2D<int> Rectangle::bottomRight() const 00486 { ASSERT(valid); return Point2D<int>(r1, b1); } 00487 00488 inline Dims Rectangle::dims() const 00489 { 00490 ASSERT(valid); 00491 return Dims(r1 - l, b1 - t); // *** CAUTION: BOUNDARIES ARE INCLUDED 00492 } 00493 00494 inline int Rectangle::width() const 00495 { ASSERT(valid); return r1 - l; } // *** CAUTION: BOUNDARIES ARE INCLUDED 00496 00497 inline int Rectangle::height() const 00498 { ASSERT(valid); return b1 - t; } // *** CAUTION: BOUNDARIES ARE INCLUDED 00499 00500 inline bool Rectangle::isValid() const 00501 { return valid; } 00502 00503 #endif 00504 00505 // ###################################################################### 00506 /* So things look consistent in everyone's emacs... */ 00507 /* Local Variables: */ 00508 /* indent-tabs-mode: nil */ 00509 /* End: */
1.4.4