Milena (Olena)
User documentation 2.0a Id
|
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 00027 /* FIXME: We should factor as much things as possible between 00028 tests/morpho/lena_line_graph_image_wst1.cc, 00029 tests/morpho/lena_line_graph_image_wst2.cc and this file, starting 00030 with conversion routines. */ 00031 00049 #include <mln/core/image/image2d.hh> 00050 #include <mln/core/alias/point2d.hh> 00051 #include <mln/core/alias/window2d.hh> 00052 #include <mln/core/alias/neighb2d.hh> 00053 00055 #include <mln/core/image/edge_image.hh> 00056 #include <mln/pw/all.hh> 00057 #include <mln/fun/i2v/array.hh> 00058 #include <mln/util/graph.hh> 00059 00060 #include <mln/morpho/line_gradient.hh> 00061 #include <mln/morpho/closing/area_on_vertices.hh> 00062 #include <mln/morpho/meyer_wst.hh> 00063 #include <mln/data/stretch.hh> 00064 00065 #include <mln/value/int_u8.hh> 00066 #include <mln/value/int_u16.hh> 00067 #include <mln/value/rgb8.hh> 00068 #include <mln/literal/black.hh> 00069 #include <mln/literal/colors.hh> 00070 00071 #include <mln/io/pgm/load.hh> 00072 #include <mln/io/pgm/save.hh> 00073 #include <mln/io/ppm/save.hh> 00074 00075 #include <mln/math/max.hh> 00076 #include <mln/math/abs.hh> 00077 00078 #include <mln/opt/at.hh> 00079 00080 #include "tests/data.hh" 00081 00082 00083 00084 int main() 00085 { 00086 using namespace mln; 00087 using value::int_u8; 00088 using value::int_u16; 00089 using value::rgb8; 00090 00091 /*--------. 00092 | Input. | 00093 `--------*/ 00094 00095 // Dimensions. 00096 const unsigned nrows = 100; 00097 const unsigned ncols = 100; 00098 const unsigned square_length = 3; 00099 typedef int_u8 input_val_t; 00100 // Create a checkboard image. 00101 image2d<input_val_t> input (nrows, ncols); 00102 for (unsigned r = 0; r < nrows; ++r) 00103 for (unsigned c = 0; c < ncols; ++c) 00104 opt::at(input, r,c) = 00105 ((r / square_length) % 2 == (c / square_length) % 2) 00106 ? mln_min(input_val_t) 00107 : mln_max(input_val_t); 00108 mln_assertion((nrows * ncols) == 10000); 00109 mln_assertion((2 * nrows * ncols - (nrows + ncols)) == 19800); 00110 00111 /*----------------. 00112 | Line gradient. | 00113 `----------------*/ 00114 00115 // Line graph image. 00116 typedef edge_image<util::site_pair<point2d>, input_val_t, util::graph> lg_ima_t; 00117 lg_ima_t lg_ima = morpho::line_gradient(input); 00118 00119 /*------. 00120 | WST. | 00121 `------*/ 00122 00123 typedef lg_ima_t::nbh_t nbh_t; 00124 nbh_t nbh; 00125 00126 // Perform a Watershed Transform. 00127 typedef edge_image<util::site_pair<point2d>, unsigned, util::graph> wshed_t; 00128 unsigned nbasins; 00129 wshed_t wshed = morpho::meyer_wst(lg_ima, nbh, nbasins); 00130 mln_assertion(nbasins == 1155); 00131 00132 /*---------. 00133 | Output. | 00134 `---------*/ 00135 00136 // FIXME: Inlined conversion, to be reifed into a routine. 00137 00138 // Save the result in gray levels (data) + color (wshed). 00139 00140 // Data. 00141 typedef rgb8 output_val_t; 00142 typedef image2d<output_val_t> output_t; 00143 point2d output_pmin = input.domain().pmin(); 00144 point2d output_pmax(input.domain().pmax()[0] * 2, 00145 input.domain().pmax()[1] * 2); 00146 output_t output(box2d(output_pmin, output_pmax)); 00147 data::fill(output, literal::black); 00148 mln_fwd_piter_(image2d<input_val_t>) p(input.domain()); 00149 for_all(p) 00150 { 00151 // Equivalent of P in OUTPUT. 00152 point2d q(p[0] * 2, p[1] * 2); 00153 input_val_t v = input(p); 00154 /* FIXME: Use a conversion function from input_val_t to 00155 output_val_t instead of an explicit construction. */ 00156 output(q) = output_val_t(v, v, v); 00157 } 00158 // Interpolate missing points in OUTPUT. 00159 mln_piter_(output_t) p_out(output.domain()); 00160 for_all(p_out) 00161 { 00162 // Process points on even rows and odd columns 00163 if (p_out[0] % 2 == 0 && p_out[1] % 2 == 1) 00164 output(p_out) = (output(p_out + left) + output(p_out + right)) / 2; 00165 // Process points on odd rows and even columns 00166 if (p_out[0] % 2 == 1 && p_out[1] % 2 == 0) 00167 output(p_out) = (output(p_out + up) + output(p_out + down)) / 2; 00168 // Process points on odd rows and odd columns 00169 if (p_out[0] % 2 == 1 && p_out[1] % 2 == 1) 00170 output(p_out) = 00171 (output(p_out + dpoint2d(-1, -1)) + 00172 output(p_out + dpoint2d(-1, +1)) + 00173 output(p_out + dpoint2d(+1, -1)) + 00174 output(p_out + dpoint2d(+1, +1))) / 4; 00175 } 00176 // Draw the watershed. 00177 /* FIXME: We should draw the watershed on another image and 00178 superimpose it on OUTPUT instead of drawing it directly into 00179 OUTPUT. */ 00180 mln_piter_(wshed_t) pw(wshed.domain()); 00181 for_all(pw) 00182 { 00183 if (wshed(pw) == 0) 00184 { 00185 mln_psite_(lg_ima_t) pp(pw); 00186 // Equivalent of the line (edge) PP in OUTPUT. 00187 int row1 = pp.first()[0] * 2; 00188 int col1 = pp.first()[1] * 2; 00189 int row2 = pp.second()[0] * 2; 00190 int col2 = pp.second()[1] * 2; 00191 point2d q((row1 + row2) / 2, (col1 + col2) / 2); 00192 // Print the watershed in red. 00193 output(q) = literal::red; 00194 } 00195 } 00196 // Fill the holes, so that the watershed looks connected. 00197 /* FIXME: This approach is bad: it creates thick lines of watershed. 00198 We should probably solve this when we ``paint'' the watershed 00199 over the ``doubled'' image. 00200 00201 A better approach is probably to iterate over the set of vertices, 00202 and ``connect'' edges according to patterns (vertically or 00203 horizontally connected egdes member of the watershed, etc.). */ 00204 // Reuse the piter on OUTPUT. 00205 for_all (p_out) 00206 // Only handle points on odd rows and columns. 00207 if (p_out[0] % 2 == 1 && p_out[1] % 2 == 1) 00208 { 00209 // Count the number of adjacent watershed points. If there are 00210 // two or more, consider, create a watershed point. 00211 /* FIXME: Iterating over a c4 window would be more elegant, of 00212 course. */ 00213 unsigned nwsheds = 00214 (output.has(p_out + up ) && output(p_out + up ) == literal::red) + 00215 (output.has(p_out + down ) && output(p_out + down ) == literal::red) + 00216 (output.has(p_out + left ) && output(p_out + right) == literal::red) + 00217 (output.has(p_out + right) && output(p_out + left ) == literal::red); 00218 if (nwsheds >= 2) 00219 output(p_out) = literal::red; 00220 } 00221 io::ppm::save(output, "artificial_line_graph_image_wst-out.ppm"); 00222 }