
Index: olena/ChangeLog from Simon Odou <simon@lrde.epita.fr> * oln/basics.hh: Add behavior.hh. * oln/core/behavior.hh: Add an empty constructor for any_with_diamond. * oln/makefile.src: Add border morpher file. * oln/convol/fast_convolution.hh: Use border morpher, fix the size problem. * tests/convol/tests/fast_convol: Improve test comparing with slow version. * oln/morpher/border_morpher.hh: Border morpher. * tests/morpher/tests/border: Test border morpher. Index: olena/oln/basics.hh --- olena/oln/basics.hh Thu, 07 Aug 2003 02:37:23 +0200 burrus_n (oln/d/42_basics.hh 1.13 600) +++ olena/oln/basics.hh Tue, 15 Jun 2004 13:07:11 +0200 odou_s (oln/d/42_basics.hh 1.13 600) @@ -1,4 +1,4 @@ -// Copyright (C) 2001, 2002, 2003 EPITA Research and Development Laboratory +// Copyright (C) 2001, 2002, 2003, 2004 EPITA Research and Development Laboratory // // This file is part of the Olena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -54,5 +54,6 @@ # include <oln/core/traverse.hh> # include <oln/core/compose.hh> # include <oln/core/generate.hh> +# include <oln/core/behavior.hh> #endif // ! OLENA_BASICS_HH Index: olena/oln/core/behavior.hh --- olena/oln/core/behavior.hh Wed, 09 Jun 2004 20:13:57 +0200 van-vl_n (oln/j/47_behavior.h 1.4 600) +++ olena/oln/core/behavior.hh Tue, 15 Jun 2004 15:59:34 +0200 odou_s (oln/j/47_behavior.h 1.4 600) @@ -83,6 +83,9 @@ ntg::cast::force<oln_value_type(I)>(value_)); }; + /// Empty constructor for any_with_diamond hierarchy. + value_behavior() {} + protected: value_type value_; }; Index: olena/oln/makefile.src --- olena/oln/makefile.src Tue, 15 Jun 2004 19:50:21 +0200 thivol_d (oln/r/4_makefile.s 1.4 600) +++ olena/oln/makefile.src Tue, 15 Jun 2004 20:02:22 +0200 odou_s (oln/r/4_makefile.s 1.4 600) @@ -150,6 +150,7 @@ level/set_level.hh \ level/threshold.hh \ math/macros.hh \ + morpher/border_morpher.hh \ morpher/color_morpher.hh \ morpher/func_morpher.hh \ morpher/generic_morpher.hh \ Index: olena/oln/convol/fast_convolution.hh --- olena/oln/convol/fast_convolution.hh Mon, 14 Jun 2004 17:26:55 +0200 odou_s (oln/r/12_fast_convo 1.2 600) +++ olena/oln/convol/fast_convolution.hh Tue, 15 Jun 2004 20:27:36 +0200 odou_s (oln/r/12_fast_convo 1.2 600) @@ -33,6 +33,7 @@ # include <mlc/array/all.hh> # include <oln/transforms/fft.hh> # include <oln/morpher/piece_morpher.hh> +# include <oln/morpher/border_morpher.hh> namespace oln { @@ -44,6 +45,34 @@ */ namespace fast { + /// Internal namespace + namespace internal { + + inline const coord + center_dst(coord n) + { + return n % 2 ? n / 2 + 1 : n / 2; + } + + inline const coord + center_src(coord n) + { + return n % 2 ? n / 2 : (n - 1) / 2; + } + + template <class I, class J, class P> + const P + center(const abstract::image<I>& big_ima, const abstract::image<J>& ima) + { + P p; + for (unsigned i = 0; i < image_id<I>::dim; i++) + p.nth(i) = internal::center_dst(big_ima.size().nth(0)) - + internal::center_src(ima.size().nth(0)) - 1; + return p; + } + + } // end of namespace internal + /*! ** \brief Perform a convolution of two images. ** @@ -99,28 +128,43 @@ { mlc::eq<I::dim, J::dim>::ensure(); mlc::eq<I::dim, 2>::ensure(); - assert(input.npoints() >= k.npoints()); - // We compute k with a size of input (k is centered in big_k). - image2d<oln_value_type(J)> big_k(input.size()); -#define CENTER_DST(I) \ -((I) % 2 ? (I) / 2 + 1 : (I) / 2) -#define CENTER_SRC(I) \ -((I) % 2 ? (I) / 2 : ((I) - 1) / 2) - typedef morpher::piece_morpher< image2d<oln_value_type(J)> > piece_t; - piece_t piece_k(big_k, - dpoint2d(CENTER_DST(big_k.size().nrows()) - - CENTER_SRC(k.size().nrows()) - 1, - CENTER_DST(big_k.size().ncols()) - - CENTER_SRC(k.size().ncols()) - 1), - oln::image2d_size(k.size().nrows(), - k.size().ncols(), - big_k.border())); - oln_iter_type(piece_t) i_k(piece_k); - for_all(i_k) - piece_k[i_k] = k[i_k]; + oln_size_type(I) big_size; + coord width_input = 0; + coord width_k = 0; + for (unsigned i = 0; i < I::dim; i++) + { + big_size.nth(i) = input.size().nth(i) + k.size().nth(i) - 1; + if (width_input < k.size().nth(i) - 1) + { + width_input = k.size().nth(i) - 1; + width_k = input.size().nth(i) - 1; + } + } + big_size.border() = input.border(); + + const morpher::border_morpher< const image2d<oln_value_type(I)>, replicate_behavior<> > + big_input(input.exact(), (width_input + 1) / 2, replicate_bhv()); - transforms::fft<oln_value_type(I), ntg::rect> tr_input(input.exact()); + J big_k(big_size); + oln_iter_type(J) big_iter(big_k); + for_all(big_iter) + big_k[big_iter] = 0; + oln_iter_type(J) k_iter(k); + oln_iter_type(J) input_iter(input); + + morpher::piece_morpher<J> + piece_k(big_k, internal::center<J, J, oln_dpoint_type(J)>(big_k, k), k.size()); + + for_all(k_iter) + piece_k[k_iter] = k[k_iter]; + + /// \todo FIXME: unfortunately, fft does not support morphers for now. + I big_input_(big_input.size()); + for_all(big_iter) + big_input_[big_iter] = big_input[big_iter]; + + transforms::fft<oln_value_type(I), ntg::rect> tr_input(big_input_.exact()); transforms::fft<oln_value_type(J), ntg::rect> tr_k(big_k.exact()); tr_input.transform(); @@ -129,14 +173,19 @@ const typename mute<J, ntg::cplx<ntg::rect, ntg::float_d> >::ret K = tr_k.transform(); - oln_iter_type(I) i_input(Input); - for_all(i_input) { - Input[i_input] *= K[i_input]; + for_all(big_iter) { + Input[big_iter] *= K[big_iter]; // Scale. - Input[i_input] *= Input.size().nrows() * Input.size().ncols(); + Input[big_iter] *= Input.nrows() * Input.ncols(); } - typename mute<I, DestValue>::ret output = tr_input.shift_transform_inv(); + typename mute<I, DestValue>::ret big_output = tr_input.shift_transform_inv(); + typename mute<I, DestValue>::ret output(input.size()); + + morpher::piece_morpher<J> + piece_output(big_output, internal::center<J, J, oln_dpoint_type(J)>(big_input_, input), input.size()); + for_all(input_iter) + output[input_iter] = piece_output[input_iter]; return output; } Index: olena/tests/convol/tests/fast_convol --- olena/tests/convol/tests/fast_convol Mon, 14 Jun 2004 09:07:03 +0200 odou_s (oln/r/13_fast_convo 1.1 600) +++ olena/tests/convol/tests/fast_convol Tue, 15 Jun 2004 18:31:11 +0200 odou_s (oln/r/13_fast_convo 1.1 600) @@ -10,11 +10,6 @@ using namespace ntg; int main() { - oln::utils::key::value_type data_key[] = - {0x7a, 0x42, 0xc0, 0xa5, 0xec, 0xc7, 0x14, 0xa, 0xc7, - 0x21, 0xd9, 0x1f, 0xdb, 0xfa, 0x54, 0xb9}; - oln::utils::key key(data_key); - image2d<int_u8> src(rdata("lena.pgm")); float_d sigma = 2.5; float_d radius = 3; @@ -22,12 +17,12 @@ image2d<float_d> f_src(src.size()); oln_iter_type_(image2d<float_d>) i(src); for_all(i) - f_src[i] = float_d(src[i]); + f_src[i] = cast::bound<float_d>(src[i]); image2d<float_d> tmp = convol::fast::convolve<float_d>(f_src, k); + image2d<float_d> tmp2 = convol::slow::convolve<float_d>(f_src, k); for_all(i) - src[i] = tmp[i]; - if (oln::utils::md5(src) != key) + if (tmp[i] != tmp2[i]) return false; } Index: olena/oln/morpher/border_morpher.hh --- olena/oln/morpher/border_morpher.hh Tue, 15 Jun 2004 20:35:49 +0200 odou_s () +++ olena/oln/morpher/border_morpher.hh Tue, 15 Jun 2004 19:44:35 +0200 odou_s (oln/u/15_border_mor 644) @@ -0,0 +1,384 @@ +// Copyright (C) 2004 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library 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 BORDER_MORPHER_HH +# define BORDER_MORPHER_HH + +# include <oln/morpher/generic_morpher.hh> +# include <oln/core/abstract/behavior.hh> +# include <oln/core/behavior.hh> + +namespace oln { + + namespace morpher { + + template <class I, class BehaviorType, class Exact = mlc::final> + struct border_morpher; + template <class I, class BehaviorType, class Exact = mlc::final> + struct super_border_morpher; + + } // end of namespace morpher + + /// Informations about the super border morpher. + template <class SrcType, class BehaviorType, class Exact> + struct image_id< morpher::super_border_morpher<SrcType, BehaviorType, Exact> > + { + typedef typename mlc::exact_vt< + morpher::super_border_morpher<SrcType, BehaviorType, Exact>, + Exact>::ret + exact_type; + ///< Retrieve the exact type of the image. + }; + + /// Informations about the border morpher. + template <class SrcType, class BehaviorType, class Exact> + struct image_id< morpher::border_morpher<SrcType, BehaviorType, Exact> > + { + enum {dim = SrcType::dim}; ///< The Image dimension. + typedef oln_impl_type(SrcType) impl_type; + ///< Underlying implementation. + typedef oln_value_type(SrcType) value_type; + ///< The value type of the decorated image. + typedef typename mlc::exact_vt<morpher::border_morpher<SrcType, BehaviorType, Exact>, + Exact>::ret exact_type; + ///< Retrieve the exact type of the image. + typedef oln_point_type(SrcType) point_type; + typedef oln_dpoint_type(SrcType) dpoint_type; + typedef oln_size_type(SrcType) size_type; + typedef oln_iter_type(SrcType) iter_type; + }; + + /// Traits for border morpher. + template <class SrcType, class BehaviorType, class Exact> + struct image_traits < morpher::border_morpher<SrcType, BehaviorType, Exact> > + : public + image_traits< + morpher::abstract::generic_morpher< + SrcType, + typename image_id<morpher::border_morpher<SrcType, + BehaviorType, + Exact> >::exact_type + > + > + {}; + + + namespace morpher { + + /// Abstract border morpher class used for code factorization. + template <class SrcType, class BehaviorType, class Exact> + class super_border_morpher + : public abstract::generic_morpher<SrcType, Exact> + { + + public: + + typedef super_border_morpher<SrcType, BehaviorType, Exact> self_type; + typedef typename image_id<self_type>::exact_type exact_type; + typedef abstract::generic_morpher<SrcType, Exact> super_type; + + typedef typename image_id<exact_type>::dpoint_type dpoint_type; + typedef typename image_id<exact_type>::size_type size_type; + + protected: + + /*! + ** \brief Default constructor. + ** \arg ima will be the image. + ** \arg width The width of the border you want to see. + ** \arg be The behavior of the border. + */ + super_border_morpher(const SrcType &ima, + const coord width, + const BehaviorType& be) + : super_type(ima), width(width), be(be) + { + be.adapt_border(ima, width + get_ima().border()); + for (unsigned i = 0; i < image_id<exact_type>::dim; ++i) + { + size_.nth(i) = get_ima().size().nth(i) + 2 * width; + dp_.nth(i) = -width; + } + size_.border() = get_ima().size().border(); + } + + const coord width; ///< The width of the border. + const BehaviorType be; ///< The behavior of the border. + size_type size_; + dpoint_type dp_; + + /*! + ** \brief Empty constructor. + ** + ** Needed by mlc_hierarchy::any_with_diamond. + */ + super_border_morpher() : width(0) + {} + + public: + + /// Return the size (different from the original picture). + const size_type + size() const + { + return size_; + } + + /// Return the point (-width, -width, ...) + const dpoint_type + get_dp() const + { + return dp_; + } + + /// Return the behavior of the border. + const BehaviorType + get_behavior() const + { + return be; + } + + /// Return width, the width of the border. + const coord + get_width() const + { + return width; + } + + /// Useful to debug. + static std::string + name() + { + return "super_border_morpher<" + super_type::name() + ">"; + } + + }; + + /*! + ** \brief The default border morpher class. + ** + ** Using this class, a border of picture is a picture. + ** + ** \see oln::morpher::abstract::generic_morpher + ** \see oln::morpher::border_morph + */ + template <class SrcType, class BehaviorType, class Exact> + struct border_morpher + : public super_border_morpher< + SrcType, + BehaviorType, + typename image_id<border_morpher<SrcType, BehaviorType, Exact> >::exact_type + > + { + typedef border_morpher<SrcType, BehaviorType, Exact> self_type; + typedef typename image_id<self_type>::exact_type exact_type; + typedef super_border_morpher<SrcType, BehaviorType, exact_type> super_type; + + typedef typename image_id<exact_type>::point_type point_type; + typedef typename image_id<exact_type>::dpoint_type dpoint_type; + typedef typename image_id<exact_type>::size_type size_type; + typedef typename image_id<exact_type>::value_type value_type; + + /// Construct the border morpher with an image \a ima. + border_morpher(const SrcType &ima, + const coord width, + const BehaviorType& be) + : super_type(ima, width, be) + {} + + /// Construct the border morpher with another border morpher. + border_morpher(const self_type& r) + : super_type(r.get_ima(), r.get_width(), r.get_behavior()) + {} + + /*! + ** \brief Empty constructor. + ** + ** Needed by mlc_hierarchy::any_with_diamond. + */ + border_morpher() + {} + + /*! + ** \brief Return the stored value at the point. + ** \arg p The point. + ** \return The stored value. + */ + value_type& + at(const point_type& p) + { + return const_cast<value_type &> + ( const_cast<SrcType &>(this->ima_)[p + get_dp()] ); + } + + /*! + ** \brief Return the stored value at the point. + ** \arg p The point. + ** \return The stored value. + */ + const value_type + at(const point_type& p) const + { + return this->ima_[p + get_dp()]; + } + + /*! Perform a shallow copy from the decorated image of \a rhs + ** to the current decorated image. The points will be shared + ** by the two images. + */ + self_type& + assign(self_type& rhs) + { + oln_iter_type(SrcType) it(rhs); + + for_all(it) + this->at(it) = rhs[it]; + return this->exact(); + } + + /*! + ** \brief This operator= assigns rhs to the current image. + */ + self_type& + operator=(SrcType& rhs) + { + return this->exact().assign(rhs); + } + + /// Useful to debug. + static std::string + name() + { + return "border_morpher<" + super_type::name() + ">"; + } + + }; + + /// The specialized version for `const' images. + template <class SrcType, class BehaviorType, class Exact> + struct border_morpher<const SrcType, BehaviorType, Exact> + : public super_border_morpher< + const SrcType, + BehaviorType, + typename image_id<border_morpher<const SrcType, + BehaviorType, + Exact> >::exact_type + > + { + typedef border_morpher<const SrcType, BehaviorType, Exact> self_type; + typedef typename image_id<self_type>::exact_type exact_type; + typedef super_border_morpher<const SrcType, BehaviorType, exact_type> super_type; + + typedef typename image_id<exact_type>::point_type point_type; + typedef typename image_id<exact_type>::dpoint_type dpoint_type; + typedef typename image_id<exact_type>::size_type size_type; + typedef typename image_id<exact_type>::value_type value_type; + + /*! + ** \brief Construct a border morpher. + ** \arg ima The image. + ** \arg width Width + */ + border_morpher(const SrcType &ima, + const coord width, + const BehaviorType& be) + : super_type(ima, width, be) + {} + + /// Construct a border morpher from another one. + border_morpher(const self_type& r) + : super_type(r.get_ima(), r.get_width(), r.get_behavior()) + {} + + /*! + ** \brief Empty constructor. + ** + ** Needed by mlc_hierarchy::any_with_diamond. + */ + border_morpher() {} + + /*! + ** \brief Return the stored value at the point. + ** \arg p The point. + ** \return The stored value. + */ + const value_type + at(const point_type &p) const + { + return this->ima_[p + get_dp()]; + } + + /// Useful to debug. + static std::string + name() + { + return "border_morpher<" + super_type::name() + ">"; + } + + }; + + + /*! + ** \brief Instantiate a temporary read-only border morpher. + ** \arg ima The image. + ** \arg width The width of the border. + ** \arg be The behavior of the border. + ** + ** A border of the image will be viewed. + ** + ** \code + ** #include <oln/morpher/border_morpher.hh> + ** #include <oln/basics2d.hh> + ** int main() + ** { + ** oln::image2d<ntg::rgb_8> imc = oln::load(IMG_IN "lena.ppm"); + ** assert(imc.has_impl()); + ** oln::save(oln::morpher::border_morph(imc, 100, oln::mirror_bhv()), + ** IMG_OUT "oln_morpher_border_morpher.pgm"); + ** } + ** \endcode + ** \image html lena_ppm.png + ** \image latex lena_ppm.png + ** => + ** \image html oln_morpher_border_morpher.png + ** \image latex oln_morpher_border_morpher.png + */ + template <class I, class BehaviorType> + const border_morpher<I, BehaviorType> + border_morph(I &ima, + const coord width, + const BehaviorType& be) + { + return border_morpher<I, BehaviorType>(ima, width, be); + } + + + } // end namespace morpher + +} // end namespace oln + +#endif // !BORDER_MORPHER Index: olena/tests/morpher/tests/border --- olena/tests/morpher/tests/border Tue, 15 Jun 2004 20:35:49 +0200 odou_s () +++ olena/tests/morpher/tests/border Tue, 15 Jun 2004 15:22:04 +0200 odou_s (oln/u/16_border 644) @@ -0,0 +1,92 @@ +// -*- c++ -*- +// Copyright (C) 2004 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library 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. + +#include <oln/morpher/border_morpher.hh> +#include <oln/basics2d.hh> +#include <ntg/all.hh> + +#include <oln/utils/md5.hh> +#include "data.hh" +#include "check.hh" + +// Try to read from the morpher. +template <class E, class F> +void foo(const oln::abstract::image<E>& src, oln::abstract::image<F>& dst) +{ + oln_iter_type(oln::abstract::image<E>) it(dst); + for_all(it) + dst[it] = src[it]; +} + +// Try to write inside the morpher. +template <class E, class F> +void foo(oln::abstract::image<E>& src, oln::abstract::image<F>& dst) +{ + oln_iter_type(oln::abstract::image<E>) it_src(dst); + + for_all(it_src) + src[it_src] = dst[it_src]; +} + +int main() +{ + bool fail (false); + + oln::utils::key::value_type data1_key[16] = + {0x5b, 0x8c, 0xd9, 0x41, 0xc6, 0x62, 0x58, 0x34, 0xff, + 0x4c, 0x4, 0x8, 0x33, 0xf2, 0x95, 0xd7}; + oln::utils::key::value_type data2_key[16] = + {0x5a, 0xd1, 0xac, 0x80, 0xec, 0xbd, 0x17, 0x96, 0xad, + 0x12, 0xec, 0xe7, 0x2b, 0xa5, 0x50, 0xa2}; + + + oln::coord delta = 10; + oln::image2d<ntg::rgb_8> im = oln::load(rdata("lena.ppm")); + const oln::image2d<ntg::rgb_8> im_const = oln::load(rdata("lena.ppm")); + oln::image2d<ntg::rgb_8> im_out(oln::image2d_size(im.size().nrows() + 2*delta, + im.size().ncols() + 2*delta, im.border())); + oln::image2d<ntg::rgb_8> im_const_out(oln::image2d_size(im.size().nrows() + 2*delta, + im.size().ncols() + 2*delta, im.border())); + + oln::morpher::border_morpher< oln::image2d<ntg::rgb_8>, oln::mirror_behavior<> > im_nonconst_out(im, delta, oln::mirror_bhv()); + + foo(im_nonconst_out, im); + foo(oln::morpher::border_morph(im, delta, oln::mirror_bhv()), im_out); + foo(oln::morpher::border_morph(im_const, delta, oln::mirror_bhv()), im_const_out); + + fail = fail | (oln::utils::md5(im_const_out) != oln::utils::key(data2_key)); + fail = fail | (oln::utils::md5(im_out) != oln::utils::key(data1_key)); + + if (!fail) + std::cout << "OK" << std::endl; + else + { + std::cout << "FAIL" << std::endl; + return true; + } +} -- Simon Odou simon@lrde.epita.fr