olena: olena-2.0-853-g8f4ee01 Various changes in mln::border::mirror.

* mln/border/mirror.hh: Here. * tests/border/mirror.cc: Revamp test. * tests/border/Makefile.am (check_PROGRAMS): Reenable mirror_full. --- milena/ChangeLog | 8 ++ milena/mln/border/mirror.hh | 225 ++++++++++++++++++--------------------- milena/tests/border/Makefile.am | 5 +- milena/tests/border/mirror.cc | 74 +++++++------ 4 files changed, 157 insertions(+), 155 deletions(-) diff --git a/milena/ChangeLog b/milena/ChangeLog index a2e295e..0206b0f 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,11 @@ +2014-05-20 Roland Levillain <roland@lrde.epita.fr> + + Various changes in mln::border::mirror. + + * mln/border/mirror.hh: Here. + * tests/border/mirror.cc: Revamp test. + * tests/border/Makefile.am (check_PROGRAMS): Reenable mirror_full. + 2012-10-02 Guillaume Lazzara <z@lrde.epita.fr> Fix a precondition (Trac ticket #256). diff --git a/milena/mln/border/mirror.hh b/milena/mln/border/mirror.hh index 89a132d..6fcb788 100644 --- a/milena/mln/border/mirror.hh +++ b/milena/mln/border/mirror.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2007, 2008, 2009, 2011, 2012, 2013 EPITA Research and -// Development Laboratory (LRDE) +// Copyright (C) 2007, 2008, 2009, 2011, 2012, 2013, 2014 EPITA +// Research and Development Laboratory (LRDE). // // This file is part of Olena. // @@ -28,28 +28,23 @@ # define MLN_BORDER_MIRROR_HH /// \file +/// \brief Fill an image's border using a mirror tranformation. /// -/// Define function that fills border using nearer pixels with a -/// mirroring effect. -/// -/// \todo 2D version is not correct if the border is larger than the -/// image domain. -/// -/// \todo Awful code: rewrite it! +/// \todo The 2D version is not correct when the border is larger than +/// the image's domain. # include <mln/core/image/image1d.hh> # include <mln/core/image/image2d.hh> # include <mln/core/image/image3d.hh> -# include <mln/core/concept/image.hh> -# include <mln/core/internal/fixme.hh> -# include <mln/core/internal/fixme.hh> # include <mln/geom/min_row.hh> # include <mln/geom/max_row.hh> # include <mln/geom/min_col.hh> # include <mln/geom/max_col.hh> # include <mln/geom/ninds.hh> +# include <mln/math/min.hh> + # include <mln/opt/element.hh> @@ -60,13 +55,18 @@ namespace mln { /*! \brief Mirror the virtual (outer) border of image \p ima with - * the (inner) level contents of this image. + * the (inner) contents of this image. * * \param[in,out] ima The image whose border is to be mirrored. + * Note that \a ima is modified, even though it + * is passed as a const reference, + * as---following to the usual Milena + * semantics---only values in the border (not + * the actual image's contents) are altered by + * this routine. * - * \pre \p ima has to be initialized. - * - * \todo Implement 3d version + optimize with memset if possible. + * \todo Implement a 3D version. + * \todo Optimize using memset if possible. * * \ingroup mlnborderext */ @@ -79,131 +79,122 @@ namespace mln namespace impl { + // Implementation for images based on an mln::box1d. + template <typename I> inline - void mirror_(const box1d&, const I& ima_) + void mirror_(const box1d&, I& ima) { mln_trace("border::impl::mirror_"); - I& ima = const_cast<I&>(ima_); - - def::coord - border = static_cast<def::coord>(ima.border()), - nbinds = static_cast<def::coord>(geom::ninds(ima)), - min; - - if (border > nbinds) - min = nbinds; - else - min = border; - - /// left border - { - def::coord i = 0; - for (; i < min; ++i) - opt::element(ima, border - 1 - i) = ima(point1d(i)); - - for (; i < border; ++i) - opt::element(ima, border - 1 - i) = ima(point1d(static_cast<def::coord>(min - 1))); - } - - /// right border - { - def::coord - i = 0, - j = static_cast<def::coord>(nbinds - 1); - for (; - i < min; - ++i, --j) - opt::element(ima, border + nbinds + i) = ima(point1d(j)); - ++j; - for (; - i < border; - ++i) - opt::element(ima, border + nbinds + i) = ima(point1d(j)); - } + + def::coord border = ima.border(); + def::coord ninds = geom::ninds(ima); + def::coord min = math::min(border, ninds); + + // Left-hand border. + for (def::coord i = 0; i < min; ++i) + opt::element(ima, border - 1 - i) = ima(point1d(i)); + for (def::coord i = min; i < border; ++i) + opt::element(ima, border - 1 - i) = ima(point1d(min - 1)); + + // Right-hand border. + def::coord j = ninds - 1; + for (def::coord i = 0; i < min; ++i, --j) + opt::element(ima, border + ninds + i) = ima(point1d(j)); + ++j; + for (def::coord i = min; i < border; ++i) + opt::element(ima, border + ninds + i) = ima(point1d(j)); } + + // Implementation for images based on an mln::box2d. + template <typename I> inline - void mirror_(const box2d&, const I& ima_) + void mirror_(const box2d&, I& ima) { mln_trace("border::impl::mirror_"); - I& ima = const_cast<I&>(ima_); - - unsigned border = ima.border (); - unsigned nbrows = geom::max_row(ima) - geom::min_row(ima); - unsigned nbcols = geom::max_col(ima) - geom::min_col(ima); - unsigned real_nbcols = (nbcols + 1) + 2 * border; - unsigned start = real_nbcols * border + border; - unsigned s = start; - - // mirror top left corner - for (unsigned i = 0; i < border; ++i) - for (unsigned j = 0; j < border; ++j) - opt::element(ima, i * ((nbcols + 1) + 2 * border) + j) = + + /* FIXME: This implementation is buggy, as it does not address + the case of a border larger than the width or the height of + the image. */ + + def::coord border = ima.border (); + def::coord nrows = geom::max_row(ima) - geom::min_row(ima); + def::coord ncols = geom::max_col(ima) - geom::min_col(ima); + def::coord real_ncols = (ncols + 1) + 2 * border; + def::coord start = real_ncols * border + border; + def::coord s = start; + + // Top left-hand corner. + for (def::coord i = 0; i < border; ++i) + for (def::coord j = 0; j < border; ++j) + opt::element(ima, i * real_ncols + j) = opt::element(ima, s); - // mirror top left corner - s = start + nbcols; - for (unsigned i = 0; i < border; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, i * ((nbcols + 1) + 2 * border) + (nbcols + border + j)) = opt::element(ima, s); - - // mirror bottom left corner - s = start + (nbrows * real_nbcols); - for (unsigned i = 1; i <= border; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, s - i + (j * (real_nbcols))) = + // Top right-hand corner. + s = start + ncols; + for (def::coord i = 0; i < border; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, i * real_ncols + (ncols + border + j)) = opt::element(ima, s); - // mirror bottom right corner - s = start + (nbrows * real_nbcols) + nbcols; - for (unsigned i = 1; i <= border; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, s + i + (j * real_nbcols)) = + // Bottom left-hand corner. + s = start + (nrows * real_ncols); + for (def::coord i = 1; i <= border; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, s - i + (j * real_ncols)) = opt::element(ima, s); - // mirror top border - s = start; - for (unsigned i = 0; i <= nbcols; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, s + i - (j * real_nbcols)) = - opt::element(ima, s + i + ((j - 1)* real_nbcols)); + // Bottom right-hand corner. + s = start + (nrows * real_ncols) + ncols; + for (def::coord i = 1; i <= border; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, s + i + (j * real_ncols)) = + opt::element(ima, s); - // mirror left border + // Top border. s = start; - for (unsigned i = 0; i <= nbrows; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, s + (i * real_nbcols) - j) = - opt::element(ima, s + (i * real_nbcols) + (j - 1)); + for (def::coord i = 0; i <= ncols; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, s + i - (j * real_ncols)) = + opt::element(ima, s + i + ((j - 1) * real_ncols)); - // mirror right border + // Left-hand border. s = start; - for (unsigned i = 0; i <= nbrows; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, s + (i * real_nbcols + nbcols) + j) = - opt::element(ima, s + (i * real_nbcols + nbcols) - (j - 1)); - - // mirror bottom border - s = start + (nbrows * real_nbcols); - for (unsigned i = 0; i <= nbcols; ++i) - for (unsigned j = 1; j <= border; ++j) - opt::element(ima, s + i + (j * real_nbcols)) = - opt::element(ima, s + i - ((j - 1)* real_nbcols)); + for (def::coord i = 0; i <= nrows; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, s + (i * real_ncols) - j) = + opt::element(ima, s + (i * real_ncols) + (j - 1)); + // Right-hand border. + s = start; + for (def::coord i = 0; i <= nrows; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, s + (i * real_ncols + ncols) + j) = + opt::element(ima, s + (i * real_ncols + ncols) - (j - 1)); + + // Bottom border. + s = start + (nrows * real_ncols); + for (def::coord i = 0; i <= ncols; ++i) + for (def::coord j = 1; j <= border; ++j) + opt::element(ima, s + i + (j * real_ncols)) = + opt::element(ima, s + i - ((j - 1) * real_ncols)); } + + // Implementation for images based on an mln::box3d. + template <typename I> inline - void mirror_(const box3d&, const I& ima) + void mirror_(const box3d&, I& /* ima */) { mln_trace_warning("border::mirror for 3D image is not implemented," " so image borders have not been mirrored!"); - (void) ima; - // FIXME write it! + // FIXME: write it! + abort(); } - } // end of namespace mln::border::impl @@ -212,19 +203,13 @@ namespace mln void mirror(const Image<I>& ima_) { mln_trace("border::mirror"); - - const I& ima = exact(ima_); - - mln_precondition(ima.is_valid()); mlc_is(mln_trait_image_speed(I), trait::image::speed::fastest)::check(); - typedef mln_psite(I) P; - - if (!ima.border ()) + I& ima = const_cast<I&>(exact(ima_)); + mln_precondition(ima.is_valid()); + if (!ima.border()) return; - impl::mirror_(ima.bbox(), ima); - } # endif // ! MLN_INCLUDE_ONLY diff --git a/milena/tests/border/Makefile.am b/milena/tests/border/Makefile.am index 64c8197..a268a5b 100644 --- a/milena/tests/border/Makefile.am +++ b/milena/tests/border/Makefile.am @@ -1,5 +1,5 @@ -# Copyright (C) 2007, 2008, 2009, 2010, 2011 EPITA Research and Development -# Laboratory (LRDE). +# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2014 EPITA Research and +# Development Laboratory (LRDE). # # This file is part of Olena. # @@ -26,6 +26,7 @@ check_PROGRAMS = \ find \ get \ mirror \ + mirror_full \ resize_equal \ resize_image1d_1 \ resize_image1d_2 \ diff --git a/milena/tests/border/mirror.cc b/milena/tests/border/mirror.cc index 09435e5..58a038e 100644 --- a/milena/tests/border/mirror.cc +++ b/milena/tests/border/mirror.cc @@ -1,5 +1,5 @@ -// Copyright (C) 2007, 2008, 2009, 2011 EPITA Research and Development -// Laboratory (LRDE) +// Copyright (C) 2007, 2008, 2009, 2011, 2014 EPITA Research and Development +// Laboratory (LRDE). // // This file is part of Olena. // @@ -24,7 +24,7 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -/// \file +// Exercise mln::border::mirror. #include <mln/core/image/image1d.hh> #include <mln/core/image/image2d.hh> @@ -35,46 +35,54 @@ #include <mln/data/paste_without_localization.hh> #include <mln/data/compare.hh> -using namespace mln; - int -main (void) +main() { - { - image1d<int> ima(2, 3); - debug::iota(ima); - border::mirror(ima); - mln_assertion(opt::element(ima, 0) == 2); - mln_assertion(opt::element(ima, 1) == 2); - mln_assertion(opt::element(ima, 2) == 1); - mln_assertion(opt::element(ima, 3) == 1); - mln_assertion(opt::element(ima, 4) == 2); - mln_assertion(opt::element(ima, 5) == 2); - mln_assertion(opt::element(ima, 6) == 1); - mln_assertion(opt::element(ima, 7) == 1); - } - + using namespace mln; - // Image2d + // image1d. { - unsigned ref_data[6][7] = { - { 1, 1, 4, 5, 6, 3, 3 }, - { 1, 1, 1, 2, 3, 3, 3 }, - { 2, 1, 1, 2, 3, 3, 2 }, - { 5, 4, 4, 5, 6, 6, 5 }, - { 4, 4, 4, 5, 6, 6, 6 }, - { 4, 4, 1, 2, 3, 6, 6 } - }; + // A 2-pixel 1D image with a 3-pixel border. + image1d<unsigned> input(2, 3); + debug::iota(input); + border::mirror(input); + // Data are framed; other values form the border. + unsigned ref_data[8] = + // ,-------------. + { 2, 2, 1, /* | */ 1, 2, /* | */ 2, 1, 1 }; + // `-------------' + image1d<unsigned> ref = make::image(ref_data); - image2d<unsigned> ref = make::image(ref_data); + image1d<unsigned> output(8, 0); + data::paste_without_localization(extended_to(input, input.vbbox()), + output); + mln_assertion(output == ref); + } + + // image2d. + { + // A 2x3-pixel 2D image with a 2-pixel border. image2d<unsigned> input(2, 3, 2); - image2d<unsigned> res(6, 7, 0); debug::iota(input, 0); border::mirror(input); - data::paste_without_localization(extended_to(input, input.vbbox()), res); + // Data are framed; other values form the border. + unsigned ref_data[6][7] = { + { 1, 1, 4, 5, 6, 3, 3 }, + { 1, 1, 1, 2, 3, 3, 3 }, + // ,----------------. + { 2, 1, /* | */ 1, 2, 3, /* | */ 3, 2 }, + { 5, 4, /* | */ 4, 5, 6, /* | */ 6, 5 }, + // `----------------' + { 4, 4, 4, 5, 6, 6, 6 }, + { 4, 4, 1, 2, 3, 6, 6 } + }; + image2d<unsigned> ref = make::image(ref_data); - mln_assertion(res == ref); + image2d<unsigned> output(6, 7, 0); + data::paste_without_localization(extended_to(input, input.vbbox()), + output); + mln_assertion(output == ref); } } -- 1.7.10.4
participants (1)
-
Roland Levillain