* 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(a)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(a)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