Layout.H

Go to the documentation of this file.
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
Generated on Sun May 8 08:40:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3