Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
test_khalimksy/lap.cc
1 
2 #include <mln/core/image/image2d.hh>
3 #include <mln/value/int_u8.hh>
4 
5 #include <mln/io/pgm/load.hh>
6 #include <mln/io/pbm/save.hh>
7 #include <mln/io/pgm/save.hh>
8 #include <mln/io/ppm/save.hh>
9 
10 #include <mln/literal/colors.hh>
11 #include <mln/literal/white.hh>
12 
13 #include <mln/core/routine/duplicate.hh>
14 #include <mln/data/fill.hh>
15 
16 #include <mln/accu/stat/max.hh>
17 #include <mln/pw/all.hh>
18 #include <mln/core/image/dmorph/image_if.hh>
19 
20 #include <mln/debug/filename.hh>
21 #include <mln/morpho/laplacian.hh>
22 #include <mln/win/rectangle2d.hh>
23 #include <mln/estim/min_max.hh>
24 
25 #include <mln/labeling/background.hh>
26 #include <mln/labeling/compute.hh>
27 #include <mln/labeling/colorize.hh>
28 #include <mln/fun/vvvv2v/mean.hh>
29 #include <mln/fun/vv2v/mean.hh>
30 #include <mln/fun/v2v/abs.hh>
31 #include <mln/math/mean.hh>
32 
33 #include <mln/world/k1/immerse.hh>
34 #include <mln/world/k1/un_immerse.hh>
35 #include <mln/world/k1/neighb2d.hh>
36 #include <mln/world/k2/immerse.hh>
37 #include <mln/world/k2/is_primary_2_face.hh>
38 #include <mln/world/k2/fill_non_primary_from_primary_2_faces.hh>
39 #include <mln/world/kn/is_2_face.hh>
40 #include <mln/world/kn/fill_1_from_aux_2_faces.hh>
41 #include <mln/world/kn/fill_1_from_2_faces.hh>
42 #include <mln/world/kn/fill_2_from_1_faces.hh>
43 #include <mln/world/kn/dilate_0_from_1_faces.hh>
44 #include <mln/world/kn/is_0_or_1_face.hh>
45 #include <mln/world/kn/display_enlarged.hh>
46 
47 #include <mln/debug/println.hh>
48 #include <mln/debug/println_with_border.hh>
49 
50 
51 namespace mln
52 {
53 
54 
55 
56  struct f_zero_t : Function_vv2v< f_zero_t >
57  {
58  typedef bool result;
59  bool operator()(int v1, int v2) const
60  {
61  return v1 * v2 <= 0;
62  }
63  } f_zero;
64 
65  typedef mln::fun::vv2v::mean<unsigned> f_mean;
66 
67 
68  template <typename V>
69  struct lap_fill2_k2_t : Function_vv2v< lap_fill2_k2_t<V> >
70  {
71  typedef mln_equiv(V) result;
72  typedef mln_equiv(V) argument;
73 
74  mln_equiv(V) operator()(const mln_equiv(V)& v1, const mln_equiv(V)& v2) const
75  {
76  if (v1 * v2 <= 0)
77  return 0;
78  else
79  return (v1 + v2) / 2;//math::mean(v1, v2);
80  }
81  };
82 
83 
84  template <typename V>
85  struct lap_fill4_k2_t : Function_vvvv2v< lap_fill4_k2_t<V> >
86  {
87  typedef mln_equiv(V) result;
88  typedef mln_equiv(V) argument;
89 
90  mln_equiv(V) operator()(const mln_equiv(V)& v1, const mln_equiv(V)& v2,
91  const mln_equiv(V)& v3, const mln_equiv(V)& v4) const
92  {
93  if (v1 * v2 * v3 * v4 <= 0)
94  return 0;
95  else
96  return (v1 + v2 + v3 + v4) / 4;//math::mean(v1, v2, v3, v4);
97  }
98  };
99 
100  void
101  doit_k1(const image2d<value::int_u8>& in, unsigned size)
102  {
103  using namespace world;
104 
105  box2d b = in.domain();
106 
107  win::rectangle2d rect(size, size);
108  image2d<value::int_u8>
109  dil = morpho::dilation(in, rect),
110  ero = morpho::erosion(in, rect),
111  grad(b);
112  data::fill(grad, pw::value(dil) - pw::value(ero));
113 
114  image2d<int> lap = duplicate((pw::value(dil) + pw::value(ero) - pw::cst(2) * pw::value(in)) | b);
115 
116  int lap_min, lap_max;
117  estim::min_max(lap, lap_min, lap_max);
118 
119  std::cout << lap_min << ' ' << lap_max << std::endl;
120 
121 
122  image2d<int> lap_k1 = world::k1::immerse(lap);
123  box2d B = lap_k1.domain();
124  data::fill((lap_k1 | world::kn::is_0_or_1_face).rw(), 0);
125 
126 
127  image2d<bool> lap_zero_k1(B);
128 
129  // 1-faces = 0-crossing
130  world::kn::fill_1_from_aux_2_faces(lap_zero_k1, lap_k1, f_zero);
131 
132  // 2-faces = lap is 0
133  data::fill((lap_zero_k1 |world::kn::is_2_face).rw(), pw::value(lap_k1) == pw::cst(0));
134 
135  // 0-faces = max 2-faces neighbors
136  world::kn::dilate_0_from_1_faces(lap_zero_k1);
137 
138 
139  image2d<bool>
140  lap_zero_k1_enlarged = world::kn::display_enlarged(lap_zero_k1, 5);
141  io::pbm::save(lap_zero_k1_enlarged,
142  debug::filename("lap_zero_k1.pbm"));
143 
144 
145  image2d<value::int_u8> grad_on_01f(B);
146  data::fill(grad_on_01f, 0u);
147 
148  world::kn::fill_1_from_aux_2_faces(grad_on_01f,
149  world::k1::immerse(grad), f_mean()); // Use f_max ?
150  kn::fill_0_from_1_faces(grad_on_01f, accu::stat::max<value::int_u8>());
151 
152  // Gradient enlarged
153 
154  image2d<value::int_u8>
155  grad_on_01f_enlarged = world::kn::display_enlarged(grad_on_01f, 5);
156  io::pgm::save(grad_on_01f_enlarged, debug::filename("grad_k1.pgm"));
157 
158 
159  // Gradient on Laplacian edges.
160 
161  world::kn::fill_2_from_1_faces((grad_on_01f | pw::value(lap_zero_k1)).rw(), fun::vvvv2v::mean<int>());
162  data::fill((grad_on_01f | (pw::value(lap_zero_k1) == pw::cst(false))).rw(), 0u);
163  grad_on_01f_enlarged = world::kn::display_enlarged(grad_on_01f, 5);
164  io::pgm::save(grad_on_01f_enlarged, debug::filename("grad_on_lap0_k1.pgm"));
165 
166 
167  unsigned nlabels;
168  image2d<unsigned> lap_lbl_k1 = labeling::background(lap_zero_k1, c4(), nlabels);
169  io::ppm::save(labeling::colorize(value::rgb8(), lap_lbl_k1, nlabels), debug::filename("lap_lbl_k1.ppm"));
170  image2d<unsigned> lap_lbl = k1::un_immerse(lap_lbl_k1);
171 
172  util::array<float> mean_val = labeling::compute(accu::stat::mean<value::int_u8>(), in, lap_lbl, nlabels);
173  util::array<value::int_u8> mean_val_u8;
174  convert::from_to(mean_val, mean_val_u8);
175  io::pgm::save(data::transform(lap_lbl, mean_val_u8), debug::filename("lap_lbl_mean_input_val.pgm"));
176  image2d<value::int_u8> lap_abs = data::transform(lap, fun::v2v::abs<int,value::int_u8>());
177 
178  // Compute max for connected components.
179  {
180  util::array<value::int_u8> max = labeling::compute(accu::stat::max<value::int_u8>(), lap_abs, lap_lbl, nlabels);
181  max[0] = 0;
182  image2d<value::int_u8> lap_max_abs = data::transform(lap_lbl, max);
183 
184  io::pgm::save(lap_max_abs, debug::filename("lap_max_abs.pgm"));
185  }
186 
187  {
188  // Compute mean of gradient on contours.
189  util::array<float> mean_grad = labeling::compute(accu::stat::mean<value::int_u8>(), grad, lap_lbl, nlabels);
190  image2d<value::int_u8> grad_mean_on_contours(lap_lbl_k1.domain());
191  data::fill(grad_mean_on_contours, 0);
192  mln_piter_(image2d<value::int_u8>) p(lap_lbl_k1.domain());
193  for_all(p)
194  if (kn::is_1_face_vertical(p)
195  && lap_lbl_k1(p + left) != lap_lbl_k1(p + right))
196  {
197  grad_mean_on_contours(p) = math::mean(mean_grad[lap_lbl_k1(p + left)],
198  mean_grad[lap_lbl_k1(p + right)]);
199  }
200  else if (kn::is_1_face_horizontal(p)
201  && lap_lbl_k1(p + up) != lap_lbl_k1(p + down))
202  {
203  grad_mean_on_contours(p) = math::mean(mean_grad[lap_lbl_k1(p + up)],
204  mean_grad[lap_lbl_k1(p + down)]);
205  }
206  kn::fill_0_from_1_faces(grad_mean_on_contours, accu::stat::max<value::int_u8>());
207 
208  io::pgm::save(grad_mean_on_contours, debug::filename("grad_mean_on_contours_k1.pgm"));
209  }
210 
211  // Display Laplacian regions in colors.
212 
213  // float hue;
214  // image2d<value::rgb8> out(lap.domain());
215  // mln_piter_(box2d) p(lap.domain());
216  // for_all(p)
217  // {
218  // if (lap(p) == 0)
219  // {
220  // convert::from_to(in(p), out(p));
221  // continue;
222  // }
223 
224  // if (lap(p) < 0)
225  // hue = 10;
226  // else
227  // hue = 110;
228 
229  // value::hsl_<float,float,float> hsl__(
230  // hue,
231  // 1,
232  // unsigned(in(p)) * .002745f); // = 1 / 255 * 0.7);
233  // convert::from_to(hsl__, out(p));
234  // }
235  }
236 
237 
238  void
239  doit_k2(const image2d<value::int_u8>& in, unsigned size)
240  {
241  using namespace world;
242 
243  box2d b = in.domain();
244 
245  win::rectangle2d rect(size, size);
246  image2d<value::int_u8>
247  dil = morpho::dilation(in, rect),
248  ero = morpho::erosion(in, rect),
249  grad(b);
250  data::fill(grad, pw::value(dil) - pw::value(ero));
251 
252  image2d<int> lap = duplicate((pw::value(dil) + pw::value(ero) - pw::cst(2) * pw::value(in)) | b);
253 
254 
255  typedef value::intsub<2> T;
256  typedef value::interval<value::intsub<2> > V;
257  image2d<V> lap_k2 = k2::immerse(lap, V());
258 
259  debug::println(lap_k2 | k2::is_primary_2_face);
260 
261  k2::fill_non_primary_from_primary_2_faces(lap_k2, lap_fill2_k2_t<V>(), lap_fill4_k2_t<V>());
262 
263  debug::println(lap_k2 | kn::is_2_face);
264  debug::println(lap_k2);
265  }
266 
267 } // mln
268 
269 
270 
271 void
272 usage(char* argv[])
273 {
274  std::cerr << "usage: " << argv[0] << " input.pgm size outprefix" << std::endl;
275  std::cerr << " sample use: " << argv[0] << " lena.pgm 5 out_lena" << std::endl;
276  std::abort();
277 }
278 
279 
280 
281 int main(int argc, char* argv[])
282 {
283  using namespace mln;
284  using value::int_u8;
285 
286  if (argc != 4)
287  usage(argv);
288 
289  int size = std::atoi(argv[2]);
290  if (size <= 0)
291  usage(argv);
292 
293  image2d<int_u8> in;
294  io::pgm::load(in, argv[1]);
295 
296  debug::internal::filename_prefix = argv[3];
297 
298  //doit_k1(in, size);
299 
300  doit_k2(in, size);
301 }