00001 /*!@file Image/Layout.H Tiled layouts of arbitrary numbers of images of different sizes */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the 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: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/Layout.H $ 00035 // $Id: Layout.H 10801 2009-02-09 02:07:52Z itti $ 00036 // 00037 00038 #ifndef IMAGE_LAYOUT_H_DEFINED 00039 #define IMAGE_LAYOUT_H_DEFINED 00040 00041 #include "Image/CutPaste.H" 00042 #include "Image/Image.H" 00043 #include "Image/ImageSet.H" 00044 00045 #include <vector> 00046 00047 /// Represents tiled layouts of arbitrary numbers of images of different sizes 00048 /** Previously, when we wanted to build up a big image of different 00049 individual images (e.g. for display), we had two choices: 00050 00051 - use a series of nested concatX() and concatY() calls, which is 00052 convenient syntactically but is inefficient because each pixel 00053 is copied multiple times, once for each concat call 00054 - make a single output image and use a series of inplacePaste() or 00055 inplaceEmbed() calls to put the various pieces in place; this is 00056 efficient but requires manual tabulation of the various corner 00057 locations of the different tiles 00058 00059 Now, with the Layout class, we get both efficiency and syntactical 00060 convenience. Instead of concatX() and concatY(), we use hcat() and 00061 vcat() which construct Layout objects (with arbitrary nesting); 00062 none of these calls involves any pixel copying. Instead we just 00063 keep track of the tile structure that is desired. Then when the 00064 final Layout has been constructed, it can be rendered into an 00065 Image in a single pass with the render() call. 00066 00067 For example, where previously you would have done 00068 00069 Image<byte> = concatX(e, concatY(concatX(a,b), concatX(c,d))); 00070 00071 now you would do 00072 00073 Image<byte> = hcat(e, vcat(hcat(a,b), hcat(c,d))).render(); 00074 */ 00075 template <class T> 00076 class Layout 00077 { 00078 public: 00079 enum Dir { H, V }; 00080 00081 inline Layout(); 00082 00083 inline Layout(const Image<T>& p); 00084 00085 inline Layout(const Layout<T>& p1, const Layout<T>& p2, Dir d); 00086 00087 inline Layout(const Image<T>* imgs, const size_t nimgs, Dir d); 00088 00089 inline Layout(const ImageSet<T>& imgs, Dir d); 00090 00091 inline Layout(const Layout<T>* imgs, const size_t nimgs, Dir d); 00092 00093 bool initialized() const { return itsDims.isNonEmpty(); } 00094 00095 Dims getDims() const { return itsDims; } 00096 int getWidth() const { return itsDims.w(); } 00097 int getHeight() const { return itsDims.h(); } 00098 00099 Dir getDir() const { return itsDir; } 00100 00101 size_t numParts() const { return itsParts.size(); } 00102 00103 const Layout<T>& part(size_t i) const { return itsParts[i]; } 00104 00105 const Image<T>& leafImage() const { return itsLeafImg; } 00106 00107 inline Image<T> render() const; 00108 inline Image<T> render(const T& bgcol) const; 00109 00110 inline void renderInto(Image<T>& x, const Point2D<int> p) const; 00111 00112 private: 00113 // NOTE: this implementation make sizeof(Layout)==32 on a 32-bit 00114 // machine; if this becomes a problem it may be possible to reduce 00115 // the footprint with some optimization tricks (such as: use a 00116 // custom linked list instead of the std::vector<>; condense 00117 // itsLeafImg and itsRenderCache into a single image; replace itsDir 00118 // with a single-bit bitfield) 00119 00120 std::vector<Layout<T> > itsParts; 00121 Image<T> itsLeafImg; 00122 Dir itsDir; 00123 Dims itsDims; 00124 mutable Image<T> itsRenderCache; 00125 }; 00126 00127 // ###################################################################### 00128 // convenience functions for horizontal Layout concatenation 00129 00130 template <class T> inline 00131 Layout<T> hcat(const Image<T>& p1, const Image<T>& p2) 00132 { return Layout<T>(p1, p2, Layout<T>::H); } 00133 00134 template <class T> inline 00135 Layout<T> hcat(const Image<T>& p1, const Layout<T>& p2) 00136 { return Layout<T>(p1, p2, Layout<T>::H); } 00137 00138 template <class T> inline 00139 Layout<T> hcat(const Layout<T>& p1, const Image<T>& p2) 00140 { return Layout<T>(p1, p2, Layout<T>::H); } 00141 00142 template <class T> inline 00143 Layout<T> hcat(const Layout<T>& p1, const Layout<T>& p2) 00144 { return Layout<T>(p1, p2, Layout<T>::H); } 00145 00146 template <class T> inline 00147 Layout<T> hcat(const Layout<T>& p1, const Layout<T>& p2, const Layout<T>& p3) 00148 { return Layout<T>(p1, p2, p3, Layout<T>::H); } 00149 00150 template <class T> inline 00151 Layout<T> hcat(const Image<T>* imgs, const size_t nimgs) 00152 { return Layout<T>(imgs, nimgs, Layout<T>::H); } 00153 00154 template <class T> inline 00155 Layout<T> hcat(const ImageSet<T>& imgs) 00156 { return Layout<T>(imgs, Layout<T>::H); } 00157 00158 template <class T> inline 00159 Layout<T> hcat(const Layout<T>* imgs, const size_t nimgs) 00160 { return Layout<T>(imgs, nimgs, Layout<T>::H); } 00161 00162 00163 // ###################################################################### 00164 // convenience functions for vertical Layout concatenation 00165 00166 template <class T> inline 00167 Layout<T> vcat(const Image<T>& p1, const Image<T>& p2) 00168 { return Layout<T>(p1, p2, Layout<T>::V); } 00169 00170 template <class T> inline 00171 Layout<T> vcat(const Image<T>& p1, const Layout<T>& p2) 00172 { return Layout<T>(p1, p2, Layout<T>::V); } 00173 00174 template <class T> inline 00175 Layout<T> vcat(const Layout<T>& p1, const Image<T>& p2) 00176 { return Layout<T>(p1, p2, Layout<T>::V); } 00177 00178 template <class T> inline 00179 Layout<T> vcat(const Layout<T>& p1, const Layout<T>& p2) 00180 { return Layout<T>(p1, p2, Layout<T>::V); } 00181 00182 template <class T> inline 00183 Layout<T> vcat(const Layout<T>& p1, const Layout<T>& p2, const Layout<T>& p3) 00184 { return Layout<T>(p1, p2, p3, Layout<T>::V); } 00185 00186 template <class T> inline 00187 Layout<T> vcat(const Image<T>* imgs, const size_t nimgs) 00188 { return Layout<T>(imgs, nimgs, Layout<T>::V); } 00189 00190 template <class T> inline 00191 Layout<T> vcat(const ImageSet<T>& imgs) 00192 { return Layout<T>(imgs, Layout<T>::V); } 00193 00194 template <class T> inline 00195 Layout<T> vcat(const Layout<T>* imgs, const size_t nimgs) 00196 { return Layout<T>(imgs, nimgs, Layout<T>::V); } 00197 00198 00199 00200 // ###################################################################### 00201 // convenience functions for combination h/v array Layout concatenation 00202 00203 template <class T> inline 00204 Layout<T> arrcat(const Image<T>* imgs, const size_t nimgs, const size_t nx) 00205 { 00206 std::vector<Layout<T> > rows; 00207 00208 for (size_t n = 0; n < nimgs; n += nx) 00209 rows.push_back(hcat(imgs + n, std::min(nimgs - n, nx))); 00210 00211 return vcat(&rows[0], rows.size()); 00212 } 00213 00214 template <class T> inline 00215 Layout<T> arrcat(const ImageSet<T>& imgs, const size_t nx) 00216 { 00217 const size_t nimgs = imgs.size(); 00218 std::vector<Layout<T> > rows; 00219 00220 for (size_t n = 0; n < nimgs; n += nx) 00221 rows.push_back(hcat(imgs.subSet(n, n + std::min(nimgs - n, nx)))); 00222 00223 return vcat(&rows[0], rows.size()); 00224 } 00225 00226 // ###################################################################### 00227 // Layout implementation 00228 // ###################################################################### 00229 template <class T> inline 00230 Layout<T>::Layout() : itsLeafImg(), itsDir(H), itsDims() {} 00231 00232 // ###################################################################### 00233 template <class T> inline 00234 Layout<T>::Layout(const Image<T>& p) : itsLeafImg(p), itsDir(H), itsDims(p.getDims()) {} 00235 00236 // ###################################################################### 00237 template <class T> inline 00238 Layout<T>::Layout(const Layout<T>& p1, const Layout<T>& p2, Dir d) 00239 : 00240 itsDir(d), 00241 itsDims(d == H 00242 ? Dims(p1.getDims().w() + p2.getDims().w(), 00243 std::max(p1.getDims().h(), p2.getDims().h())) 00244 : Dims(std::max(p1.getDims().w(), p2.getDims().w()), 00245 p1.getDims().h() + p2.getDims().h())) 00246 { itsParts.push_back(p1); itsParts.push_back(p2); } 00247 00248 // ###################################################################### 00249 template <class T> inline 00250 Layout<T>::Layout(const Image<T>* imgs, const size_t nimgs, Dir d) 00251 : 00252 itsDir(d), 00253 itsDims() 00254 { 00255 int w = 0; int h = 0; 00256 00257 for (size_t i = 0; i < nimgs; ++i) 00258 { 00259 itsParts.push_back(imgs[i]); 00260 if (d == H) 00261 { 00262 w += imgs[i].getWidth(); 00263 h = std::max(h, imgs[i].getHeight()); 00264 } 00265 else 00266 { 00267 w = std::max(w, imgs[i].getWidth()); 00268 h += imgs[i].getHeight(); 00269 } 00270 } 00271 00272 itsDims = Dims(w, h); 00273 } 00274 00275 // ###################################################################### 00276 template <class T> inline 00277 Layout<T>::Layout(const ImageSet<T>& imgs, Dir d) 00278 : 00279 itsDir(d), 00280 itsDims() 00281 { 00282 int w = 0; int h = 0; 00283 const uint nimgs = imgs.size(); 00284 00285 for (size_t i = 0; i < nimgs; ++i) 00286 { 00287 itsParts.push_back(imgs[i]); 00288 if (d == H) 00289 { 00290 w += imgs[i].getWidth(); 00291 h = std::max(h, imgs[i].getHeight()); 00292 } 00293 else 00294 { 00295 w = std::max(w, imgs[i].getWidth()); 00296 h += imgs[i].getHeight(); 00297 } 00298 } 00299 00300 itsDims = Dims(w, h); 00301 } 00302 00303 // ###################################################################### 00304 template <class T> inline 00305 Layout<T>::Layout(const Layout<T>* imgs, const size_t nimgs, Dir d) 00306 : 00307 itsDir(d), 00308 itsDims() 00309 { 00310 int w = 0; int h = 0; 00311 00312 for (size_t i = 0; i < nimgs; ++i) 00313 { 00314 itsParts.push_back(imgs[i]); 00315 if (d == H) 00316 { 00317 w += imgs[i].getDims().w(); 00318 h = std::max(h, imgs[i].getDims().h()); 00319 } 00320 else 00321 { 00322 w = std::max(w, imgs[i].getDims().w()); 00323 h += imgs[i].getDims().h(); 00324 } 00325 } 00326 00327 itsDims = Dims(w, h); 00328 } 00329 00330 // ###################################################################### 00331 template <class T> inline 00332 Image<T> Layout<T>::render() const 00333 { 00334 if (itsParts.size() == 0) return itsLeafImg; 00335 00336 if (!itsRenderCache.initialized()) 00337 { 00338 itsRenderCache = Image<T>(this->getDims(), ZEROS); 00339 00340 this->renderInto(itsRenderCache, Point2D<int>(0,0)); 00341 } 00342 00343 return itsRenderCache; 00344 } 00345 00346 // ###################################################################### 00347 template <class T> inline 00348 Image<T> Layout<T>::render(const T& bgcol) const 00349 { 00350 if (itsParts.size() == 0) return itsLeafImg; 00351 00352 if (!itsRenderCache.initialized()) 00353 { 00354 itsRenderCache = Image<T>(this->getDims(), NO_INIT); 00355 itsRenderCache.clear(bgcol); 00356 00357 this->renderInto(itsRenderCache, Point2D<int>(0,0)); 00358 } 00359 00360 return itsRenderCache; 00361 } 00362 00363 // ###################################################################### 00364 template <class T> inline 00365 void Layout<T>::renderInto(Image<T>& x, const Point2D<int> p) const 00366 { 00367 if (itsParts.size() == 0) 00368 { 00369 if (itsLeafImg.initialized()) 00370 inplacePaste(x, itsLeafImg, p); 00371 } 00372 else if (itsDir == H) 00373 { 00374 Point2D<int> pp = p; 00375 for (size_t i = 0; i < itsParts.size(); ++i) 00376 { 00377 itsParts[i].renderInto(x, pp); 00378 pp.i += itsParts[i].getDims().w(); 00379 } 00380 } 00381 else 00382 { 00383 Point2D<int> pp = p; 00384 for (size_t i = 0; i < itsParts.size(); ++i) 00385 { 00386 itsParts[i].renderInto(x, pp); 00387 pp.j += itsParts[i].getDims().h(); 00388 } 00389 } 00390 } 00391 00392 // ###################################################################### 00393 /* So things look consistent in everyone's emacs... */ 00394 /* Local Variables: */ 00395 /* mode: c++ */ 00396 /* indent-tabs-mode: nil */ 00397 /* End: */ 00398 00399 #endif // IMAGE_LAYOUT_H_DEFINED