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

complex_image_wst.cc

00001 // Copyright (C) 2008, 2009, 2010 EPITA Research and Development
00002 // Laboratory (LRDE)
00003 //
00004 // This file is part of Olena.
00005 //
00006 // Olena is free software: you can redistribute it and/or modify it under
00007 // the terms of the GNU General Public License as published by the Free
00008 // Software Foundation, version 2 of the License.
00009 //
00010 // Olena is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Olena.  If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software project without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to produce
00022 // an executable, this file does not by itself cause the resulting
00023 // executable to be covered by the GNU General Public License.  This
00024 // exception does not however invalidate any other reasons why the
00025 // executable file might be covered by the GNU General Public License.
00026 
00031 
00032 #include <iostream>
00033 #include <fstream>
00034 #include <sstream>
00035 #include <iomanip>
00036 
00037 #include <mln/value/int_u8.hh>
00038 #include <mln/value/rgb8.hh>
00039 #include <mln/literal/black.hh>
00040 #include <mln/literal/white.hh>
00041 
00042 #include <mln/core/concept/function.hh>
00043 #include <mln/core/alias/point2d.hh>
00044 #include <mln/core/site_set/p_faces.hh>
00045 #include <mln/core/image/complex_image.hh>
00046 // FIXME: Include these elsewhere? (In complex_image.hh?)
00047 #include <mln/core/image/complex_neighborhoods.hh>
00048 #include <mln/core/image/complex_neighborhood_piter.hh>
00049 
00050 #include <mln/data/fill.hh>
00051 
00052 #include <mln/norm/l2.hh>
00053 
00054 #include <mln/morpho/closing/area.hh>
00055 #include <mln/morpho/watershed/flooding.hh>
00056 
00057 #include <mln/convert/to.hh>
00058 
00059 #include <mln/debug/iota.hh>
00060 
00061 // FIXME: To be put elsewhere (from milena/sandbox/geraud/wst_edge.cc).
00062 struct colorize : mln::Function_v2v< colorize >
00063 {
00064   typedef mln::value::rgb8 result;
00065   colorize(unsigned max)
00066     : lut(max + 1)
00067   {
00068     lut[0] = mln::literal::black;
00069     for (unsigned i = 1; i <= max; ++i)
00070       lut[i] = result(100 + std::rand() % 150,
00071                       100 + std::rand() % 150,
00072                       100 + std::rand() % 150);
00073   }
00074   result operator()(unsigned i) const
00075   {
00076     return lut[i];
00077   }
00078   std::vector<result> lut;
00079 };
00080 
00081 
00082 
00083 int main()
00084 {
00085   using namespace mln;
00086   using mln::value::int_u8;
00087 
00088   /*----------------------------------------.
00089   | Complex + complex geometry (location).  |
00090   `----------------------------------------*/
00091 
00092   /* A (simplicial) 1-complex and its adjacency graph.
00093 
00094        c   0     1     2     3
00095      r .------------------------
00096        |        v0      e3     v3
00097      0 |         o-----------o                v0----e3----v3
00098        |        / \         /                / \         /
00099        |       /   \       /                /   \       /
00100      1 |   e0 /     e1    / e4             e0    e1    e4
00101        |     /       \   /                /       \   /
00102        |    /         \ /                /         \ /
00103      2 |   o-----------o                v1----e2----v2
00104        | v1     e2      v2
00105 
00106        v = vertex
00107        e = edge
00108   */
00109 
00110 
00111   const unsigned D = 1;
00112 
00113   topo::complex<D> c;
00114 
00115   typedef point2d P;
00116   typedef geom::complex_geometry<D, P> G;
00117   G geom;
00118 
00119   // Convenience typedefs.
00120   typedef topo::n_face<0, D> vertex;
00121   typedef topo::n_face<1, D> edge;
00122 
00123   // 0-faces (vertices).
00124   vertex v0 = c.add_face();  geom.add_location(point2d(0,1));
00125   vertex v1 = c.add_face();  geom.add_location(point2d(2,0));
00126   vertex v2 = c.add_face();  geom.add_location(point2d(2,2));
00127   vertex v3 = c.add_face();  geom.add_location(point2d(0,3));
00128 
00129   // 1-faces (edges).
00130   edge e0 = c.add_face(-v1 + v0);
00131   edge e1 = c.add_face(-v2 + v0);
00132   edge e2 = c.add_face(-v2 + v1);
00133   edge e3 = c.add_face(-v0 + v3);
00134   edge e4 = c.add_face(-v3 + v2);
00135 
00136   /*---------------------.
00137   | Complex-based pset.  |
00138   `---------------------*/
00139 
00140   p_complex<D, G> pc(c, geom);
00141 
00142   /*----------------------.
00143   | Complex-based image.  |
00144   `----------------------*/
00145 
00146   // An image type built on a 1-complex with unsigned values on each
00147   // face (both vertices and edges).
00148   typedef complex_image<D, G, unsigned> dist_ima_t;
00149 
00150   // Create and initialize an image based on PC.
00151   dist_ima_t dist_ima(pc);
00152   data::fill(dist_ima, 0u);
00153 
00154   /*--------------------------------.
00155   | Complex-based image iterators.  |
00156   `--------------------------------*/
00157 
00158   // For each edge (1-face), compute the distance between the two
00159   // adjacent vertices (0-faces).
00160   p_n_faces_fwd_piter<D, G> e(dist_ima.domain(), 1);
00161   typedef complex_lower_neighborhood<D, G> v_nbh_t;
00162   v_nbh_t v_nbh;
00163   mln_niter_(v_nbh_t) v(v_nbh, e);
00164   for_all(e)
00165   {
00166     v.start();
00167     point2d p1 = v.to_site().front();
00168     v.next();
00169     point2d p2 = v.to_site().front();
00170     v.next();
00171     mln_invariant(!v.is_valid());
00172 
00173     dist_ima(e) = convert::to<unsigned>(10 * norm::l2_distance(p1.to_vec(), p2.to_vec()));
00174   }
00175   // Initialize 0-faces to a dummy value, to prevent the watershed from
00176   // finding minima on 0-faces.
00177   p_n_faces_fwd_piter<D, G> v_(dist_ima.domain(), 0);
00178   for_all(v_)
00179     dist_ima(v_) = mln_max(mln_value_(dist_ima_t));
00180 
00181   // For all edges, iterate on adjacent edges (i.e., on edges sharing
00182   // an adjacent vertex).
00183   typedef complex_lower_dim_connected_n_face_neighborhood<D, G> nbh_t;
00184   nbh_t nbh;
00185   // Neighbor edge.
00186   mln_niter_(nbh_t) ne(nbh, e);
00187   for_all(e)
00188   {
00189     std::cout << "dist_ima(" << e << ") = " << dist_ima(e)
00190               << " -- adjacent edges :" << std::endl;
00191     for_all(ne)
00192       std::cout << "           " << ne << std::endl;
00193   }
00194 
00195   /*-----------------.
00196   | Simplification.  |
00197   `-----------------*/
00198 
00199   // Currently, does nothing (lambda = 1).
00200   dist_ima_t closed_dist_ima = morpho::closing::area(dist_ima, nbh, 1);
00201 
00202   /*------.
00203   | WST.  |
00204   `------*/
00205 
00206   // Perform a Watershed Transform.
00207   typedef unsigned wst_val_t;
00208   wst_val_t nbasins;
00209   typedef complex_image<D, G, wst_val_t> wst_ima_t;
00210   wst_ima_t wshed = morpho::watershed::flooding(closed_dist_ima, nbh, nbasins);
00211   /* Note that since the image is based not only on the 1-faces but
00212      also on the 0-faces of the complex, and given the above
00213      neighborhood, the domain seen by the WST is not connected!  It is
00214      actually composed of five components :
00215 
00216      - a component containing all the 1-faces (egdes) which are all
00217        connected through
00218        mln::complex_lower_dim_connected_n_face_neighborhood;
00219 
00220      - four (singleton) components corresponding to the 0-faces
00221        (vertices), connected to no other part of the complex according to
00222        mln::complex_lower_dim_connected_n_face_neighborhood.
00223 
00224      Since the component made of the edges contains two local minima,
00225      the number of basins is equal to 6:
00226 
00227            2 minima for the edges' component
00228      + 4 * 1 minima for the vertices's components
00229      --------------------------------------------
00230            6 basins.
00231 
00232      Hence the result.
00233 
00234 
00235      We definitely need a complex_image that can accept a subset of a
00236      complex as domain (or at least a p_face<N, D, P>.  */
00237   wst_val_t actual_nbasins = nbasins - c.nfaces_of_static_dim<0>();
00238   std::cout << "nbasins = " << actual_nbasins << std::endl;
00239 
00240 
00241   colorize color(nbasins);
00242 
00243   std::ofstream g("complex_image_wst-wst.neato");
00244   g << "graph wst"  << std::endl
00245     << "{" << std::endl
00246     << "  graph [bgcolor = \"#000000\"]" << std::endl
00247     << "  edge [color = \"#FFFFFF\"]" << std::endl
00248     << "  node [color = \"#FFFFFF\", fontcolor = \"#FFFFFF\" ]" << std::endl;
00249 
00250   // Vertices.
00251   typedef complex_higher_neighborhood<D, G> e_nbh_t;
00252   e_nbh_t e_nbh;
00253   mln_niter_(e_nbh_t) v_e(e_nbh, v_);   
00254   for_all(v_)
00255   {
00256     // Find the adjacent basin (color).
00257     value::rgb8 basin_color = literal::white;
00258     for_all(v_e)
00259       if (wshed(v_e) != 0)
00260         {
00261           basin_color = color(wshed(v_e));
00262           break;
00263         }
00264     std::ostringstream basin_color_str;
00265     basin_color_str << '#'
00266                     << std::hex
00267                     << std::setfill('0')
00268                     << std::setw(2) << basin_color.red()
00269                     << std::setw(2) << basin_color.green()
00270                     << std::setw(2) << basin_color.blue()
00271                     << std::dec;
00272 
00273     g << "  v" << v_.unproxy_().face_id()
00274       << " [pos = \""
00275       << std::fixed << std::setprecision(1)
00276       << (float)v_.to_site().front()[1] << ", "
00277       << -(float)v_.to_site().front()[0]
00278       << "\", color = \"" << basin_color_str.str()
00279       << "\", fillcolor = \"" << basin_color_str.str()
00280       << "\", pin = \"true\", style=\"filled,setlinewidth(3)\"];"
00281       << std::endl;
00282   }
00283 
00284   for_all(e)
00285   {
00286     value::rgb8 basin_color = color(wshed(e));
00287     std::ostringstream basin_color_str;
00288     basin_color_str << '#'
00289               << std::hex
00290               << std::setfill('0')
00291               << std::setw(2) << basin_color.red()
00292               << std::setw(2) << basin_color.green()
00293               << std::setw(2) << basin_color.blue()
00294               << std::dec;
00295 
00296     // Adjacent vertices.
00297     v.start();
00298     topo::face<1> v1 = v.unproxy_().face();
00299     point2d p1 = v.to_site().front();
00300     v.next();
00301     topo::face<1> v2 = v.unproxy_().face();
00302     point2d p2 = v.to_site().front();
00303     v.next();
00304     mln_invariant(!v.is_valid());
00305 
00306     // Edges.
00307     g << "  v" << v1.face_id() << " -- v" << v2.face_id() << " ";
00308     if (wshed(e) == 0)
00309       g << "[color = \"#FFFFFF\"];" << std::endl;
00310     else
00311       g << "[color = \"" << basin_color_str.str()
00312         << "\", style=\"setlinewidth(3)\"];" << std::endl;
00313   }
00314 
00315   g << "}" << std::endl;
00316   g.close();
00317 }

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