about-image.dxy

00001 //      -*- mode: text; fill-column: 70; indent-tabs-mode: nil -*-
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; filed July 23, 2001, following provisional applications     //
00012 // No. 60/274,674 filed March 8, 2001 and 60/288,724 filed May 4, 2001).//
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00033 // $Id: about-image.dxy 6359 2006-03-13 01:47:10Z rjpeters $
00034 //
00035 
00036 // ######################################################################
00037 // ######################################################################
00038 
00039 /*!
00040 
00041 \page about-image About the Image class
00042 
00043 \note Some of this documentation was originally written at the time
00044 that we converted the Image class to have a ref-counted interface and
00045 moved functionality from member functions to free functions; this is
00046 the source of references to "new" and "old" styles.
00047 
00048 <!--############################################################-->
00049 <!--############################################################-->
00050 <!--############################################################-->
00051 
00052 \section refcounting Ref-counting and copy-on-write
00053 
00054 \subsection refcounting-overview How ref-counting works, in four parts:
00055 
00056 - <tt>Dims</tt> represents the width and height dimensions:
00057 \code
00058 struct Dims
00059 {
00060   int const ww; // the width
00061   int const hh; // the height
00062 };
00063 \endcode
00064 
00065 - <tt>ArrayData</tt> encapsulates the management of a 2-D data array
00066 \code
00067 template <class T>
00068 class ArrayData
00069 {
00070   long       itsRefCount; // reference count, is managed by ArrayHandle
00071   Dims const itsDims;     // the width and height, fixed at construction
00072   T*   const itsData;     // the data array, fixed at construction
00073 
00074 public:
00075   // ... constructors/destructor omitted
00076 
00077   const T* data()  const { return itsData; } // const version
00078         T* dataw()       { return itsData; } // non-const version
00079 
00080   ArrayData* clone() const  { return new ArrayData(*this); }
00081 
00082   void incrRefCount() const { ++itsRefCount; }
00083 
00084   long decrRefCount() const { return (--itsRefCount); }
00085 
00086   bool isShared() const     { return (itsRefCount > 1); }
00087 };
00088 \endcode
00089 
00090 - <tt>ArrayHandle</tt> offers ref-counted, copy-on-write access to ArrayData
00091 \code
00092 template <class T>
00093 class ArrayHandle
00094 {
00095   ArrayData<T>* px; // pointer to our data
00096 
00097 public:
00098   // ... constructors/destructor omitted
00099 
00100   // REF-COUNTING:
00101 
00102   ArrayHandle(const ArrayHandle& other) :
00103     px(other.px)
00104   {
00105     px->incrRefCount(); // just share other's data, and bump the ref-count
00106   }
00107 
00108   ~ArrayHandle()
00109   {
00110     if (px->decrRefCount() == 0) // drop the ref-count, and if we were the
00111                                  // last user, then delete the ArrayData
00112       delete px;
00113   }
00114 
00115   // COPY-ON-WRITE:
00116 
00117   const ArrayData<T>& get() const
00118   {
00119     return *px;                  // const version just returns the ArrayData
00120   }
00121 
00122   ArrayData<T>& uniq()
00123   {
00124     if (px->isShared())         // non-const version checks if the ArrayData
00125                                 // is shared, and makes a fresh copy if needed
00126       {
00127         *this = ArrayHandle(px->clone());
00128       }
00129 
00130     return *px;
00131   }
00132 };
00133 \endcode
00134 
00135 - Image wraps an ArrayHandle, and offers an expanded interface:
00136 \code
00137 template <class T>
00138 class Image
00139 {
00140   ArrayHandle<T> itsHdl;
00141 
00142   const ArrayData<T>& impl() const { return itsHdl.get(); }
00143         ArrayData<T>& uniq()       { return itsHdl.uniq(); }
00144 
00145 public:
00146   int getWidth() const { return impl().w(); }
00147   int getHeight() const { return impl().h(); }
00148 
00149   void setVal(int index, const T value)
00150   {
00151     uniq().dataw()[index] = value;
00152   }
00153 };
00154 \endcode
00155 
00156 \subsection refcounting-syntax Ref-counting usage syntax
00157 
00158 - Since copying is cheap, an Image<T> can be the return value of a
00159   function...
00160 \code
00161 template <class T>void coolFilter(const Image<T>& src, Image<T>& result);
00162 
00163 template <class T>
00164 Image<T> hotFilter(const Image<T>& src);
00165 
00166 template <class T>
00167 void foo(const Image<T>& x)
00168 {
00169   Image<T> coolResult;
00170   coolFilter(x, coolResult);
00171 
00172   Image<T> hotResult = hotFilter(x);
00173 }
00174 \endcode
00175 
00176 - ...and chaining operations is easier:
00177 \code
00178 template <class T>
00179 void foo(const Image<T>& x)
00180 {
00181   Image<T> tmpResult, coolResult;
00182   coolFilter1(x, tmpResult);
00183   coolFilter2(tmpResult, coolResult);
00184 
00185   Image<T> hotResult = hotFilter2(hotFilter1(x));
00186 }
00187 
00188 \endcode
00189 
00190 \subsection refcounting-avoid-copies Ref-counting helps avoid copies
00191 - We only have to deep copy the data when absolutely necessary.
00192   For instance, if we are converting an Image<T> of unknown type to Image<byte>:
00193 \code
00194 template <class T>
00195 void process(const Image<T>& x)
00196 {
00197   Image<byte> xbyte = x; // without ref-counting, this always does a deep copy
00198                          // with ref-counting, avoids copying if T is byte
00199 }
00200 \endcode
00201 
00202 \subsection refcounting-reduce-bugs Ref-counting helps reduce bugs
00203 - Since memory management is encapsulated
00204   within ArrayData and ArrayHandle, "ordinary" functions should not have
00205   to call <tt>new[]</tt>/<tt>delete[]</tt> to manage temporary storage
00206 \code
00207 template <class T>
00208 void Image<T>::coolDraw()
00209 {
00210   T* buf = new T[w*h]; // get temporary storage
00211 
00212   // ... fill in buf ...
00213 
00214   T* old = a;          // clean up
00215   a = buf;
00216   delete [] old;
00217 }
00218 
00219 template <class T>
00220 void Image<T>::hotDraw()
00221 {
00222   Image<T> tmp;
00223 
00224   // ... fill in tmp ...
00225 
00226   this->swap(tmp);
00227   // or
00228   *this = tmp;
00229 }
00230 
00231 \endcode
00232 
00233 \subsection refcounting-exception-safety Ref-counting helps with exception safety
00234 - if an exception is thrown while filling in <tt>buf</tt> in
00235   <tt>coolDraw()</tt>, then we leak memory
00236 - but if an exception is thrown while filling in <tt>tmp</tt> in
00237   <tt>hotDraw()</tt>, then <tt>~Image()</tt> will clean up <tt>tmp</tt> for us
00238 
00239 \subsection refcounting-gotchas Ref-counting "gotchas"
00240 - non-const functions must check uniqueness each time they are called
00241 - in particular, it is not especially efficient to call Image::setVal() in
00242   the middle of some inner loop, since
00243   - Image::setVal() must check Image::coordsOk() each time it is called, and
00244   - Image::setVal() must check uniqueness each time it is called
00245 - therefore, in time-critical loops, instead of this:
00246 \code
00247 Image<float> a;
00248 for (int y = 0; y < a.getHeight(); ++y)
00249   for (int x = 0; x < a.getWidth(); ++x)
00250     a.setVal(x,y,42);
00251 \endcode
00252 - try this if you like <tt>while</tt> loops:
00253 \code
00254 Image<float>::iterator itr = a.beginw(), stop = a.endw();
00255 while (itr != stop)
00256   *itr++ = 42;
00257 \endcode
00258 - or this if you like <tt>for</tt> loops:
00259 \code
00260 for(Image<float>::iterator itr = a.beginw(), stop = a.endw();
00261     itr != stop;
00262     ++itr)
00263   {
00264     *itr = 42;
00265   }
00266 \endcode
00267 
00268 
00269 
00270 
00271 <!--############################################################-->
00272 <!--############################################################-->
00273 <!--############################################################-->
00274 
00275 \section iterators Image iterators
00276 
00277 \subsection iterators-review Quick iterator review
00278 
00279 - Iterators act like pointers
00280 - All standard library containers provide iterators
00281 \code
00282 #include <vector>
00283 #include <iostream>
00284 
00285 void foo()
00286 {
00287   std::vector<int> myvec;
00288 
00289   // fill in with some data
00290   for (int i = 0; i < 10; ++i)
00291     myvec.push_back(i);
00292 
00293   // print out the contents using iterators
00294   for (std::vector<int>::const_iterator
00295          itr = myvec.begin(),
00296          stop = myvec.end();
00297        itr != stop;
00298        ++itr)
00299     {
00300       std::cout << *itr << std::endl;
00301     }
00302 }
00303 \endcode
00304 
00305 - Iterators can be used with generic algorithms:
00306 \code
00307 template <class Iterator>
00308 void printContents(Iterator itr, Iterator stop)
00309 {
00310   while (itr != stop)
00311     std::cout << *itr++ << std::endl;
00312 }
00313 
00314 void foo()
00315 {
00316   std::vector<int> myvec;
00317 
00318   // ... fill in with some data ...
00319 
00320   // print the contents
00321   printContents(myvec.begin(), myvec.end());
00322 }
00323 
00324 \endcode
00325 
00326 \subsection image-iterators-version Image iterators: normal and debug versions
00327 
00328 - Normal (non-debug) iterators are just pointers:
00329 \code
00330 template <class T>
00331 class Image
00332 {
00333 public:
00334 #ifndef INVT_MEM_DEBUG
00335 
00336   typedef       T*       iterator;
00337   typedef const T* const_iterator;
00338 
00339   const_iterator begin() const { return impl().data(); }
00340   const_iterator end()   const { return impl().end(); }
00341 
00342         iterator beginw()      { return uniq().dataw(); }
00343         iterator endw()        { return uniq().endw(); }
00344 #endif
00345 };
00346 \endcode
00347 
00348 - Debug iterators are objects that act like pointers, but check that the
00349   pointer is in bounds every time it is dereferenced.
00350 - To use debug iterators, first <tt>make clean</tt>, then re-run
00351   <tt>./configure</tt> with <tt>--enable-mem-debug</tt>, then re-run
00352   <tt>make all</tt>.
00353 
00354 \code
00355 template <class T>
00356 class CheckedIterator                 // a checked iterator class
00357 {
00358   TT* ptr;
00359   TT* start;
00360   TT* stop;
00361 
00362   // ... ++, --, <, >, <=, >=, +=, -=, all those goodies ...
00363 
00364   TT* operator->() const
00365     {
00366       CheckedIteratorAux::ck_range_helper(ptr, start, stop);
00367       return ptr;
00368     }
00369   TT& operator*() const
00370     {
00371       CheckedIteratorAux::ck_range_helper(ptr, start, stop);
00372       return *ptr;
00373     }
00374   TT& operator[](diff_t d) const
00375     {
00376       CheckedIteratorAux::ck_range_helper(ptr+d, start, stop);
00377       return ptr[d];
00378     }
00379 };
00380 
00381 template <class T>
00382 class Image
00383 {
00384 public:
00385 #ifndef INVT_MEM_DEBUG
00386   // ... normal iterators ...
00387 #else
00388 
00389   typedef CheckedIterator<T>             iterator;
00390   typedef CheckedIterator<const T> const_iterator;
00391 
00392   const_iterator begin()  const
00393     { return const_iterator(impl().data(), impl().end()); }
00394 
00395   const_iterator end()    const
00396     { return const_iterator(impl().end(), impl().end()); }
00397 
00398   iterator beginw() { return iterator(uniq().dataw(), uniq().endw()); }
00399   iterator endw()   { return iterator(uniq().endw(), uniq().endw()); }
00400 
00401 #endif
00402 }
00403 \endcode
00404 
00405 - Iterators in use with handmade loops:
00406 \code
00407 template<class T>
00408 void Image<T>::clear(const T& val)
00409 {
00410   for (Image<T>::iterator itr = this->beginw(), stop = this->endw();
00411        itr != stop; ++itr)
00412     {
00413       *itr = val;
00414     }
00415 }
00416 \endcode
00417 
00418 - Iterators in use with STL algorithms:
00419 \code
00420 #include <algorithm> // for std::count(), etc.
00421 #include <numeric> // for std::accumulate(), etc.
00422 
00423 template <class T>
00424 int emptyArea(const Image<T>& img)
00425 {
00426   return std::count(img.begin(), img.end(), T());
00427 }
00428 
00429 template<class T>
00430 double getMean(const Image<T>& img)
00431 {
00432   const double sum = std::accumulate(img.begin(), img.end(), 0.0);
00433 
00434   return sum / double(img.getSize());
00435 }
00436 
00437 \endcode
00438 
00439 
00440 
00441 
00442 <!--############################################################-->
00443 <!--############################################################-->
00444 <!--############################################################-->
00445 
00446 \section free-functions Free functions for image operations
00447 
00448 - Almost all image-related functions are free functions, rather than
00449   member functions, defined in separate <tt>.H</tt> files. Why do
00450   this?
00451 
00452   - The best example is to see the Image class in analogy to the
00453     std::vector class. The std::vector class defines only the complete
00454     but minimal set of operations needed to use std::vector as a
00455     container. Any functions for application-specific <i>uses</i> of
00456     the std::vector class would be written as free functions. Likewise,
00457     the Image class provides the complete but minimal set of
00458     operations needed to use Image as a two-dimensional array of
00459     values; any domain-specific <i>uses</i> of the Image class (such
00460     as filtering, rescaling, concatenating, arithmetic) are written as
00461     free functions.
00462   - Since all operations can be coded in terms of iterators, most Image
00463     algorithms do not need access to the <tt>private</tt> parts of Image.
00464   - In some cases free functions offer a more natural mathematical syntax than
00465     member functions.
00466   - Keeping unrelated functions in separate files improves logical
00467     encapsulation and decreases compile-time dependencies.
00468 
00469 <table>
00470 <tr> <td> <b>File name</b>            <td><b>Contents</b>
00471 <tr> <td> <tt>Image/All.H</tt>        <td> <tt>\#include</tt>s all other Image-related files
00472 <tr> <td> <tt>Image/ColorOps.H</tt>   <td> color operations: get/set components, luminance, RGB-YIQ conversions, etc.
00473 <tr> <td> <tt>Image/FilterOps.H</tt>  <td> <tt>lowPass*(), convolve*(), sepFilter*(),</tt> etc.
00474 <tr> <td> <tt>Image/MathOps.H</tt>    <td> <tt>absDiff(), average(), takeMax(), RMSerr(),</tt> etc.
00475 <tr> <td> <tt>Image/Omni.H</tt>       <td> all omni-directional related operations
00476 <tr> <td> <tt>Image/ShapeOps.H</tt>   <td> <tt>rescale(), downSize(), concat*(), dec*(), int*(), crop()</tt>
00477 <tr> <td> <tt>Image/Transforms.H</tt> <td> <tt>segmentObject(), dct(), infoFFT(),</tt> etc.
00478 </table>
00479 
00480 \subsection free-functions-syntax Free function syntax examples
00481 
00482 \code
00483 void oldFoo(const Image<float>& x)
00484 {
00485   Image<float> filtered = x;
00486   filtered.lowPass3(true, true);
00487 }
00488 
00489 #include "Image/FilterOps.H"
00490 
00491 void newFoo(const Image<float>& x)
00492 {
00493   Image<float> filtered = lowPass3(x, true, true);
00494 }
00495 \endcode
00496 
00497 \code
00498 void oldFoo(const Image<PixRGB<byte> >& x)
00499 {
00500   Image<float> lum;
00501   x.luminance(lum);
00502 }
00503 
00504 #include "Image/ColorOps.H"
00505 
00506 void newFoo(const Image<PixRGB<byte> >& x)
00507 {
00508   Image<float> lum = luminance(x);
00509 }
00510 \endcode
00511 
00512 \code
00513 void oldFoo(const Image<byte>& x)
00514 {
00515   Image<float> smaller = x;
00516   smaller.rescale(x.getWidth()/2, x.getHeight()/2);
00517 }
00518 
00519 #include "Image/ShapeOps.H"
00520 
00521 void newFoo(const Image<byte>& x)
00522 {
00523   Image<float> smaller = rescale(x, x.getWidth()/2, x.getHeight()/2);
00524 }
00525 
00526 \endcode
00527 
00528 
00529 
00530 
00531 <!--############################################################-->
00532 <!--############################################################-->
00533 <!--############################################################-->
00534 
00535 \section numericlimits Use of std::numeric_limits
00536 
00537 - old:
00538 \code
00539 #define BYTEMIN 0
00540 #define BYTEMAX 255
00541 #define INT16MIN (-32768)
00542 #define INT16MAX 32767
00543 #define INT32MIN (-2147483647)
00544 #define INT32MAX 2147483647
00545 #define FLOATMIN -3.40e+38F
00546 #define FLOATMAX 3.40282347e+38F
00547 
00548 void foo(Image<float>& x)
00549 {
00550   x.normalize(BYTEMIN, BYTEMAX);
00551 }
00552 \endcode
00553 
00554 - new:
00555 \code
00556 #include <limits>
00557 
00558 void foo(Image<float>& x)
00559 {
00560   x.normalize(std::numeric_limits<byte>::max(),
00561               std::numeric_limits<byte>::min());
00562 }
00563 \endcode
00564 
00565 - Why? It's standard, it's portable, it offers more
00566   - <i>can be specialized for user-defined types</i>
00567   - get the number of bits used to represent the type
00568   - get the range of the exponent for floating-point types
00569 \code
00570 #include <limits>
00571 
00572 template <class T>
00573 void foo(const Image<T>& x)
00574 {
00575   if (std::numeric_limits<T>::is_signed)
00576     {
00577       // do something for a signed type
00578     }
00579   else
00580     {
00581       // do something for an unsigned type
00582     }
00583 }
00584 
00585 template <class T>
00586 void bar(const Image<T>& x)
00587 {
00588   if (std::numeric_limits<T>::is_integer)
00589     {
00590       // do something for an integral type
00591     }
00592   else
00593     {
00594       // do something for a floating-point type
00595     }
00596 }
00597 \endcode
00598 
00599  */
Generated on Sun May 8 08:40:05 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3