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