• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

2008__tour2.cc

00001 // Copyright (C) 2001, 2007 EPITA Research and Development Laboratory
00002 //
00003 // This file is part of Olena.
00004 //
00005 // Olena is free software: you can redistribute it and/or modify it under
00006 // the terms of the GNU General Public License as published by the Free
00007 // Software Foundation, version 2 of the License.
00008 //
00009 // Olena is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Olena.  If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 // As a special exception, you may use this file as part of a free
00018 // software project without restriction.  Specifically, if other files
00019 // instantiate templates or use macros or inline functions from this
00020 // file, or you compile this file and link it with other files to produce
00021 // an executable, this file does not by itself cause the resulting
00022 // executable to be covered by the GNU General Public License.  This
00023 // exception does not however invalidate any other reasons why the
00024 // executable file might be covered by the GNU General Public License.
00025 
00026 // File: tour2.cc.
00027 
00028 #include <oln/core/2d/image2d.hh>
00029 #include <oln/core/2d/window2d.hh>
00030 #include <oln/debug/println.hh>
00031 
00032 
00033 
00034 // Note to the reader: If you do not have read the tour1.cc file, you
00035 // should have a quick look at it before proceeding with this present
00036 // file.  Some important features and practices are described in the
00037 // former tour step that are here assumed to be known.
00038 
00039 
00040 
00041 int main()
00042 {
00043   using namespace oln;
00044 
00045   // As shown before, image data read access and pixel value
00046   // assignments can be performed using:
00047   // - either the parenthesis operator with takes a point as its
00048   //   argument,
00049   // - or the ".at" method which requires the coordinates of the point
00050   //   you want to access to.
00051 
00052   //   ex: ima(p), with p a 1D point, or ima.at(i), ima being a 1D
00053   //   image and i an index---single coordinate.
00054 
00055 
00056   // Objects from image2d and image3d types can be build and access to
00057   // in a similar way than image1d, except you have to account for
00058   // respectively one and two extra coordinates.  Let us take an
00059   // example.
00060 
00061   image2d<bool> img(4, 5);  // A 4x5 2D binary image.
00062 
00063   for (unsigned row = 0; row < img.nrows(); ++row)
00064     for (unsigned col = 0; col < img.ncols(); ++col)
00065       img.at(row, col) =
00066         (row > 0 and row < 3) and (col > 0 and col < 4);
00067 
00068   debug::println(img); // Gives:
00069   // - - - - - 
00070   // - | | | - 
00071   // - | | | - 
00072   // - - - - - 
00073 
00074   // When debug::print'ing binary images, the 'true' (object) and
00075   // 'false' (background) values are respectively depicted by the '|'
00076   // and '-' symbols.
00077 
00078 
00079 
00080 
00081   // As said before, a point is a position in an image.  Because
00082   // Olena supports different dimensions, it supports different
00083   // point types: point1d, point2d, and point3d.
00084 
00085   // We build a point by passing it as much coordinates as
00086   // needed:
00087   point2d p(2, 0); // a 2D point so a couple of coordinates.
00088 
00089   // Each point coordinate can be accessed separately...
00090   std::cout << "row = " << p.row() << std::endl
00091             << "col = " << p.col() << std::endl;
00092 
00093   // ...and modified:
00094   p.col() = 1;
00095   std::cout << "col = " << p.col() << " (new value!)" << std::endl;
00096 
00097   // So we have a way to access image data:
00098   img(p) = false;
00099   // which is shorter than the equivalent writing:
00100   // ima2a.at(2, 1) = false;
00101 
00102   debug::println(img);
00103   // Gives (with hand-written coordinates):
00104   //  col 0 1 2 3 4
00105   // row    v
00106   //  0   - - - - -
00107   //  1   - | | | -
00108   //  2 > - - | | -
00109   //  3   - - - - -
00110 
00111   // Points in Olena are not really like mathematical vectors.  The
00112   // reason is twofold.  Some operations over vectors are meaningless
00113   // with points; for instance adding points together makes no sense.
00114   // Furthermore we want C++ expressions with points to be more
00115   // strongly typed so that errors from the user can be more easily
00116   // pointed out.
00117 
00118   // To record a displacement from one point to another one, Olena
00119   // introduces the notion of "delta-points".  The types for
00120   // delta-points are dpoint1d, dpoint2d, and dpoint3d.  We have:
00121 
00122   dpoint2d dp(-1, +2);  // -1 applies to row, +2 applies to column.
00123   img(p + dp) = false;
00124   debug::println(img);
00125   // Gives:
00126   //  col 0 1 2 3 4
00127   // row    . . v
00128   //  0   - - - - -
00129   //  1 > - | | - -
00130   //  2 . - - | | -
00131   //  3   - - - - -
00132 
00133   // Let us verify:
00134   point2d p2 = p + dp;
00135   std::cout << "p2 " << p2
00136             << " = p " << p
00137             << " + dp " << dp << std::endl;
00138   assert(p2 == point2d(1, 3)); // Right: p2 is (1, 3).
00139 
00140   // Taking the difference between a couple of points gives a
00141   // delta-point.
00142   dpoint2d dp2 = p2 - p;  // That should be equal to 'dp'.
00143   assert(dp2 == dp);      // Indeed.
00144 
00145   // Delta-points (amongst them) feature the classical arithmetical
00146   // operators:
00147   dpoint2d dp3 = dp + dp2;
00148   dp3 -= dp2;
00149   assert(dp3 == dp);
00150 
00151 
00152   // The notion of delta-point is at the base of the definitions of
00153   // classical window and neighborhood.
00154 
00155 
00156   // A window, or "sliding window", is a region defined around a
00157   // point.  In its most usual forms offered by Olena, for instance
00158   // window2d for the 2D case, windows are internally defined by a set
00159   // of delta-points.
00160 
00161   window2d win; // Empty window.
00162   win
00163     .take(dpoint2d(-1, -1)) // Add a delta-point.
00164     .take(dpoint2d( 0, 0))
00165     .take(dpoint2d( 1, 1))
00166     .take(dpoint2d( 1, 2));
00167   std::cout << "win = " << win << std::endl;
00168   // win = [ (-1, -1), (0, 0), (1, 1), (1, 2) ]
00169 
00170   // A window is commonly used to iterate around a fixed point.
00171   std::cout << "around " << p
00172             << " window points are ";
00173   for (unsigned i = 0; i < win.size(); ++i)
00174     std::cout << (p + win[i])  // win[i] gives the ith element of the
00175               << ' ';          // window, i.e., a delta-point.
00176   std::cout << std::endl;
00177   // The code above outputs:
00178   // around (2, 1) window points are (1, 0) (2, 1) (3, 2) (3, 3)
00179 
00180 
00181   // If we try to generalize this kind of display to all image points,
00182   // one straightforward code is the following:
00183 
00184   {
00185     // First version.
00186 
00187     std::cout << std::endl
00188               << "First version:" << std::endl
00189               << std::endl;
00190 
00191     for (unsigned row = 0; row < img.nrows(); ++row)
00192       for (unsigned col = 0; col < img.ncols(); ++col)
00193         {
00194           point2d p(row, col);
00195           std::cout << p << ": ";
00196           for (unsigned i = 0; i < win.size(); ++i)
00197             {
00198               point2d q = p + win[i];  // q is a point around p;
00199                                        // precisely, the ith point of
00200                                        // the window win centered at
00201                                        // point p
00202               if (img.has(q)) // we only print q if it actually lies
00203                               // within the image
00204                 std::cout << q << ' ';
00205             }
00206           std::cout << std::endl;
00207         }
00208 
00209   } // End of 1st version.
00210 
00211   // We obtain:
00212   // (0, 0): (0, 0) (1, 1) (1, 2) 
00213   // (0, 1): (0, 1) (1, 2) (1, 3) 
00214   // (0, 2): (0, 2) (1, 3) (1, 4) 
00215   // (0, 3): (0, 3) (1, 4) 
00216   // (0, 4): (0, 4) 
00217   // (1, 0): (1, 0) (2, 1) (2, 2) 
00218   // (1, 1): (0, 0) (1, 1) (2, 2) (2, 3) 
00219   // (1, 2): (0, 1) (1, 2) (2, 3) (2, 4) 
00220   // (1, 3): (0, 2) (1, 3) (2, 4) 
00221   // (1, 4): (0, 3) (1, 4) 
00222   // (2, 0): (2, 0) (3, 1) (3, 2) 
00223   // (2, 1): (1, 0) (2, 1) (3, 2) (3, 3) 
00224   // (2, 2): (1, 1) (2, 2) (3, 3) (3, 4) 
00225   // (2, 3): (1, 2) (2, 3) (3, 4) 
00226   // (2, 4): (1, 3) (2, 4) 
00227   // (3, 0): (3, 0) 
00228   // (3, 1): (2, 0) (3, 1) 
00229   // (3, 2): (2, 1) (3, 2) 
00230   // (3, 3): (2, 2) (3, 3) 
00231   // (3, 4): (2, 3) (3, 4) 
00232 
00233 
00234   // An equivalent code, given here just for you to realize that you
00235   // may continue to handle images and points with Olena just the way
00236   // you are used to it:
00237 
00238   /*
00239 
00240   { // A variation.
00241 
00242     int nrows = img.nrows(), ncols = img.ncols();
00243     unsigned n = win.size();
00244     for (int row = 0; row < nrows; ++row)
00245       for (int col = 0; col < ncols; ++col)
00246         {
00247           std::cout << "(" << row << ", " << col << "): "; // print p
00248           for (unsigned i = 0; i < n; ++i)
00249             {
00250               int // define q coordinates:
00251                 r = row + win[i].row(),
00252                 c = col + win[i].col();
00253               if (r >= 0 and r < nrows and c >= 0 and c < ncols) // q is in img 
00254                 std::cout << "(" << r << ", " << c << ") "; // print q
00255             }
00256           std::cout << std::endl;
00257         }
00258 
00259   } // End of a variation.
00260 
00261   */
00262 
00263 
00264   // Such samples of "classical" image processing code have 3 (three!)
00265   // main drawbacks:
00266 
00267   // - it is error-prone; note that there is rather a lot of code for
00268   //   a so simple algorithm;
00269 
00270   // - the algorithm, that is, the most important part of this code, is
00271   //   totally drowned in the middle of implementation details;
00272 
00273   // - this kind of writing only applies to a very special type of
00274   //   images (2D ones, rectangular, and starting at (0,0)) so it is
00275   //   not reusable.
00276 
00277 
00278   // If we express the algorithm into natural language, we can say:
00279   //
00280   //   p, a point of img
00281   //   q, a point of win centered at p
00282   //
00283   //   for all p
00284   //     print p
00285   //     for all q
00286   //       if q is in img 
00287   //         print q
00288   //       print end of line
00289   //     end for
00290   //   end for
00291 
00292 
00293   // The Olena library has been designed so that you can easily
00294   // translate your algorithms into code.  With the running example we
00295   // can write:
00296 
00297   { // Second version.
00298 
00299     std::cout << std::endl
00300               << "Second version (same result):" << std::endl
00301               << std::endl;
00302 
00303     box2d::piter    p (img.points());
00304     window2d::qiter q (win, p);
00305 
00306     for_all(p)
00307       {
00308         std::cout << p << ": ";
00309         for_all(q)
00310           if (img.has(q))
00311             std::cout << q << ' ';
00312         std::cout << std::endl;
00313       }
00314 
00315   } // End of 2nd version.
00316 
00317   std::cout << std::endl;
00318 
00319 
00320   // Above, p and q behave just like points; for instance, the
00321   // following expressions are valid:
00322 
00323   //    int r = p.row();
00324   //    to get the current row value,
00325 
00326   //    bool b = img(p);
00327   //    to get the pixel value at the current point,
00328 
00329   // or point2d pp = p + dp;
00330   //    where dp is a delta-point to get a point nearby p.
00331 
00332   // Yet, p and q are "more than points" since they allow to
00333   // browse/iterate over a set of points, respectivelly, the domain of
00334   // 'img' and the window centered at p.
00335 
00336 
00337   // The domain of 'img' is obtained with "img.points()" and is
00338   // provided to the 'p' object so that it knows how to iterate.
00339 
00340   // For a "basic" image, its set of points is an n-dimensional box.
00341   // In the 2D space, the box type is called 'box2d'.  We also have
00342   // 'box1d' and 'box3d' for other dimensions.
00343 
00344   box2d pts = img.points();
00345   std::cout << "img points are " << pts << std::endl;
00346   // Prints:
00347   // img points are { (0, 0) .. (3, 4) }
00348 
00349   // The type of iterators over a point set is obtained with the
00350   // expression: "name_of_the_point_set_type::piter", where 'piter'
00351   // means "point iterator" for short.
00352 
00353   // The same construction is available for iterators on window
00354   // points, whose types are obtained in a similar way with
00355   // "name_of_the_window_type::qiter".  Here the 'q' in 'qiter'
00356   // emphases the fact that a window is not really a set of points but
00357   // "a set of dpoints and a center point".
00358 
00359 
00360 
00361   // The second version of our example contrasts with the more
00362   // "classical" ones; it is:
00363 
00364   // - shorter,
00365   //   so it is less error-prone for the developer;
00366 
00367   // - easy to read,
00368   //   so the algorithm appears clearly from the code;
00369 
00370   // - (almost) "generic",
00371   //   for instance, no details within the loops indicate that we are
00372   //   processing a 2D image, that this image is rectangular, etc.
00373 
00374 
00375   //  +-----------------------------------------------------------+
00376   //  |                                                           |
00377   //  |  A major feature of Olena is to offer to its users a way  |
00378   //  |  to write GENERIC algorithms, that is, algorithms that    |
00379   //  |  accept different image types as input.                   |
00380   //  |                                                           |
00381   //  +-----------------------------------------------------------+
00382 
00383 
00384   // The next files of the tour give many details about what you can
00385   // expect from the notion of "genericity" applied to image
00386   // processing.
00387 
00388   // Now you can jump to tour3.cc
00389 
00390 
00391 }

Generated on Tue Oct 4 2011 15:23:23 for Milena (Olena) by  doxygen 1.7.1