histo3d_rgb.hh 9.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
// (LRDE)
//
// This file is part of Olena.
//
// Olena is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, version 2 of the License.
//
// Olena is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Olena.  If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, you may use this file as part of a free
// software project without restriction.  Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to produce
// an executable, this file does not by itself cause the resulting
// executable to be covered by the GNU General Public License.  This
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.

#ifndef MLN_ACCU_STAT_HISTO3D_RGB_HH
# define MLN_ACCU_STAT_HISTO3D_RGB_HH

/// \file
///
/// \brief Define a histogram as accumulator which returns an image3d.
///
/// This source implements the discrete histogram version. It was
/// created for images which the values are derived from integer
/// type. The number of bins is directly infered from the cardinality
/// of the image value. It works for RGB space. See histo1d.hh for limitations
/// of such implementation. 8 bits quantification is very
/// expensive, it produces image3d with [0..255,0..255,0..255] as domain.
///
/// The following sample is a typical use of the histogram.
///
/// #include <mln/accu/stat/histo3d_rgb.hh>
/// #include <mln/core/image/image2d.hh>
/// #include <mln/core/image/image3d.hh>
/// #include <mln/data/compute.hh>
/// #include <mln/data/transform.hh>
/// #include <mln/fun/v2v/rgb8_to_rgbn.hh>
/// #include <mln/img_path.hh>
/// #include <mln/io/ppm/load.hh>
/// #include <mln/value/rgb.hh>
/// #include <mln/value/rgb8.hh>
///
/// int main()
/// {
///   typedef mln::value::rgb8   t_rgb8;
///   typedef mln::value::rgb<7> t_rgb7;
///   mln::image2d<t_rgb8>       img_rgb8;
///   mln::image2d<t_rgb7>       img_rgb7;
///   mln::image3d<unsigned>     histo;
///
///   mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/lena.ppm");
///   img_rgb7 =mln::data::transform(img_rgb8,mln::fun::v2v::rgb8_to_rgbn<7>());
///   histo = mln::data::compute(mln::accu::meta::stat::histo3d_rgb(),img_rgb7);
///
///   return 0;
/// }


# include <iostream>

# include <mln/accu/internal/base.hh>

# include <mln/arith/plus.hh>

# include <mln/core/macros.hh>
# include <mln/core/image/image3d.hh>
# include <mln/core/alias/point3d.hh>
# include <mln/core/alias/box3d.hh>

# include <mln/literal/zero.hh>

# include <mln/trace/entering.hh>
# include <mln/trace/exiting.hh>

# include <mln/trait/value/comp.hh>

# include <mln/value/ops.hh>

namespace mln
{

  namespace accu
  {

    namespace stat
    {

      // Forward declaration
      template <typename V>
      struct histo3d_rgb;

    } // end of namespace mln::accu::stat

    namespace meta
    {

      namespace stat
      {

	struct histo3d_rgb : public Meta_Accumulator<histo3d_rgb>
	{
	  template <typename V>
	  struct with
	  {
	    typedef accu::stat::histo3d_rgb<V> ret;
	  };
	};

      } // end of namespace mln::accu::meta::stat

    } // end of namespace mln::accu::meta

  } // end of namespace mln::accu


  namespace trait
  {

    template <typename V>
    struct accumulator_< mln::accu::stat::histo3d_rgb<V> >
    {
      typedef accumulator::has_untake::no    has_untake;
      typedef accumulator::has_set_value::no has_set_value;
      typedef accumulator::has_stop::no      has_stop;
      typedef accumulator::when_pix::use_v   when_pix;
    };

    template <typename V>
    struct set_precise_binary_<op::eq,
			       accu::stat::histo3d_rgb<V>,
			       accu::stat::histo3d_rgb<V> >
    {
      typedef bool ret;
    };

  } // end of namespace mln::trait

  namespace accu
  {

    namespace stat
    {

      /// \brief Define a histogram as accumulator which returns an image3d.
      ///
      /// Param V defines the type of the input image value. It is in
      /// this space that we count the values. For instance, this
      /// histogram works well for image2d< rgb<2> > or with image2d<
      /// rgb<7> >. The number of bins depends directly the values V.
      /// For 8 bits there is 256x3 bins. Note that less
      /// quantification works too.
      ///
      /// \ingroup modaccuvalues

      template <typename V>
      struct histo3d_rgb :
	public mln::accu::internal::base<image3d<unsigned>, histo3d_rgb<V> >
      {
	typedef V                 argument;
	typedef image3d<unsigned> result;
	typedef result            q_result;

	/// Constructors.
	/// \{
	/// \brief Infer the size of the resulting image3d domain.
	///
	/// By evaluating the minimum and the maximum of V, we define the domain
	/// of the resulting image3d.
	histo3d_rgb();
	/// \}


	/// Manipulators.
	/// \{
	/// \brief Initialize the histogram with zero value.
	///
	/// This method must be called just before starting the use of the
	/// histogram. If it's not, resulting values won't converge to the
	/// density.
	void init();


	/// \brief Update the histogram with the RGB pixel t.
	/// \param[in] t a graylevel pixel of type V.
	///
	/// The end user shouldn't call this method. In place of it, he can
	/// go through the data compute interface.
	void take(const argument& t);


	/// \brief Update the histogram with an other histogram.
	/// \param[in] other the other histogram.
	///
	/// The end user shouldn't call this method. This is part of
	/// data compute interface mechanism.
	void take(const histo3d_rgb<V>& other);
	/// \}

	/// Accessors.
	/// \{
	/// \brief Return the histogram as an RGB image3d.
	///
	/// This is the machinery to communicate with data compute interface.
	/// The end user should'nt use it.
	result to_result() const;
	operator result () const;
	/// \}

	/// \brief Check whethever this accumulator is able to return a result.
	///
	/// Depends if the resulting image1d is valid. We can assume it is quite
	/// always the case.
	bool is_valid() const;

      protected:
	result  count_;
      };

      /// \brief Check wethever an histogram is equal to an other one.
      /// \param[in] histo1 the first histogram to compare with.
      /// \param[in] histo2 the second histogram.
      ///
      /// The operator compares all the bins from the two histograms.
      /// Nobody uses this method unless unitary tests.
      template <typename V>
      bool operator==(const histo3d_rgb<V>& histo1,
		      const histo3d_rgb<V>& histo2);

# ifndef MLN_INCLUDE_ONLY

      template <typename V>
      inline
      histo3d_rgb<V>::histo3d_rgb()
      {
	trace::entering("mln::accu::stat::histo3d_rgb::cstor");

	typedef mln_trait_value_comp(V,0) comp0;
	typedef mln_trait_value_comp(V,1) comp1;
	typedef mln_trait_value_comp(V,2) comp2;

	// comp keep a trace of the dimension of the theorical image.
	// mln_min(comp) --> 0
	// mln_max(comp) --> 2^(n-1) [127 for n=7][255 for n=8] ...

	count_.init_(box3d(point3d(mln_min(comp0),
				   mln_min(comp1),
				   mln_min(comp2)),
			   point3d(mln_max(comp0),
				   mln_max(comp1),
				   mln_max(comp2))));

	trace::exiting("mln::accu::stat::histo3d_rgb::cstor");
      }

      template <typename V>
      inline
      void histo3d_rgb<V>::init()
      {
	data::fill(count_, literal::zero);
      }

      template <typename V>
      inline
      void histo3d_rgb<V>::take(const argument& t)
      {
	// Just convert a greyscale value (int_u8 like) to a position for an
	// iterator on the resulting image.
	// Take care to the constructor : Point(slice, row, column)
	++count_(point3d(t.blue(), t.red(), t.green()));
      }


      template <typename V>
      inline
      void histo3d_rgb<V>::take(const histo3d_rgb<V>& other)
      {
	count_ += other.count_;
      }

      template <typename V>
      inline
      typename histo3d_rgb<V>::result histo3d_rgb<V>::to_result() const
      {
	return count_;
      }

      template <typename V>
      inline
      histo3d_rgb<V>::operator result() const
      {
	return count_;
      }

      template <typename V>
      inline
      bool histo3d_rgb<V>::is_valid() const
      {
	bool result = count_.is_valid();

	return result;
      }

      template <typename V>
      bool operator==(const histo3d_rgb<V>& histo1,
		      const histo3d_rgb<V>& histo2)
      {
	trace::entering("mln::accu::stat::histo3d_rgb::operator==");

	bool  result                  = true;
	const image3d<unsigned>& res1 = histo1.to_result();
	const image3d<unsigned>& res2 = histo2.to_result();

	mln_precondition(res1.is_valid());
	mln_precondition(res2.is_valid());

	mln_piter(image3d<unsigned>)      p1(res1.domain());
	mln_piter(image3d<unsigned>)      p2(res2.domain());

	for_all_2(p1, p2)
	  result &= (res1(p1) == res2(p2));

	trace::exiting("mln::accu::stat::histo3d_rgb::operator==");
	return result;
      }

# endif // ! MLN_INCLUDE_ONLY


    } // end of namespace mln::accu::stat

  } // end of namespace mln::accu

} // end of namespace mln

#endif // ! MLN_ACCU_STAT_HISTO3D_RGB_HH