Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
February 2009
- 12 participants
- 266 discussions
16 Feb '09
* mln/make/graph.hh: use an adjacency matrix and a neighborhood.
* mln/make/region_adjacency_graph.hh: make a graph from a watershed
image.
* tests/make/Makefile.am,
* tests/make/graph.cc,
* tests/make/region_adjacency_graph.cc: add new tests.
---
milena/ChangeLog | 13 ++
milena/mln/make/graph.hh | 84 ++++++++----
milena/mln/make/region_adjacency_graph.hh | 202 +++++++++++++++++++++++++++
milena/mln/util/graph.hh | 10 ++
milena/tests/make/Makefile.am | 6 +-
milena/tests/make/graph.cc | 58 ++++++++
milena/tests/make/region_adjacency_graph.cc | 59 ++++++++
7 files changed, 403 insertions(+), 29 deletions(-)
create mode 100644 milena/mln/make/region_adjacency_graph.hh
create mode 100644 milena/tests/make/graph.cc
create mode 100644 milena/tests/make/region_adjacency_graph.cc
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 7797b25..2282bcd 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,16 @@
+2009-02-16 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Fix make::graph and add make::region_adjacency_graph.
+
+ * mln/make/graph.hh: use an adjacency matrix and a neighborhood.
+
+ * mln/make/region_adjacency_graph.hh: make a graph from a watershed
+ image.
+
+ * tests/make/Makefile.am,
+ * tests/make/graph.cc,
+ * tests/make/region_adjacency_graph.cc: add new tests.
+
2009-02-13 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Add unit test for n_max.hh.
diff --git a/milena/mln/make/graph.hh b/milena/mln/make/graph.hh
index df76416..c9dddb1 100644
--- a/milena/mln/make/graph.hh
+++ b/milena/mln/make/graph.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -34,6 +35,11 @@
///
/// \sa transform::influence_zone_geodesic.
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/box2d.hh>
+# include <mln/extension/adjust_fill.hh>
# include <mln/util/graph.hh>
namespace mln
@@ -48,8 +54,10 @@ namespace mln
/// \param[in] nlabels number of influence zone in \p iz.
///
/// \return util::graph Graph based on the adjacency of the influence zones.
- template <typename I>
- util::graph graph(const Image<I>& iz, mln_value(I) nlabels);
+ template <typename I, typename N>
+ util::graph
+ graph(const Image<I>& iz_, const Neighborhood<N>& nbh,
+ mln_value(I) nlabels);
@@ -59,53 +67,71 @@ namespace mln
namespace internal
{
- template <typename I>
+ template <typename I, typename N>
void
- graph_tests(const Image<I>& iz, mln_value(I))
+ graph_tests(const Image<I>& iz, const Neighborhood<N>& nbh,
+ mln_value(I))
{
mln_precondition(exact(iz).is_valid());
-
+ mln_precondition(exact(nbh).is_valid());
(void) iz;
+ (void) nbh;
}
} // end of namespace mln::make::internal
-
namespace impl
{
namespace generic
{
- template <typename I>
+ template <typename I, typename N>
util::graph
- graph(const Image<I>& iz_, mln_value(I) nlabels)
+ graph(const Image<I>& iz_, const Neighborhood<N>& nbh_,
+ mln_value(I) nlabels)
{
trace::entering("make::impl::generic::graph");
- internal::graph_tests(iz_, nlabels);
+ internal::graph_tests(iz_, nbh_, nlabels);
const I& iz = exact(iz_);
+ const N& nbh = exact(nbh_);
- util::graph g;
- g.add_vertices(nlabels.next());
+ mln::image2d<bool> adj(mln::box2d(nlabels.next(), nlabels.next()));
+ data::fill(adj, false);
+ typedef mln_value(I) L;
mln_piter(I) p(iz.domain());
+ mln_niter(N) n(nbh, p);
for_all(p)
{
- // Checking 'forward' neighboors and create an edge if necessary.
- for (unsigned dim = 0; dim < mln_site_(I)::dim; ++dim)
+ L l1 = iz(p);
+ for_all(n)
{
- mln_site(I) n = p;
- ++n[dim];
-
- // FIXME: check that calling iz.domain().has() is correct
- // and that we don't prefer iz.has().
- if (iz.domain().has(n) && iz(p) != iz(n))
- g.add_edge(iz(p), iz(n));
+ if (iz.domain().has(n))
+ {
+ L l2 = iz(n);
+ if (iz(n) != iz((p)))
+ {
+ // l2 is adjacent to l1
+ if (l2 < l1)
+ adj(point2d(l1,l2)) = true;
+ else
+ adj(point2d(l2,l1)) = true;
+ }
+ }
}
}
+ // Construct graph.
+ util::graph g;
+ g.add_vertices(nlabels.next());
+ for (unsigned i = 0; i < geom::nrows(adj); ++i)
+ for (unsigned j = 0; j < i; ++j)
+ if (adj(point2d(i,j)))
+ g.add_edge(i, j);
+
trace::exiting("make::impl::generic::graph");
return g;
}
@@ -119,11 +145,12 @@ namespace mln
namespace internal
{
- template <typename I>
+ template <typename I, typename N>
util::graph
- graph_dispatch(const Image<I>& iz, mln_value(I) nlabels)
+ graph_dispatch(const Image<I>& iz, const Neighborhood<N>& nbh,
+ mln_value(I) nlabels)
{
- return make::impl::generic::graph(iz, nlabels);
+ return make::impl::generic::graph(iz, nbh, nlabels);
}
} // end of namespace mln::make::internal
@@ -132,16 +159,17 @@ namespace mln
// Facade
- template <typename I>
+ template <typename I, typename N>
inline
util::graph
- graph(const Image<I>& iz, mln_value(I) nlabels)
+ graph(const Image<I>& iz, const Neighborhood<N>& nbh,
+ mln_value(I) nlabels)
{
trace::entering("make::graph");
- internal::graph_tests(iz, nlabels);
+ internal::graph_tests(iz, nbh, nlabels);
- util::graph g = internal::graph_dispatch(iz, nlabels);
+ util::graph g = internal::graph_dispatch(iz, nbh, nlabels);
trace::exiting("make::graph");
return g;
diff --git a/milena/mln/make/region_adjacency_graph.hh b/milena/mln/make/region_adjacency_graph.hh
new file mode 100644
index 0000000..695174d
--- /dev/null
+++ b/milena/mln/make/region_adjacency_graph.hh
@@ -0,0 +1,202 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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.
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_MAKE_REGION_ADJACENCY_GRAPH_HH
+# define MLN_MAKE_REGION_ADJACENCY_GRAPH_HH
+
+/// \file mln/make/region_adjacency_graph.hh
+///
+/// Create a region_adjacency_graph from a watershed image.
+///
+/// \sa morpho::meyer_wst.
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/box2d.hh>
+# include <mln/extension/adjust_fill.hh>
+# include <mln/util/graph.hh>
+
+namespace mln
+{
+
+ namespace make
+ {
+
+ /// Create a region adjacency graph from a watershed image.
+ ///
+ /// \param[in] wshd watershed image.
+ /// \param[in] nbasins number of influence zone in \p wshd.
+ ///
+ /// \return util::graph Graph based on the adjacency of the influence zones.
+ template <typename I, typename N>
+ util::graph
+ region_adjacency_graph(const Image<I>& wshd_,
+ const Neighborhood<N>& nbh,
+ mln_value(I) nbasins);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ namespace internal
+ {
+
+ template <typename I, typename N>
+ void
+ region_adjacency_graph_tests(const Image<I>& wshd,
+ const Neighborhood<N>& nbh,
+ mln_value(I))
+ {
+ mln_precondition(exact(wshd).is_valid());
+ mln_precondition(exact(nbh).is_valid());
+ (void) wshd;
+ (void) nbh;
+ }
+
+ } // end of namespace mln::make::internal
+
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ template <typename I, typename N>
+ util::graph
+ region_adjacency_graph(const Image<I>& wshd_,
+ const Neighborhood<N>& nbh_,
+ mln_value(I) nbasins)
+ {
+ trace::entering("make::impl::generic::region_adjacency_graph");
+
+ internal::region_adjacency_graph_tests(wshd_, nbh_, nbasins);
+ const I& wshd = exact(wshd_);
+ const N& nbh = exact(nbh_);
+
+ mln::image2d<bool> adj(mln::box2d(nbasins.next(), nbasins.next()));
+ data::fill(adj, false);
+ extension::adjust_fill(wshd, nbh, 0u);
+
+ typedef mln_value(I) L;
+ L l1, l2;
+ mln_piter(I) p(wshd.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ if (wshd(p) != 0u)
+ continue;
+ // p is in the watershed line.
+ l1 = l2 = 0;
+ for_all(n)
+ if (wshd.has(n) && wshd(n) != 0u)
+ {
+ if (l1 == 0u) // First label to be stored.
+ l1 = wshd(n);
+ else
+ if (wshd(n) != l1) // Useless: && l2 == 0)
+ { // Second label to be stored.
+ mln_invariant(l2 == 0u);
+ l2 = wshd(n);
+ break;
+ }
+ }
+ if (l2 == 0u || l1 == 0u)
+ continue;
+ if (l2 < l1)
+ std::swap(l1, l2);
+
+ // adjacency l1 l2
+ adj(point2d(l2,l1)) = true;
+ }
+
+ // Construct graph.
+ util::graph g;
+ g.add_vertices(nbasins.next());
+ for (unsigned i = 1; i < geom::nrows(adj); ++i)
+ for (unsigned j = 1; j < i; ++j)
+ if (adj(point2d(i,j)))
+ g.add_edge(i, j);
+
+
+ trace::exiting("make::impl::generic::region_adjacency_graph");
+ return g;
+ }
+
+ } // end of namespace mln::make::impl::generic
+
+ } // end of namespace mln::make::impl
+
+
+
+ namespace internal
+ {
+
+ template <typename I, typename N>
+ util::graph
+ region_adjacency_graph_dispatch(const Image<I>& wshd,
+ const Neighborhood<N>& nbh,
+ mln_value(I) nbasins)
+ {
+ return make::impl::generic::region_adjacency_graph(wshd, nbh, nbasins);
+ }
+
+ } // end of namespace mln::make::internal
+
+
+
+ // Facade
+
+ template <typename I, typename N>
+ inline
+ util::graph
+ region_adjacency_graph(const Image<I>& wshd,
+ const Neighborhood<N>& nbh,
+ mln_value(I) nbasins)
+ {
+ trace::entering("make::region_adjacency_graph");
+
+ internal::region_adjacency_graph_tests(wshd, nbh, nbasins);
+
+ util::graph g = internal::region_adjacency_graph_dispatch(wshd, nbh, nbasins);
+
+ trace::exiting("make::region_adjacency_graph");
+ return g;
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace mln::make
+
+} // end of namespace mln
+
+
+#endif // ! MLN_MAKE_REGION_ADJACENCY_GRAPH_HH
diff --git a/milena/mln/util/graph.hh b/milena/mln/util/graph.hh
index 897deb4..f95e1e8 100644
--- a/milena/mln/util/graph.hh
+++ b/milena/mln/util/graph.hh
@@ -71,8 +71,11 @@ namespace mln
vertices_t vertices_;
/// The edges.
edges_t edges_;
+
+# ifndef NDEBUG
/// An index of the set of edges, for fast-access purpose.
edges_set_t edges_set_;
+# endif // ! NDEBUG
};
} // end of namespace mln::internal
@@ -383,8 +386,10 @@ namespace mln
unsigned
graph::add_edge(unsigned id_v1, unsigned id_v2)
{
+ //FIXME: to be removed! We should not check that, except in without NDEBUG.
// Does this edge already exist in the graph?
edge_data_t edge(id_v1, id_v2);
+# ifndef NDEBUG
if (data_->edges_set_.find(edge) != data_->edges_set_.end ())
{
// Return the erroneous value.
@@ -392,6 +397,7 @@ namespace mln
}
else
{
+# endif // ! NDEBUG
// Otherwise insert it into the graph.
/* FIXME: This is not thread-proof (these two lines should
form an atomic section). */
@@ -404,7 +410,11 @@ namespace mln
data_->vertices_[edge.second()].push_back(id);
return id;
+
+# ifndef NDEBUG
}
+# endif // ! NDEBUG
+
}
inline
diff --git a/milena/tests/make/Makefile.am b/milena/tests/make/Makefile.am
index 913867c..95eb5ea 100644
--- a/milena/tests/make/Makefile.am
+++ b/milena/tests/make/Makefile.am
@@ -4,18 +4,22 @@ include $(top_srcdir)/milena/tests/tests.mk
check_PROGRAMS = \
dual_neighb \
+ graph \
h_mat \
image2d \
image3d \
mat \
+ region_adjacency_graph \
w_window \
w_window_directional
-dual_neighb_SOURCES = dual_neighb.cc
+dual_neighb_SOURCES = dual_neighb.c
+graph_SOURCES = graph.cc
h_mat_SOURCES = h_mat.cc
image2d_SOURCES = image2d.cc
image3d_SOURCES = image3d.cc
mat_SOURCES = mat.cc
+region_adjacency_graph_SOURCES = region_adjacency_graph.cc
w_window_SOURCES = w_window.cc
w_window_directional_SOURCES = w_window_directional.cc
diff --git a/milena/tests/make/graph.cc b/milena/tests/make/graph.cc
new file mode 100644
index 0000000..bb88706
--- /dev/null
+++ b/milena/tests/make/graph.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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.
+
+/// \file tests/make/graph.cc
+///
+/// Tests on mln::make::graph.
+
+#include <mln/make/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/util/graph.hh>
+#include <mln/make/graph.hh>
+#include <mln/value/label_8.hh>
+
+
+int main()
+{
+ using namespace mln;
+
+ value::label_8 vals[9] = { 1, 1, 3,
+ 1, 2, 3,
+ 1, 0, 4 };
+
+ image2d<value::label_8> ima = make::image2d(vals);
+
+ util::graph g = make::graph(ima, c4(), 4u);
+
+ mln_assertion(g.e_nmax() == 7u);
+ mln_assertion(g.v_nmax() == 5u);
+ mln_assertion(g.v_nmax_nbh_edges(0) == 3);
+ mln_assertion(g.v_nmax_nbh_edges(1) == 3);
+ mln_assertion(g.v_nmax_nbh_edges(2) == 3);
+ mln_assertion(g.v_nmax_nbh_edges(3) == 3);
+ mln_assertion(g.v_nmax_nbh_edges(4) == 2);
+}
diff --git a/milena/tests/make/region_adjacency_graph.cc b/milena/tests/make/region_adjacency_graph.cc
new file mode 100644
index 0000000..7f8cb12
--- /dev/null
+++ b/milena/tests/make/region_adjacency_graph.cc
@@ -0,0 +1,59 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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.
+
+/// \file tests/make/graph.cc
+///
+/// Tests on mln::make::region_adjacency_graph.
+
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/util/graph.hh>
+
+#include <mln/value/label_8.hh>
+
+#include <mln/make/image2d.hh>
+#include <mln/make/region_adjacency_graph.hh>
+
+int main()
+{
+ using namespace mln;
+
+ value::label_8 vals[16] = { 1, 0, 3, 3,
+ 1, 0, 0, 0,
+ 0, 0, 4, 4,
+ 2, 2, 0, 4 };
+
+ image2d<value::label_8> ima = make::image2d(vals);
+
+ util::graph g = make::region_adjacency_graph(ima, c4(), 4u);
+
+ mln_assertion(g.e_nmax() == 4u);
+ mln_assertion(g.v_nmax() == 5u);
+ mln_assertion(g.v_nmax_nbh_edges(0) == 0);
+ for (unsigned i = 1; i < 4; ++i)
+ mln_assertion(g.v_nmax_nbh_edges(i) == 2);
+}
--
1.5.6.5
1
0
15 Feb '09
Hand-made message, because Vcs wouldn't let me send it for obscure diff
reasons.
Fix and generate more images for the Applications.
* article.sty (areaclosing): New operator. Use it...
* article.tex: ..here.
(section{Applications}): Simplify the chain.
Adjust listing, and show actual code.
Add more images.
Reorganize.
* apps/chain.hh: Move the computation of the gradient out of the
chain.
* apps/image2d.cc: Adjust.
* apps/complex.cc: Start to adjust (unfinished work).
* apps/chain.lst: New.
* apps/lena-g.png: New.
* apps/graph.cc,
* apps/graph.neato, apps/graph.pdf,
* apps/graph-g.nato, apps/graph-g.pdf,
* apps/graph-s.neato, apps/graph-s.pdf:
New.
* pics/graph.cc: Fix a previous patch by adding a missing #include.
* apps/new/: New directory.
* apps/new/m283.gcl, apps/new/m283.off, apps/new/m283.png
* apps/new/m283-c.gcl, apps/new/m283-c.off, apps/new/m283-c.png
* apps/new/m283-s.gcl, apps/new/m283-s.off, apps/new/m283-s.png:
New.
* Makefile (IMAGES): Add apps/lena-g.png.
Move old images...
(IMAGES_OLD): ...here (new).
(article.pdf): Depend on apps/chain.lst.
(apps/graph-s.neato): New target.
(%-g.gcl, %-c.gcl): New targets.
(%-s.off): Disable target.
* apps/old/: New directory.
* apps/m283.gcl, apps/m283.off, apps/m283.png,
* apps/m283-s.off, apps/m283-s.png:
Move...
* apps/old/m283.gcl, apps/old/m283.off, apps/old/m283.png,
* apps/old/m283-s.off, apps/old/m283-s.png:
...here.
Index: article.sty
===================================================================
--- article.sty (revision 3417)
+++ article.sty (revision 3418)
@@ -11,6 +11,7 @@
\RequirePackage{amsopn}
\DeclareMathOperator{\attrclosing}{attribute-closing}
+\DeclareMathOperator{\areaclosing}{area-closing}
\DeclareMathOperator{\gradientnorm}{gradient-norm}
\DeclareMathOperator{\wst}{wst}
Index: article.tex
===================================================================
--- article.tex (revision 3417)
+++ article.tex (revision 3418)
@@ -782,28 +782,24 @@
\section{Applications}
\label{sec:applications}
-\fixme{Remove the gradient step: $G$ should be our input.}
+In this part, we consider a simple, classical image processing chain
+(\autoref{fig:chain-diagram}): from an image $I$ (e.g., the magnitude
+of a gradient), compute an area closing $C$ using criterion value
+$\lambda$; then, perform a \ac{wst} on $C$ to obtain a segmentation
+$S$.
-In this part, we consider a simple, classical image processing chain:
-from an image $I$, produce an image of the magnitude of the gradient
-$G$; then compute an attribute closing $C$ using an attribute $\alpha$
-and a criterion value $\lambda$; last, perform a \ac{wst} on $C$ to
-obtain a segmentation $S$.
-
\begin{figure}
\centering
\begin{tikzpicture}
\tikzstyle{im}=[minimum height=0.6cm]
\tikzstyle{op}=[rectangle, minimum height=0.6cm]
- \node[im] (i) at ( 0.0,2) {$I$};
- \node[op] (closing) at ( 2.0,2) [draw] {$\gradientnorm$};
- \node[im] (c) at ( 4.0,2) {$G$};
- \node[op] (gradient) at ( 6.5,2) [draw] {$\attrclosing$ $(\alpha, \lambda)$};
- \node[im] (g) at ( 9.0,2) {$C$};
+ \node[im] (i) at ( 5.0,2) {$I$};
+ \node[op] (closing) at ( 7.0,2) [draw] {$\areaclosing$ $(\lambda)$};
+ \node[im] (c) at ( 9.0,2) {$C$};
\node[op] (wst) at (10.0,2) [draw] {$\wst$};
\node[im] (s) at (11.0,2) {$S$};
- \foreach \from/\to in {i/closing,closing/c,c/gradient,gradient/g,g/wst,wst/s}
+ \foreach \from/\to in {i/closing,closing/c,c/wst,wst/s}
\draw[->] (\from) -- (\to);
\end{tikzpicture}
\caption{A generic morphological image processing chain.}
@@ -813,7 +809,7 @@
\fixme{More.}
% --------------------------------------------------------------------
-\subsubsection{Implementation in Milena}
+\subsection{Implementation in Milena}
\label{sec:apps-impl}
\fixme{Merge this section into the previous one?}
@@ -830,63 +826,38 @@
catchments basins (with the special label `0' for watershed
sites).}:
%
-\fixme{Is the remark on \code{mln\_ch\_value} too much? We could use
- an abstract type \code{output} for \code{wst} and mask this
- detail.}%
+\fixme{Is the remark on \code{mln\_ch\_value} too much? If not,
+ explain \code{mln\_concrete} as well.}%
%
-%% Actual Milena code is admittedly different. We should converge
-%% toward a unique implementation.
-\begin{lstlisting}[%
+\lstinputlisting[%
mathescape,
% Identifiers.
emph={[1]c,s,ima,nbh,lambda,nbasins},%
emphstyle={[1]\color{darkgreen}\bfseries},%
% More types.
- morekeywords={[2]image}]
- // Compute $G$.
- image g = gradient(ima, nbh);
- // Compute $C$.
- image c = attribute_closing<alpha>(g, nbh, lambda);
- // Holds the number of basins (to be computed by the Watershed Transform).
- unsigned int nbasins;
- // Compute $S$.
- mln_ch_value(image, unsigned int) s = wst(c, nbh, nbasins);
-\end{lstlisting}
+ morekeywords={[2]I,N,L}]{apps/chain.lst}
-\fixme{The \code{gradient} algorithm might be different according to
- the application.}
-\fixme{Even if this chain is generic, working on edges requires a
- slightly different code!}
-
-\subsubsection{Regular 2-Dimensional Image}
-\label{sec:apps-image2d}
-
-In the classical regular 2-D image, $\Dom$ is a subset of $\Z$ and is
-expressed as a 2-D bounding box. Therefore, the notion of
-neighborhood does not depend on the site, and neighbors can be
-expressed as a set of vectors. For instance a 4-connectivity
-neighborhood is the set of 2-D vectors $\{(-1, 0), (0, -1), (0, 1), (1,
- 0) \}$. In Milena, such vectors are called \emph{delta-points},
-since they encode a difference between two sites. \fixme{Careful: point
- vs. site (?)}
-
-\fixme{Continue.}
-
-\subsubsection{Graph-Based Image}
-\label{sec:apps-graph}
-
-\subsubsection{Simplicial Complex-Based Image}
-\label{sec:apps-complex}
-
\begin{figure}
\centering
\subfigure[Regular 2-Dimensional Image]{
- \includegraphics[width=0.45\textwidth]{apps/lena}
+ \includegraphics[width=0.30\textwidth]{apps/lena}
\label{fig:chain-images:lena}
}
+ % FIXME: Improve dependencies in Makefile.
+ % * apps/lena-g.pgm (and then apps/lena-g.png) was generated as a
+ % side effect of apps/image2d with:
+ % make apps/lena-s.png
+ \subfigure[Morphological gradient image of
+ \ref{fig:chain-images:lena}]{
+ \includegraphics[width=0.30\textwidth]{apps/lena-g}
+ \label{fig:chain-images:lena-g}
+ }
+ % * apps/lena-s.png (and then apps/lena-s.png) was generated using
+ % apps/image2d with:
+ % make apps/lena-s.png
\subfigure[Result of the image processing chain on
- \ref{fig:chain-images:lena}]{
- \includegraphics[width=0.45\textwidth]{apps/lena-s}
+ \ref{fig:chain-images:lena-g}]{
+ \includegraphics[width=0.30\textwidth]{apps/lena-s}
\label{fig:chain-images:lena-s}
}
@@ -915,23 +886,90 @@
%% \label{fig:chain-images:m272-pinv-curv-s}
%% }
- \subfigure[FIXME: Caption.]{
- \fbox{\includegraphics[width=0.45\textwidth]{apps/m283}}
+ \subfigure[Graph-Based Image]{
+ \fbox{\includegraphics[width=0.29\textwidth]{apps/graph}}
+ \label{fig:chain-images:graph}
}
- \subfigure[FIXME: Caption.]{
- \fbox{\includegraphics[width=0.45\textwidth]{apps/m283-s}}
+ % FIXME: Improve dependencies in Makefile.
+ % * apps/graph-g.neato (and then apps/graph-g.pdf) was generated as
+ % a side effect of apps/graph with:
+ % make apps/graph-s.neato
+ \subfigure[Morphological gradient of \ref{fig:chain-images:graph}]{
+ \fbox{\includegraphics[width=0.29\textwidth]{apps/graph-g}}
+ \label{fig:chain-images:graph-g}
}
+ % * apps/graph-s.png (and then apps/graph-s.png) was generated using
+ % apps/graph with:
+ % make apps/graph-s.png
+ \subfigure[Result of the image processing chain on
+ \ref{fig:chain-images:graph-g}]{
+ \fbox{\includegraphics[width=0.29\textwidth]{apps/graph-s}}
+ \label{fig:chain-images:graph-s}
+ }
+ \subfigure[Simplicial Complex-Based Image]{
+ \fbox{\includegraphics[width=0.29\textwidth]{apps/new/m283}}
+ \label{fig:chain-images:new-m283}
+ }
+ % FIXME: Turn this into a Make rule (and break the dependency with
+ % milena/apps/statues).
+ % * new/m283-c.off was generated with the (Trimesh-based) command:
+ % milena/apps/statues/mesh-max-curv m283.off new/m283-c.off
+ \subfigure[Maximum surface curvature computed on
+ \ref{fig:chain-images:new-m283}]{
+ \fbox{\includegraphics[width=0.29\textwidth]{apps/new/m283-c}}
+ \label{fig:chain-images:new-m283-c}
+ }
+ % FIXME: Turn this into a Make rule (and break the dependency with
+ % milena/apps/statues).
+ % * new/m283-s.off generated with the command:
+ % milena/apps/statues/mesh-complex-segm new/m283-c.off 200 new/m283-s.off
+ \subfigure[Result of the image processing chain on a gradient image
+ computed on the edges of \ref{fig:chain-images:new-m283-c}]{
+ \fbox{\includegraphics[width=0.29\textwidth]{apps/new/m283-s}}
+ \label{fig:chain-images:new-m283-s}
+ }
+
\caption{Results of the image processing chain from
\autoref{fig:chain-diagram} applied to various inputs.}
\label{fig:chain-images}
\end{figure}
-\fixme{Careful, \file{apps/m283-s.png} has been generated using
- \file{apps/statues/mesh-complex-max-curv-segm.cc} from Milena.}
+% FIXME: Remove these subsections' titles?
+% --------------------------------------------------------------------
+\subsection{Regular 2-Dimensional Image}
+\label{sec:apps-image2d}
+In the classical regular 2-D image, $\Dom$ is a subset of $\Z$ and is
+expressed as a 2-D bounding box. Therefore, the notion of
+neighborhood does not depend on the site, and neighbors can be
+expressed as a set of vectors. For instance a 4-connectivity
+neighborhood is the set of 2-D vectors $\{(-1, 0), (0, -1), (0, 1), (1,
+ 0) \}$. In Milena, such vectors are called \emph{delta-points},
+since they encode a difference between two sites. \fixme{Careful: point
+ vs. site (?)}
+
+\fixme{Continue.}
+
+% --------------------------------------------------------------------
+\subsection{Graph-Based Image}
+\label{sec:apps-graph}
+
+% --------------------------------------------------------------------
+\subsection{Simplicial Complex-Based Image}
+\label{sec:apps-complex}
+
+\fixme[inline]{Explain what a max curvature is.}
+\fixme[inline]{Explain why the gradient image is not depicted.}
+
+\cite{alcoverro.08.3dtv}
+
+% --------------------------------------------------------------------
+\subsection{Other images and possibilities}
+\label{sec:apps-other}
+
\fixme[inline]{Mention other possibilities: color image + gradient as
- distance in a color space, etc.}
+ distance in a color space, gradient on edges etc.}
% ====================================================================
@@ -962,8 +1000,6 @@
\cite{duret.00.gcse} (?)
% Other libraries.
\cite{yoo.04.book}
- % Applications.
- \cite{alcoverro.08.3dtv}
}
Index: apps/m283.gcl
===================================================================
--- apps/m283.gcl (revision 3417)
+++ apps/m283.gcl (revision 3418)
@@ -1,10 +0,0 @@
-(load apps/m283.off geometry)
-# `g1' is the first loaded (and sole) object.
-(bbox-draw g1 no)
-# `c0' is the initial camera.
-(backcolor c0 1 1 1)
-# `g0' is ``the World''. Rotation is expressed in radians around each axis.
-(transform g0 g0 focus rotate 0.0 2.3 0.0)
-(zoom c0 1.5)
-(snapshot c0 apps/m283.ppm)
-(quit)
Index: apps/m283-s.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: apps/m283.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: apps/chain.hh
===================================================================
--- apps/chain.hh (revision 3417)
+++ apps/chain.hh (revision 3418)
@@ -1,35 +1,18 @@
-#include <mln/morpho/gradient.hh>
-#include <mln/morpho/closing_area.hh>
-#include <mln/morpho/meyer_wst.hh>
-
#ifndef CHAIN_HH
# define CHAIN_HH
-template <typename I, typename N, typename W, typename L>
+#include <mln/morpho/closing_area.hh>
+#include <mln/morpho/meyer_wst.hh>
+
+template <typename I, typename N, typename L>
mln_ch_value(I, L)
chain(const mln::Image<I>& ima, const mln::Neighborhood<N>& nbh,
- const mln::Window<W>& win, unsigned lambda, L& nbasins)
+ unsigned lambda, L& nbasins)
{
using namespace mln;
-
- /* FIXME: Unfortunately, we cannot write
-
- morpho::gradient(ima, win)
-
- here, since MM only uses windows (yet?), not neighborhoods. And
- we cannot either write
-
- morpho::gradient(ima, nbh.win()),
-
- since that window would not contain the center site...
- Therefore, this function asks for a window WIN matching the
- neighborhood NBH, plus the center site.
-
- A neighborhood `n' should provide a method `win_p()' returning a
- window corresponding to `n' plus the center site. */
- mln_concrete(I) g = morpho::gradient(ima, win);
// FIXME: alpha (the criterion) is not changeable here! Change this.
- mln_concrete(I) c = morpho::closing_area(g, nbh, lambda);
+ mln_concrete(I) c = morpho::closing_area(ima, nbh, lambda);
+ // FIXME: Use morpho::watershed::flooding instead?
mln_ch_value(I, L) s = morpho::meyer_wst(c, nbh, nbasins);
return s;
}
Index: apps/chain.lst
===================================================================
--- apps/chain.lst (revision 0)
+++ apps/chain.lst (revision 3418)
@@ -0,0 +1,8 @@
+template <typename I, typename N, typename L>
+mln_ch_value(I, L)
+chain(const I& ima, const N& nbh, unsigned lambda, L& nbasins)
+{
+ mln_concrete(I) c = morpho::closing_area(ima, nbh, lambda); // Compute $C$.
+ mln_ch_value(I, L) s = morpho::wst(c, nbh, nbasins); // Compute $S$.
+ return s;
+}
Index: apps/lena-g.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: apps/lena-g.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: apps/complex.cc
===================================================================
--- apps/complex.cc (revision 3417)
+++ apps/complex.cc (revision 3418)
@@ -47,6 +47,11 @@
down. */
input ima;
io::off::load(ima, input_filename);
- output s = chain(ima, nbh, win, lambda, nbasins);
+
+ // FIXME: gradient_on_edges is not implemented; extract it from
+ // apps/statues/mesh-complex-max-curv-segm.cc.
+
+ input g = morpho::gradient_on_edges(ima, win);
+ output s = chain(ima, nbh, lambda, nbasins);
io::off::save(debug::colorize(value::rgb8(), s, nbasins), output_filename);
}
Index: apps/image2d.cc
===================================================================
--- apps/image2d.cc (revision 3417)
+++ apps/image2d.cc (revision 3418)
@@ -9,7 +9,10 @@
#include <mln/value/int_u8.hh>
#include <mln/value/label_8.hh>
+#include <mln/morpho/gradient.hh>
+
#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
#include <mln/io/ppm/save.hh>
#include <mln/debug/colorize.hh>
@@ -43,6 +46,28 @@
// Load, process, save.
input ima = io::pgm::load<val>(input_filename);
- output s = chain(ima, nbh, win, lambda, nbasins);
+ // Gradient.
+ /* FIXME: Unfortunately, we cannot write
+
+ morpho::gradient(ima, win)
+
+ here, since MM only uses windows (yet?), not neighborhoods. And
+ we cannot either write
+
+ morpho::gradient(ima, nbh.win()),
+
+ since that window would not contain the center site...
+ Therefore, this function asks for a window WIN matching the
+ neighborhood NBH, plus the center site.
+
+ A neighborhood `n' should provide a method `win_p()' returning a
+ window corresponding to `n' plus the center site. */
+ input g = morpho::gradient(ima, win);
+
+ // FIXME: get the name as argument.
+ io::pgm::save(g, "apps/lena-g.pgm");
+
+ // Chain.
+ output s = chain(g, nbh, lambda, nbasins);
io::ppm::save(debug::colorize(value::rgb8(), s, nbasins), output_filename);
}
Index: apps/graph.cc
===================================================================
--- apps/graph.cc (revision 0)
+++ apps/graph.cc (revision 3418)
@@ -0,0 +1,495 @@
+// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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 <iostream>
+#include <iomanip>
+
+#include <vector>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/routine/duplicate.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
+#include <mln/labeling/blobs.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/debug/println.hh>
+#include <mln/draw/line.hh>
+#include <mln/pw/all.hh>
+#include <mln/binarization/threshold.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/core/alias/point2d.hh>
+
+#include <mln/core/site_set/p_faces.hh>
+#include <mln/core/image/complex_image.hh>
+#include <mln/core/alias/complex_geometry.hh>
+#include <mln/core/alias/complex_image.hh>
+
+// FIXME: Include these elsewhere? (In complex_image.hh?)
+#include <mln/core/image/complex_neighborhoods.hh>
+#include <mln/core/image/complex_neighborhood_piter.hh>
+#include <mln/core/image/complex_windows.hh>
+
+#include <mln/data/fill.hh>
+#include <mln/morpho/gradient.hh>
+#include <mln/debug/colorize.hh>
+
+#include "chain.hh"
+
+
+// FIXME: Copied and adjusted from pics/graph.cc; factor.
+
+namespace mln
+{
+
+ template <typename I, typename N>
+ mln_concrete(I)
+ influence_zones(const I& input, const N& nbh)
+ {
+ mln_concrete(I) output = duplicate(input);
+
+ p_queue_fast<mln_site(I)> q;
+
+ {
+ // Initialization.
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ if (input(p) != 0)
+ for_all(n) if (input.has(n))
+ if (input(n) == 0)
+ {
+ q.push(p);
+ break;
+ }
+ }
+ {
+ // Body.
+ mln_site(I) p;
+ mln_niter(N) n(nbh, p);
+ while (! q.is_empty())
+ {
+ p = q.pop_front();
+ mln_invariant(output(p) != 0);
+ for_all(n) if (input.has(n))
+ if (output(n) == 0)
+ {
+ output(n) = output(p);
+ q.push(n);
+ }
+ }
+ }
+
+ return output;
+
+ }
+
+
+ namespace io
+ {
+
+ namespace neato
+ {
+
+ /* FIXME: This is just the gray-level version. Handle other value
+ types as well. */
+ void
+ save(const complex_image<1, discrete_plane_1complex_geometry,
+ value::int_u8>& ima,
+ const std::string& filename,
+ const std::string& bgcolor = "#0000C0",
+ const std::string& fontcolor = "#0000C0",
+ bool empty_vertex_label = true)
+ {
+ typedef value::int_u8 V;
+ typedef complex_image<1, discrete_plane_1complex_geometry, V> I;
+ const unsigned D = 1;
+ typedef discrete_plane_1complex_geometry G;
+
+ std::ofstream g(filename.c_str());
+ g << "graph wst" << std::endl
+ << "{" << std::endl
+ << " graph [bgcolor = \"" << bgcolor << "\"]" << std::endl
+ << " edge [color = \"#FFFFFF\"]" << std::endl
+ << " node [color = \"#FFFFFF\", height=\"5\", width=\"5\","
+ << " fontsize=\"100\", fontcolor = \"" << fontcolor << "\"]"
+ << std::endl;
+
+ // Vertices.
+ p_n_faces_fwd_piter<D, G> v(ima.domain(), 0);
+ typedef complex_higher_neighborhood<D, G> e_nbh_t;
+ e_nbh_t e_nbh;
+ for_all(v)
+ {
+ V vertex_color = ima(v);
+ std::ostringstream vertex_color_str;
+ // FIXME: Only valid for gray-level images.
+ vertex_color_str << '#'
+ << std::hex
+ << std::setfill('0')
+ << std::setw(2) << vertex_color
+ << std::setw(2) << vertex_color
+ << std::setw(2) << vertex_color
+ << std::dec;
+
+ g << " v" << v.unproxy_().face_id()
+ << " [pos = \""
+ << std::fixed << std::setprecision(1)
+ << (float)v.to_site().front()[1] << ", "
+ << -(float)v.to_site().front()[0]
+ << "\", color = \"" << vertex_color_str.str()
+ << "\", fillcolor = \"" << vertex_color_str.str()
+ << "\", pin = \"true\", style=\"filled,setlinewidth(3)\"";
+ if (empty_vertex_label)
+ g << ", label = \"\"";
+ g << "];"
+ << std::endl;
+ }
+
+ // Edges.
+ p_n_faces_fwd_piter<D, G> e(ima.domain(), 1);
+ typedef complex_lower_neighborhood<D, G> v_nbh_t;
+ v_nbh_t v_nbh;
+ mln_niter_(v_nbh_t) adj_v(v_nbh, e);
+ for_all(e)
+ {
+ V edge_color = ima(e);
+ std::ostringstream edge_color_str;
+ edge_color_str << '#'
+ << std::hex
+ << std::setfill('0')
+ << std::setw(2) << edge_color
+ << std::setw(2) << edge_color
+ << std::setw(2) << edge_color
+ << std::dec;
+
+ // Adjacent vertices.
+ adj_v.start();
+ topo::face<1> v1 = adj_v.unproxy_().face();
+ point2d p1 = adj_v.to_site().front();
+ adj_v.next();
+ topo::face<1> v2 = adj_v.unproxy_().face();
+ point2d p2 = adj_v.to_site().front();
+ adj_v.next();
+ mln_invariant(!adj_v.is_valid());
+
+ g << " v" << v1.face_id() << " -- v" << v2.face_id() << " ";
+ g << "[color = \"" << edge_color_str.str()
+ << "\", style=\"setlinewidth(10)\"];" << std::endl;
+ }
+
+ g << "}" << std::endl;
+ g.close();
+ }
+
+ // FIXME: Factor with the previous version.
+ void
+ save(const complex_image<1, discrete_plane_1complex_geometry,
+ value::rgb8>& ima,
+ const std::string& filename,
+ const std::string& bgcolor = "#0000C0",
+ const std::string& fontcolor = "#0000C0",
+ bool empty_vertex_label = true)
+ {
+ typedef value::rgb8 V;
+ typedef complex_image<1, discrete_plane_1complex_geometry, V> I;
+ const unsigned D = 1;
+ typedef discrete_plane_1complex_geometry G;
+
+ std::ofstream g(filename.c_str());
+ g << "graph wst" << std::endl
+ << "{" << std::endl
+ << " graph [bgcolor = \"" << bgcolor << "\"]" << std::endl
+ << " edge [color = \"#FFFFFF\"]" << std::endl
+ << " node [color = \"#FFFFFF\", height=\"5\", width=\"5\","
+ << " fontsize=\"100\", fontcolor = \"" << fontcolor << "\"]"
+ << std::endl;
+
+ // Vertices.
+ p_n_faces_fwd_piter<D, G> v(ima.domain(), 0);
+ typedef complex_higher_neighborhood<D, G> e_nbh_t;
+ e_nbh_t e_nbh;
+ for_all(v)
+ {
+ V vertex_color = ima(v);
+ std::ostringstream vertex_color_str;
+ // FIXME: Only valid for gray-level images.
+ vertex_color_str << '#'
+ << std::hex
+ << std::setfill('0')
+ << std::setw(2) << vertex_color.red()
+ << std::setw(2) << vertex_color.green()
+ << std::setw(2) << vertex_color.blue()
+ << std::dec;
+
+ g << " v" << v.unproxy_().face_id()
+ << " [pos = \""
+ << std::fixed << std::setprecision(1)
+ << (float)v.to_site().front()[1] << ", "
+ << -(float)v.to_site().front()[0]
+ << "\", color = \"" << vertex_color_str.str()
+ << "\", fillcolor = \"" << vertex_color_str.str()
+ << "\", pin = \"true\", style=\"filled,setlinewidth(3)\"";
+ if (empty_vertex_label)
+ g << ", label = \"\"";
+ g << "];"
+ << std::endl;
+ }
+
+ // Edges.
+ p_n_faces_fwd_piter<D, G> e(ima.domain(), 1);
+ typedef complex_lower_neighborhood<D, G> v_nbh_t;
+ v_nbh_t v_nbh;
+ mln_niter_(v_nbh_t) adj_v(v_nbh, e);
+ for_all(e)
+ {
+ V edge_color = ima(e);
+ std::ostringstream edge_color_str;
+ edge_color_str << '#'
+ << std::hex
+ << std::setfill('0')
+ << std::setw(2) << edge_color.red()
+ << std::setw(2) << edge_color.green()
+ << std::setw(2) << edge_color.blue()
+ << std::dec;
+
+ // Adjacent vertices.
+ adj_v.start();
+ topo::face<1> v1 = adj_v.unproxy_().face();
+ point2d p1 = adj_v.to_site().front();
+ adj_v.next();
+ topo::face<1> v2 = adj_v.unproxy_().face();
+ point2d p2 = adj_v.to_site().front();
+ adj_v.next();
+ mln_invariant(!adj_v.is_valid());
+
+ g << " v" << v1.face_id() << " -- v" << v2.face_id() << " ";
+ g << "[color = \"" << edge_color_str.str()
+ << "\", style=\"setlinewidth(10)\"];" << std::endl;
+ }
+
+ g << "}" << std::endl;
+ g.close();
+ }
+
+ } // end of namespace mln::io::neato
+
+ } // end of namespace mln::io
+
+} // end of namespace mln
+
+
+// FIXME: Clean up and move into Milena?
+mln::int_u8_1complex_image2d
+make_complex_image(const mln::image2d<mln::value::int_u8>& input)
+{
+ using namespace mln;
+ using mln::value::int_u8;
+
+ /*----------------------------------------.
+ | Complex + complex geometry (location). |
+ `----------------------------------------*/
+
+ border::thickness = 0;
+
+ unsigned nlabels;
+ image2d<unsigned> label =
+ labeling::blobs(mln::binarization::threshold(input, 1), c4(), nlabels);
+
+ std::cout << "n seeds = " << nlabels << std::endl;
+ {
+ image2d<int_u8> lab(label.domain());
+ data::paste(label, lab);
+ }
+
+ image2d<unsigned> iz = influence_zones(label, c4());
+ {
+ image2d<int_u8> IZ(iz.domain());
+ data::paste(iz, IZ);
+ }
+
+
+ // Make graph/complex.
+
+ std::vector< std::vector<bool> > adj(nlabels + 1);
+ for (unsigned l = 1; l <= nlabels; ++l)
+ adj[l].resize(nlabels + 1, false);
+
+ {
+ box2d::piter p(iz.domain());
+ for_all(p)
+ {
+ point2d r = p + right, b = p + down;
+ if (iz.has(r) && iz(p) != iz(r))
+ {
+ if (iz(p) <= iz(r))
+ adj[iz(p)][iz(r)] = true;
+ else
+ adj[iz(r)][iz(p)] = true;
+ }
+ if (iz.has(b) && iz(p) != iz(b))
+ {
+ if (iz(p) <= iz(b))
+ adj[iz(p)][iz(b)] = true;
+ else
+ adj[iz(b)][iz(p)] = true;
+ }
+ }
+ }
+
+ // end of mk_graph
+
+
+ const unsigned D = 1;
+
+ topo::complex<D> c;
+
+ typedef point2d P;
+ typedef geom::complex_geometry<D, P> G;
+ G geom;
+
+ // Convenience typedefs.
+ typedef topo::n_face<0, D> vertex;
+ typedef topo::n_face<1, D> edge;
+
+ {
+
+ // 0-faces (vertices).
+ std::vector<vertex> v;
+ {
+ box2d::piter p(label.domain());
+ for_all(p)
+ if (label(p) != 0)
+ {
+ geom.add_location(p);
+ v.push_back(c.add_face());
+ }
+ }
+
+ std::cout << "v size = " << v.size() << std::endl;
+
+ // 1-faces (edges).
+ std::vector<edge> e;
+ {
+ for (unsigned l = 1; l <= nlabels; ++l)
+ for (unsigned ll = l + 1; ll <= nlabels; ++ll)
+ if (adj[l][ll])
+ e.push_back( c.add_face(-v[l-1] + v[ll-1]) );
+ }
+
+ std::cout << "e size = " << e.size() << std::endl;
+
+ }
+
+
+ /*---------------------.
+ | Complex-based pset. |
+ `---------------------*/
+
+ p_complex<D, G> pc(c, geom);
+
+ /*----------------------.
+ | Complex-based image. |
+ `----------------------*/
+
+ // An image type built on a 1-complex with unsigned values on each
+ // face (both vertices and edges).
+ typedef complex_image<D, G, int_u8> output_t;
+
+ // Create and initialize an image based on PC.
+ output_t output(pc);
+
+ // Color OUTPUT's vertices with INPUT's values.
+ p_n_faces_fwd_piter<D, G> v(output.domain(), 0);
+ for_all(v)
+ output(v) = input(v.to_site().front());
+
+ // Use a medium gray to color edges.
+ p_n_faces_fwd_piter<D, G> e(output.domain(), 1);
+ for_all(e)
+ output(e) = 128;
+
+ return output;
+}
+
+
+// FIXME: Move to Milena?
+template <unsigned D, typename G, typename V>
+mln::complex_higher_dim_connected_n_face_window_p<D, G>
+make_elt_win(const mln::complex_image<D, G, V>& ima)
+{
+ return mln::complex_higher_dim_connected_n_face_window_p<D, G>();
+}
+
+// FIXME: Move to Milena?
+template <unsigned D, typename G, typename V>
+mln::complex_higher_dim_connected_n_face_neighborhood<D, G>
+make_elt_nbh(const mln::complex_image<D, G, V>& ima)
+{
+ return mln::complex_higher_dim_connected_n_face_neighborhood<D, G>();
+}
+
+
+int main(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ std::cerr << "usage: " << argv[0] << " seeds.pgm lambda output.neato"
+ << std::endl;
+ std::exit(1);
+ }
+ std::string input_filename = argv[1];
+ unsigned lambda = atoi(argv[2]);
+ std::string output_filename = argv[3];
+
+ using namespace mln;
+ using mln::value::int_u8;
+ // Use clearer names.
+ typedef int_u8_1complex_image2d int_u8_graph_image2d;
+
+ typedef int_u8_graph_image2d input;
+ typedef value::label_8 label;
+ typedef mln_ch_value_(input, label) output;
+ label nbasins;
+
+ // Seeds.
+ image2d<int_u8> seeds = io::pgm::load<int_u8>(input_filename);
+ // Input image computed from the graph of influence zones (IZ) of seeds.
+ typedef int_u8_graph_image2d ima_t;
+ ima_t ima = make_complex_image(seeds);
+ io::neato::save(ima, "apps/graph.neato");
+
+ // Gradient.
+ input g = morpho::gradient(ima, make_elt_win(ima));
+
+ // FIXME: get the name as argument.
+ io::neato::save(g, "apps/graph-g.neato");
+
+ // Chain.
+ output s = chain(g, make_elt_nbh(g), lambda, nbasins);
+ io::neato::save(debug::colorize(value::rgb8(), s, nbasins), output_filename);
+}
Index: apps/new/m283-c.gcl
===================================================================
--- apps/new/m283-c.gcl (revision 0)
+++ apps/new/m283-c.gcl (revision 3418)
@@ -0,0 +1,10 @@
+(load apps/new/m283-g.off geometry)
+# `g1' is the first loaded (and sole) object.
+(bbox-draw g1 no)
+# `c0' is the initial camera.
+(backcolor c0 1 1 1)
+# `g0' is ``the World''. Rotation is expressed in radians around each axis.
+(transform g0 g0 focus rotate 0.0 2.3 0.0)
+(zoom c0 1.5)
+(snapshot c0 apps/new/m283-g.ppm)
+(quit)
Property changes on: apps/new/m283-c.gcl
___________________________________________________________________
Added: svn:mergeinfo
Index: apps/new/m283-s.gcl
===================================================================
--- apps/new/m283-s.gcl (revision 0)
+++ apps/new/m283-s.gcl (revision 3418)
@@ -0,0 +1,10 @@
+(load apps/new/m283-s.off geometry)
+# `g1' is the first loaded (and sole) object.
+(bbox-draw g1 no)
+# `c0' is the initial camera.
+(backcolor c0 1 1 1)
+# `g0' is ``the World''. Rotation is expressed in radians around each axis.
+(transform g0 g0 focus rotate 0.0 2.3 0.0)
+(zoom c0 1.5)
+(snapshot c0 apps/new/m283-s.ppm)
+(quit)
Index: apps/new/m283.gcl
===================================================================
--- apps/new/m283.gcl (revision 0)
+++ apps/new/m283.gcl (revision 3418)
@@ -0,0 +1,10 @@
+(load apps/new/m283.off geometry)
+# `g1' is the first loaded (and sole) object.
+(bbox-draw g1 no)
+# `c0' is the initial camera.
+(backcolor c0 1 1 1)
+# `g0' is ``the World''. Rotation is expressed in radians around each axis.
+(transform g0 g0 focus rotate 0.0 2.3 0.0)
+(zoom c0 1.5)
+(snapshot c0 apps/new/m283.ppm)
+(quit)
Property changes on: apps/new/m283.gcl
___________________________________________________________________
Added: svn:mergeinfo
Index: apps/graph-g.neato
===================================================================
--- apps/graph-g.neato (revision 0)
+++ apps/graph-g.neato (revision 3418)
@@ -0,0 +1,67 @@
+graph wst
+{
+ graph [bgcolor = "#0000C0"]
+ edge [color = "#FFFFFF"]
+ node [color = "#FFFFFF", height="5", width="5", fontsize="100", fontcolor = "#0000C0"]
+ v0 [pos = "44.0, -11.0", color = "#878787", fillcolor = "#878787", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v1 [pos = "26.0, -12.0", color = "#c0c0c0", fillcolor = "#c0c0c0", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v2 [pos = "12.0, -15.0", color = "#9f9f9f", fillcolor = "#9f9f9f", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v3 [pos = "56.0, -17.0", color = "#adadad", fillcolor = "#adadad", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v4 [pos = "33.0, -19.0", color = "#eeeeee", fillcolor = "#eeeeee", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v5 [pos = "20.0, -24.0", color = "#cdcdcd", fillcolor = "#cdcdcd", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v6 [pos = "39.0, -24.0", color = "#eeeeee", fillcolor = "#eeeeee", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v7 [pos = "10.0, -28.0", color = "#898989", fillcolor = "#898989", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v8 [pos = "50.0, -31.0", color = "#e3e3e3", fillcolor = "#e3e3e3", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v9 [pos = "32.0, -36.0", color = "#e3e3e3", fillcolor = "#e3e3e3", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v10 [pos = "16.0, -37.0", color = "#a5a5a5", fillcolor = "#a5a5a5", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v11 [pos = "26.0, -41.0", color = "#ededed", fillcolor = "#ededed", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v12 [pos = "43.0, -44.0", color = "#8d8d8d", fillcolor = "#8d8d8d", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v13 [pos = "18.0, -46.0", color = "#838383", fillcolor = "#838383", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v14 [pos = "10.0, -47.0", color = "#606060", fillcolor = "#606060", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v15 [pos = "34.0, -47.0", color = "#ededed", fillcolor = "#ededed", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v16 [pos = "55.0, -48.0", color = "#727272", fillcolor = "#727272", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v17 [pos = "23.0, -54.0", color = "#868686", fillcolor = "#868686", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v18 [pos = "45.0, -57.0", color = "#727272", fillcolor = "#727272", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v0 -- v1 [color = "#000000", style="setlinewidth(10)"];
+ v0 -- v3 [color = "#000000", style="setlinewidth(10)"];
+ v0 -- v4 [color = "#000000", style="setlinewidth(10)"];
+ v0 -- v6 [color = "#000000", style="setlinewidth(10)"];
+ v1 -- v2 [color = "#000000", style="setlinewidth(10)"];
+ v1 -- v4 [color = "#000000", style="setlinewidth(10)"];
+ v1 -- v5 [color = "#000000", style="setlinewidth(10)"];
+ v2 -- v5 [color = "#000000", style="setlinewidth(10)"];
+ v2 -- v7 [color = "#000000", style="setlinewidth(10)"];
+ v3 -- v6 [color = "#000000", style="setlinewidth(10)"];
+ v3 -- v8 [color = "#000000", style="setlinewidth(10)"];
+ v4 -- v5 [color = "#000000", style="setlinewidth(10)"];
+ v4 -- v6 [color = "#000000", style="setlinewidth(10)"];
+ v4 -- v9 [color = "#000000", style="setlinewidth(10)"];
+ v5 -- v7 [color = "#000000", style="setlinewidth(10)"];
+ v5 -- v9 [color = "#000000", style="setlinewidth(10)"];
+ v5 -- v10 [color = "#000000", style="setlinewidth(10)"];
+ v5 -- v11 [color = "#000000", style="setlinewidth(10)"];
+ v6 -- v8 [color = "#000000", style="setlinewidth(10)"];
+ v6 -- v9 [color = "#000000", style="setlinewidth(10)"];
+ v7 -- v10 [color = "#000000", style="setlinewidth(10)"];
+ v8 -- v9 [color = "#000000", style="setlinewidth(10)"];
+ v8 -- v12 [color = "#000000", style="setlinewidth(10)"];
+ v8 -- v16 [color = "#000000", style="setlinewidth(10)"];
+ v9 -- v11 [color = "#000000", style="setlinewidth(10)"];
+ v9 -- v12 [color = "#000000", style="setlinewidth(10)"];
+ v9 -- v15 [color = "#000000", style="setlinewidth(10)"];
+ v10 -- v11 [color = "#000000", style="setlinewidth(10)"];
+ v10 -- v13 [color = "#000000", style="setlinewidth(10)"];
+ v10 -- v14 [color = "#000000", style="setlinewidth(10)"];
+ v11 -- v13 [color = "#000000", style="setlinewidth(10)"];
+ v11 -- v15 [color = "#000000", style="setlinewidth(10)"];
+ v11 -- v17 [color = "#000000", style="setlinewidth(10)"];
+ v12 -- v15 [color = "#000000", style="setlinewidth(10)"];
+ v12 -- v16 [color = "#000000", style="setlinewidth(10)"];
+ v12 -- v18 [color = "#000000", style="setlinewidth(10)"];
+ v13 -- v14 [color = "#000000", style="setlinewidth(10)"];
+ v13 -- v17 [color = "#000000", style="setlinewidth(10)"];
+ v14 -- v17 [color = "#000000", style="setlinewidth(10)"];
+ v15 -- v17 [color = "#000000", style="setlinewidth(10)"];
+ v15 -- v18 [color = "#000000", style="setlinewidth(10)"];
+ v16 -- v18 [color = "#000000", style="setlinewidth(10)"];
+}
Index: apps/graph-g.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: apps/graph-g.pdf
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: apps/graph-s.neato
===================================================================
--- apps/graph-s.neato (revision 0)
+++ apps/graph-s.neato (revision 3418)
@@ -0,0 +1,67 @@
+graph wst
+{
+ graph [bgcolor = "#0000C0"]
+ edge [color = "#FFFFFF"]
+ node [color = "#FFFFFF", height="5", width="5", fontsize="100", fontcolor = "#0000C0"]
+ v0 [pos = "44.0, -11.0", color = "#356d6b", fillcolor = "#356d6b", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v1 [pos = "26.0, -12.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v2 [pos = "12.0, -15.0", color = "#e8329e", fillcolor = "#e8329e", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v3 [pos = "56.0, -17.0", color = "#356d6b", fillcolor = "#356d6b", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v4 [pos = "33.0, -19.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v5 [pos = "20.0, -24.0", color = "#e8329e", fillcolor = "#e8329e", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v6 [pos = "39.0, -24.0", color = "#356d6b", fillcolor = "#356d6b", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v7 [pos = "10.0, -28.0", color = "#e8329e", fillcolor = "#e8329e", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v8 [pos = "50.0, -31.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v9 [pos = "32.0, -36.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v10 [pos = "16.0, -37.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v11 [pos = "26.0, -41.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v12 [pos = "43.0, -44.0", color = "#7db4bd", fillcolor = "#7db4bd", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v13 [pos = "18.0, -46.0", color = "#b7da2c", fillcolor = "#b7da2c", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v14 [pos = "10.0, -47.0", color = "#b7da2c", fillcolor = "#b7da2c", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v15 [pos = "34.0, -47.0", color = "#000000", fillcolor = "#000000", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v16 [pos = "55.0, -48.0", color = "#7db4bd", fillcolor = "#7db4bd", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v17 [pos = "23.0, -54.0", color = "#b7da2c", fillcolor = "#b7da2c", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v18 [pos = "45.0, -57.0", color = "#7db4bd", fillcolor = "#7db4bd", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v0 -- v1 [color = "#5cc33d", style="setlinewidth(10)"];
+ v0 -- v3 [color = "#e38416", style="setlinewidth(10)"];
+ v0 -- v4 [color = "#7d7a52", style="setlinewidth(10)"];
+ v0 -- v6 [color = "#56bed5", style="setlinewidth(10)"];
+ v1 -- v2 [color = "#6c4b6c", style="setlinewidth(10)"];
+ v1 -- v4 [color = "#ea6114", style="setlinewidth(10)"];
+ v1 -- v5 [color = "#48bc27", style="setlinewidth(10)"];
+ v2 -- v5 [color = "#164eaf", style="setlinewidth(10)"];
+ v2 -- v7 [color = "#4b691f", style="setlinewidth(10)"];
+ v3 -- v6 [color = "#bda486", style="setlinewidth(10)"];
+ v3 -- v8 [color = "#4d75ee", style="setlinewidth(10)"];
+ v4 -- v5 [color = "#39581f", style="setlinewidth(10)"];
+ v4 -- v6 [color = "#c58d18", style="setlinewidth(10)"];
+ v4 -- v9 [color = "#c6c59c", style="setlinewidth(10)"];
+ v5 -- v7 [color = "#baac2a", style="setlinewidth(10)"];
+ v5 -- v9 [color = "#6917a8", style="setlinewidth(10)"];
+ v5 -- v10 [color = "#768368", style="setlinewidth(10)"];
+ v5 -- v11 [color = "#7d7375", style="setlinewidth(10)"];
+ v6 -- v8 [color = "#6545ae", style="setlinewidth(10)"];
+ v6 -- v9 [color = "#376d19", style="setlinewidth(10)"];
+ v7 -- v10 [color = "#4c8f22", style="setlinewidth(10)"];
+ v8 -- v9 [color = "#91719b", style="setlinewidth(10)"];
+ v8 -- v12 [color = "#a1c621", style="setlinewidth(10)"];
+ v8 -- v16 [color = "#1c1c89", style="setlinewidth(10)"];
+ v9 -- v11 [color = "#5d29cc", style="setlinewidth(10)"];
+ v9 -- v12 [color = "#45e28e", style="setlinewidth(10)"];
+ v9 -- v15 [color = "#df5ab0", style="setlinewidth(10)"];
+ v10 -- v11 [color = "#e0e66c", style="setlinewidth(10)"];
+ v10 -- v13 [color = "#401ce9", style="setlinewidth(10)"];
+ v10 -- v14 [color = "#51edd6", style="setlinewidth(10)"];
+ v11 -- v13 [color = "#4744e1", style="setlinewidth(10)"];
+ v11 -- v15 [color = "#554c49", style="setlinewidth(10)"];
+ v11 -- v17 [color = "#981b79", style="setlinewidth(10)"];
+ v12 -- v15 [color = "#9f9527", style="setlinewidth(10)"];
+ v12 -- v16 [color = "#4946cf", style="setlinewidth(10)"];
+ v12 -- v18 [color = "#9892ed", style="setlinewidth(10)"];
+ v13 -- v14 [color = "#4b243a", style="setlinewidth(10)"];
+ v13 -- v17 [color = "#db49c8", style="setlinewidth(10)"];
+ v14 -- v17 [color = "#c56d31", style="setlinewidth(10)"];
+ v15 -- v17 [color = "#677028", style="setlinewidth(10)"];
+ v15 -- v18 [color = "#4557cb", style="setlinewidth(10)"];
+ v16 -- v18 [color = "#7f6634", style="setlinewidth(10)"];
+}
Index: apps/graph.neato
===================================================================
--- apps/graph.neato (revision 0)
+++ apps/graph.neato (revision 3418)
@@ -0,0 +1,67 @@
+graph wst
+{
+ graph [bgcolor = "#0000C0"]
+ edge [color = "#FFFFFF"]
+ node [color = "#FFFFFF", height="5", width="5", fontsize="100", fontcolor = "#0000C0"]
+ v0 [pos = "44.0, -11.0", color = "#010101", fillcolor = "#010101", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v1 [pos = "26.0, -12.0", color = "#222222", fillcolor = "#222222", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v2 [pos = "12.0, -15.0", color = "#c1c1c1", fillcolor = "#c1c1c1", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v3 [pos = "56.0, -17.0", color = "#757575", fillcolor = "#757575", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v4 [pos = "33.0, -19.0", color = "#888888", fillcolor = "#888888", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v5 [pos = "20.0, -24.0", color = "#383838", fillcolor = "#383838", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v6 [pos = "39.0, -24.0", color = "#0c0c0c", fillcolor = "#0c0c0c", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v7 [pos = "10.0, -28.0", color = "#aeaeae", fillcolor = "#aeaeae", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v8 [pos = "50.0, -31.0", color = "#aeaeae", fillcolor = "#aeaeae", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v9 [pos = "32.0, -36.0", color = "#efefef", fillcolor = "#efefef", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v10 [pos = "16.0, -37.0", color = "#626262", fillcolor = "#626262", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v11 [pos = "26.0, -41.0", color = "#858585", fillcolor = "#858585", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v12 [pos = "43.0, -44.0", color = "#d4d4d4", fillcolor = "#d4d4d4", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v13 [pos = "18.0, -46.0", color = "#090909", fillcolor = "#090909", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v14 [pos = "10.0, -47.0", color = "#0e0e0e", fillcolor = "#0e0e0e", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v15 [pos = "34.0, -47.0", color = "#888888", fillcolor = "#888888", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v16 [pos = "55.0, -48.0", color = "#acacac", fillcolor = "#acacac", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v17 [pos = "23.0, -54.0", color = "#020202", fillcolor = "#020202", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v18 [pos = "45.0, -57.0", color = "#626262", fillcolor = "#626262", pin = "true", style="filled,setlinewidth(3)", label = ""];
+ v0 -- v1 [color = "#808080", style="setlinewidth(10)"];
+ v0 -- v3 [color = "#808080", style="setlinewidth(10)"];
+ v0 -- v4 [color = "#808080", style="setlinewidth(10)"];
+ v0 -- v6 [color = "#808080", style="setlinewidth(10)"];
+ v1 -- v2 [color = "#808080", style="setlinewidth(10)"];
+ v1 -- v4 [color = "#808080", style="setlinewidth(10)"];
+ v1 -- v5 [color = "#808080", style="setlinewidth(10)"];
+ v2 -- v5 [color = "#808080", style="setlinewidth(10)"];
+ v2 -- v7 [color = "#808080", style="setlinewidth(10)"];
+ v3 -- v6 [color = "#808080", style="setlinewidth(10)"];
+ v3 -- v8 [color = "#808080", style="setlinewidth(10)"];
+ v4 -- v5 [color = "#808080", style="setlinewidth(10)"];
+ v4 -- v6 [color = "#808080", style="setlinewidth(10)"];
+ v4 -- v9 [color = "#808080", style="setlinewidth(10)"];
+ v5 -- v7 [color = "#808080", style="setlinewidth(10)"];
+ v5 -- v9 [color = "#808080", style="setlinewidth(10)"];
+ v5 -- v10 [color = "#808080", style="setlinewidth(10)"];
+ v5 -- v11 [color = "#808080", style="setlinewidth(10)"];
+ v6 -- v8 [color = "#808080", style="setlinewidth(10)"];
+ v6 -- v9 [color = "#808080", style="setlinewidth(10)"];
+ v7 -- v10 [color = "#808080", style="setlinewidth(10)"];
+ v8 -- v9 [color = "#808080", style="setlinewidth(10)"];
+ v8 -- v12 [color = "#808080", style="setlinewidth(10)"];
+ v8 -- v16 [color = "#808080", style="setlinewidth(10)"];
+ v9 -- v11 [color = "#808080", style="setlinewidth(10)"];
+ v9 -- v12 [color = "#808080", style="setlinewidth(10)"];
+ v9 -- v15 [color = "#808080", style="setlinewidth(10)"];
+ v10 -- v11 [color = "#808080", style="setlinewidth(10)"];
+ v10 -- v13 [color = "#808080", style="setlinewidth(10)"];
+ v10 -- v14 [color = "#808080", style="setlinewidth(10)"];
+ v11 -- v13 [color = "#808080", style="setlinewidth(10)"];
+ v11 -- v15 [color = "#808080", style="setlinewidth(10)"];
+ v11 -- v17 [color = "#808080", style="setlinewidth(10)"];
+ v12 -- v15 [color = "#808080", style="setlinewidth(10)"];
+ v12 -- v16 [color = "#808080", style="setlinewidth(10)"];
+ v12 -- v18 [color = "#808080", style="setlinewidth(10)"];
+ v13 -- v14 [color = "#808080", style="setlinewidth(10)"];
+ v13 -- v17 [color = "#808080", style="setlinewidth(10)"];
+ v14 -- v17 [color = "#808080", style="setlinewidth(10)"];
+ v15 -- v17 [color = "#808080", style="setlinewidth(10)"];
+ v15 -- v18 [color = "#808080", style="setlinewidth(10)"];
+ v16 -- v18 [color = "#808080", style="setlinewidth(10)"];
+}
Index: apps/graph-s.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: apps/graph-s.pdf
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: apps/graph.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: apps/graph.pdf
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: apps/old/m283-s.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: apps/old/m283-s.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: svn:mergeinfo
Index: apps/old/m283.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: apps/old/m283.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: svn:mergeinfo
Index: apps/old/m283.gcl
===================================================================
--- apps/old/m283.gcl (revision 0)
+++ apps/old/m283.gcl (revision 3418)
@@ -0,0 +1,10 @@
+(load apps/old/m283.off geometry)
+# `g1' is the first loaded (and sole) object.
+(bbox-draw g1 no)
+# `c0' is the initial camera.
+(backcolor c0 1 1 1)
+# `g0' is ``the World''. Rotation is expressed in radians around each axis.
+(transform g0 g0 focus rotate 0.0 2.3 0.0)
+(zoom c0 1.5)
+(snapshot c0 apps/old/m283.ppm)
+(quit)
Property changes on: apps/old/m283.gcl
___________________________________________________________________
Added: svn:mergeinfo
Property changes on: apps
___________________________________________________________________
Modified: svn:ignore
- *.dSYM
image2d
complex
+ *.dSYM
image2d
graph
complex
Index: Makefile
===================================================================
--- Makefile (revision 3417)
+++ Makefile (revision 3418)
@@ -20,18 +20,23 @@
CLEANFILES = article.pdf $(BASE).pdf
-## apps/m283-s.png is not part of IMAGES since the tool that generated
-## it is outside this repository (it is located in Milena's
-## apps/statues directory).
+## apps/old/m283-s.png is not part of IMAGES since the tools that
+## generated it (milena/apps/statues/mesh-complex-max-curv-segm) is
+## outside this repository (it is located in Milena's apps/statues
+## directory). Note that I do not remember the values of lambda.
IMAGES = \
pics/picasso.png pics/picasso-dil.png \
\
pics/graph.neato pics/graph-dil.neato \
pics/graph.png pics/graph-dil.png \
\
+ apps/lena.png apps/lena-g.png apps/lena-s.png \
\
- apps/lena.png apps/lena-s.png \
- \
+ apps/graph.neato apps/graph.pdf \
+ apps/graph-g.neato apps/graph-g.pdf \
+ apps/graph-s.neato apps/graph-s.pdf
+
+IMAGES_OLD = \
apps/m272.png \
apps/m272-max-curv.png \
apps/m272-max-curv-s.off apps/m272-max-curv-s.png \
@@ -51,7 +56,7 @@
article.pdf: article.sty rev.sty
# FIXME: Use another extension: these files are not (La)TeX ones.
-article.pdf: pics/picasso.lst pics/graph.lst
+article.pdf: pics/picasso.lst pics/graph.lst apps/chain.lst
## -------- ##
## Images. ##
@@ -98,6 +103,10 @@
# Generate for the 3-D output (*-s.off) a file similar to the one used
# to capture the 3-D input (*.off), so that both snapshots show the
# same view.
+%-g.gcl: %.gcl
+ sed "s,$*,$*-g,g" $< >$@
+%-c.gcl: %.gcl
+ sed "s,$*,$*-c,g" $< >$@
%-s.gcl: %.gcl
sed "s,$*,$*-s,g" $< >$@
# Likewise for other derived meshes.
@@ -123,10 +132,13 @@
apps/image2d: apps/chain.hh
# Generate *-s.off from *.off using apps/complex.
-%-s.off: %.off apps/complex
- apps/complex $< 100 $@
-apps/complex: apps/chain.hh
+# FIXME: Disabled.
+## %-s.off: %.off apps/complex
+## apps/complex $< 100 $@
+## apps/complex: apps/chain.hh
+apps/graph-s.neato: pics/seeds.pgm apps/graph
+ apps/graph $< 2 $@
## --------- ##
## Install. ##
Index: pics/graph.cc
===================================================================
--- pics/graph.cc (revision 3417)
+++ pics/graph.cc (revision 3418)
@@ -45,8 +45,9 @@
#include <mln/core/alias/point2d.hh>
#include <mln/core/site_set/p_faces.hh>
+#include <mln/core/image/complex_image.hh>
#include <mln/core/alias/complex_geometry.hh>
-#include <mln/core/image/complex_image.hh>
+#include <mln/core/alias/complex_image.hh>
// FIXME: Include these elsewhere? (In complex_image.hh?)
#include <mln/core/image/complex_neighborhoods.hh>
Property changes on: .
___________________________________________________________________
Modified: svn:externals
- share -r 3413 https://svn.lrde.epita.fr/svn/lrde-publis/trunk/share
+ share -r 3417 https://svn.lrde.epita.fr/svn/lrde-publis/trunk/share
1
0
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Finalize ICIP 2009 code.
* theo/publis/icip2009/compute_a.cc (a_data): New.
(compute_a): Rename as...
(compute_data): ...this.
Update.
(compute_filter): New.
(main): Update.
compute_a.cc | 376 +++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 264 insertions(+), 112 deletions(-)
Index: theo/publis/icip2009/compute_a.cc
--- theo/publis/icip2009/compute_a.cc (revision 3376)
+++ theo/publis/icip2009/compute_a.cc (working copy)
@@ -34,7 +34,9 @@
#include <mln/core/alias/neighb2d.hh>
#include <mln/value/int_u8.hh>
#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
#include <mln/debug/println.hh>
+#include <mln/core/routine/duplicate.hh>
#include <mln/core/site_set/p_array.hh>
#include <mln/level/sort_psites.hh>
@@ -44,6 +46,8 @@
#include <mln/morpho/tree/data.hh>
#include <mln/morpho/tree/compute_attribute_image.hh>
+#include <mln/morpho/watershed/flooding.hh>
+#include <mln/morpho/elementary/gradient.hh>
#include <mln/labeling/regional_minima.hh>
#include <mln/accu/count.hh>
@@ -93,13 +97,36 @@
}
- //------------------------------- compute_a
+
+ //------------------------------- data
+
+
+
+ template <typename I, typename A>
+ struct a_data
+ {
+ typedef mln_site(I) P;
+ typedef p_array<P> S;
+
+ unsigned n_regmins;
+ S s;
+
+ mln_ch_value(I, mln_result(A)) a;
+ mln_ch_value(I, unsigned) nchildren;
+ mln_ch_value(I, P) par;
+ mln_ch_value(I, bool) flag;
+ };
+
+
+
+
+ //------------------------------- compute_data
template <typename I, typename N, typename A>
- mln_ch_value(I, mln_result(A))
- compute_a(const I& f, const N& nbh, A, unsigned& n_regmins,
+ a_data<I,A>
+ compute_data(const I& f, const N& nbh, A, unsigned& n_regmins,
bool echo = false)
{
typedef mln_site(I) P;
@@ -192,22 +219,15 @@
- // Output is the attribute image.
- mln_ch_value(I, mln_result(A)) a;
+ // Outputing.
+
+ mln_ch_value(I, mln_result(A)) a; // Attribute image.
initialize(a, f);
data::paste(attr, a);
-
- // Back-propagate flags to non-representant component sites.
- {
- mln_bkd_piter(S) p(s); // Reverse.
- for_all(p)
- if (f(par(p)) == f(p) && flag(par(p)) != flag(p))
- flag(p) = flag(par(p));
- if (echo)
- debug::println("flag", flag);
- }
-
+ mln_ch_value(I, unsigned) nchildren; // Number of children.
+ initialize(nchildren, f);
+ data::fill(nchildren, 0);
unsigned
n_sites = 0,
@@ -215,24 +235,80 @@
n_nodes = 0;
- // Tree canonization
+ // Finalization.
{
mln_bkd_piter(S) p(s); // Reverse.
for_all(p)
{
- P q = par(p);
- if (f(par(q)) == f(q))
- par(p) = par(q);
- ++n_sites;
- if (par(p) == p)
- ++n_roots;
- if (par(p) == p || f(par(p)) != f(p))
- ++n_nodes;
+
+ // Tree canonization
+ P par_p = par(p);
+ if (f(par(par_p)) == f(par_p) && par(p) != par(par_p))
+ {
+ par(p) = par(par_p);
+ par_p = par(p);
+ }
+
+ ++n_sites; // Counting.
+
+ if (f(par_p) == f(p))
+ {
+ if (par_p == p)
+ {
+ ++n_roots; // Counting.
+ ++n_nodes; // Counting.
+ }
+ else
+ {
+ a(p) = a(par_p); // Attribute image.
+ flag(p) = flag(par_p); // Flag (regional minima image).
+ }
+ }
+ else
+ {
+ ++nchildren(par_p); // Nchildren.
+ ++n_nodes; // Counting.
+ }
+
+
+// // Counting.
+// ++n_sites;
+// if (par_p == p)
+// ++n_roots;
+// if (par_p == p || f(par_p) != f(p))
+// ++n_nodes;
+
+// // Attributes.
+// if (f(par_p) == f(p))
+// a(p) = a(par_p);
+
+// // Flag (regional minima image).
+// if (f(par_p) == f(p) && flag(par_p) != flag(p))
+// flag(p) = flag(par_p);
+
+// // Nchildren.
+// if (f(par_p) != f(p))
+// ++nchildren(par_p);
+
}
- // Test.
+ }
+
+
+
+
+ std::cout << "%age nodes = "
+ << (float(n_nodes) / n_sites * 100.f) << std::endl
+ << std::endl;
+
+ /*
+
+ // Tests.
+ {
+
+ // Tree canonization
{
- mln_piter(S) p(s);
+ mln_bkd_piter(S) p(s); // Reverse.
for_all(p)
{
P q = par(p);
@@ -244,31 +320,61 @@
mln_invariant(f(par(q)) != f(q));
}
}
- }
-
- std::cout << "%age nodes = "
- << (float(n_nodes) / n_sites * 100.f) << std::endl
- << std::endl;
+ // Nchildren and Attributes.
+ {
+ typedef morpho::tree::data<I,S> T;
+ S s_ = reverse(s);
+ T t(f, s_, nbh);
+ typedef typename T::function C;
+ mln_ch_value(C, unsigned) nc_ref;
+ initialize(nc_ref, t.f());
+ data::fill(nc_ref, 0);
+ mln_fwd_piter(T) p(t.domain());
+ for_all(p)
+ if (t.is_a_non_root_node(p))
{
- // The attr image is not correct on flat zones since there is
- // no back-propagation of the attribute value of the component
- // root. For instance with f="v v v" we get attr="1 2 3"
- // instead of "3 3 3". So a finalization is required.
+ mln_invariant(t.is_a_node(t.parent(p)));
+ ++nc_ref(t.parent(p));
+ }
+ mln_invariant((nchildren | t.domain()) == nc_ref);
- mln_bkd_piter(S) p(s); // Reverse.
+ accu::count< util::pix<I> > fixme_;
+ mln_ch_value(I, mln_result(A)) a_ref;
+ a_ref = morpho::tree::compute_attribute_image(fixme_, t);
+ mln_assertion(a == a_ref);
+ }
+
+ // Nregmins.
+ {
+ unsigned n_ref;
+ mln_ch_value(I, unsigned) ref;
+ ref = labeling::regional_minima(f, nbh, n_ref);
+ // debug::println("ref", ref);
+
+ mln_assertion(n_regmins == n_ref);
+ mln_assertion(((pw::value(ref) != 0) | ref.domain()) == flag);
+ }
+ {
+ unsigned n = 0;
+ mln_fwd_piter(S) p(s);
for_all(p)
- if (f(par(p)) == f(p))
- a(p) = a(par(p));
+ if (f(par(p)) != f(p) && flag(p))
+ ++n;
+ mln_assertion(n == n_regmins);
}
- // Display tree.
+ } // end of Tests.
+
+
if (echo)
{
+ // Display tree, attributes, flags, and nchildren.
+
mln_ch_value(I, char) tree;
initialize(tree, f);
data::fill(tree, ' ');
@@ -282,82 +388,128 @@
else
tree(p) = '.';
debug::println(tree);
+
+ debug::println("a", a);
+ debug::println("flag", flag);
+ debug::println("nchildren", nchildren);
}
+*/
+ a_data<I,A> dta;
+ dta.s = s;
+ dta.a = a;
+ dta.nchildren = nchildren;
+ dta.par = par;
+ dta.flag = flag;
+ dta.n_regmins = n_regmins;
- {
- mln_ch_value(I, unsigned) nchildren;
- initialize(nchildren, f);
- data::fill(nchildren, 0);
+ return dta;
- mln_fwd_piter(S) p(s);
- for_all(p)
- if (f(par(p)) != f(p))
- {
- // Since the tree is canonized, par(p) is a node
- // (a component representative):
- P q = par(p);
- mln_invariant(par(q) == q || f(par(q)) != f(q));
- ++nchildren(par(p));
- }
+ } // compute_data
- if (echo)
- debug::println("nchildren", nchildren);
- // Test.
- {
- typedef morpho::tree::data<I,S> T;
- S s_ = reverse(s);
- T t(f, s_, nbh);
- typedef typename T::function C;
- mln_ch_value(C, unsigned) ref;
- initialize(ref, t.f());
- data::fill(ref, 0);
- mln_fwd_piter(T) p(t.domain());
- for_all(p)
- if (t.is_a_non_root_node(p))
+
+
+ //------------------------------- compute_filter
+
+
+
+ template <typename I, typename A>
+ mln_concrete(I)
+ compute_filter(const I& f, const a_data<I,A>& dta,
+ unsigned n_objects,
+ mln_result(A)& lambda,
+ bool echo = false)
{
- mln_invariant(t.is_a_node(t.parent(p)));
- ++ref(t.parent(p));
- }
+ typedef mln_site(I) P;
+ typedef p_array<P> S;
- mln_invariant((nchildren | t.domain()) == ref);
- }
+ const S& s = dta.s;
+ mln_ch_value(I, mln_result(A)) a = dta.a;
+ mln_ch_value(I, unsigned) nchildren = dta.nchildren;
+ mln_ch_value(I, P) par = dta.par;
+ unsigned n_regmins = dta.n_regmins;
+
+ if (n_objects >= n_regmins)
+ {
+ std::cout << "warning: number of expected objects is greater than number of regmins!" << std::endl;
+ std::cout << "aborting..." << std::endl;
+ return duplicate(f);
}
+ unsigned
+ count = dta.n_regmins,
+ less = 0;
+
+ // NOW attributes are sorted increasingly!
+ S s_a = level::sort_psites_increasing(a);
- // Tests.
- {
+
+ mln_fwd_piter(S) p(s_a);
+ for_all(p) // with increasing attribute.
{
- unsigned n_ref;
- mln_ch_value(I, unsigned) ref;
- ref = labeling::regional_minima(f, nbh, n_ref);
- // debug::println("ref", ref);
+ if (! (par(p) == p || f(par(p)) != f(p))) // Not a node.
+ continue;
- mln_assertion(n_regmins == n_ref);
- mln_assertion(((pw::value(ref) != 0) | ref.domain()) == flag);
+ if (a(p) < lambda && par(p) != p)
+ {
+ mln_assertion(nchildren(par(p)) > 0);
+ --nchildren(par(p));
+ if (nchildren(par(p)) != 0)
+ {
+ if (count <= n_objects)
+ {
+ ++less; // minus 1 object wrt the expected number!
}
+ --count;
+ if (count == n_objects)
{
- unsigned n = 0;
- mln_fwd_piter(S) p(s);
+ lambda = a(p) + 1;
+ std::cout << "lambda = " << lambda << std::endl
+ << std::endl;
+ }
+ }
+ }
+ }
+
+ if (less != 0)
+ std::cerr << "WARNING: less objects (" << less << ") than expected..." << std::endl
+ << std::endl;
+
+ if (echo)
+ debug::println("nchildren =", nchildren);
+
+
+ // Filtering.
+ mln_concrete(I) g;
+ initialize(g, f);
+
+ {
+ mln_bkd_piter(S) p(s); // Reverse.
for_all(p)
- if (f(par(p)) != f(p) && flag(p))
- ++n;
- mln_assertion(n == n_regmins);
+ {
+ if ((par(p) == p || f(par(p)) != f(p)) // p is a node.
+ &&
+ a(p) >= lambda) // Keep it.
+ g(p) = f(p);
+ else
+ g(p) = g(par(p)); // Propagate => filtering.
}
- } // end of Tests.
- return a;
+ if (echo)
+ debug::println("g =", g);
+ }
- } // compute
+ return g;
+ } // compute_filter
} // mln
@@ -367,7 +519,7 @@
void usage(char* argv[])
{
- std::cerr << "usage: " << argv[0] << " input.pgm echo" << std::endl;
+ std::cerr << "usage: " << argv[0] << " input.pgm n_objects filtered.pgm echo" << std::endl;
std::abort();
}
@@ -378,10 +530,14 @@
using namespace mln;
using value::int_u8;
- if (argc != 3)
+ if (argc != 5)
+ usage(argv);
+
+ int n_objects = std::atoi(argv[2]);
+ if (n_objects < 0)
usage(argv);
- int echo = std::atoi(argv[2]);
+ int echo = std::atoi(argv[4]);
if (echo != 0 && echo != 1)
usage(argv);
@@ -390,37 +546,33 @@
typedef image2d<int_u8> I;
- I f;
- io::pgm::load(f, argv[1]);
+ I input;
+ io::pgm::load(input, argv[1]);
if (echo)
- debug::println("f", f);
+ debug::println("input", input);
- accu::count<point2d> area;
- unsigned n_regmins;
- image2d<unsigned> a = compute_a(f, nbh, area, n_regmins, echo);
+ I f = morpho::elementary::gradient(input, nbh);
if (echo)
- debug::println("a", a);
+ debug::println("f (gradient)", f);
+ typedef accu::count<point2d> A;
+ typedef mln_result_(A) L;
+ A area;
+ unsigned n_regmins;
- {
- // Test of 'a'.
- typedef p_array<point2d> S;
- S s = level::sort_psites_decreasing(f);
- morpho::tree::data<I,S> t(f, s, nbh);
- accu::count< util::pix<I> > area;
- image2d<unsigned> a_ref = morpho::tree::compute_attribute_image(area, t);
- // debug::println("a_ref", a_ref);
- mln_assertion(a == a_ref);
- }
-
+ a_data<I,A> dta = compute_data(f, nbh, area, n_regmins, echo);
+ L lambda;
+ I g = compute_filter(f, dta, n_objects, lambda, echo);
+ io::pgm::save(g, argv[3]);
-// unsigned n_wanted = 10;
-// I g = filtering(f, a, nbh, n_regmins, n_wanted);
+ unsigned n_basins;
+ morpho::watershed::flooding(g, nbh, n_basins);
+ std::cout << "n basins = " << n_basins << std::endl;
}
1
0
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Update ICIP 2009 code.
* theo/publis,
* theo/publis/icip2009: New directories.
* theo/tufa_2008/regmin_count.cc: Move...
* theo/publis/icip2009/regmin_count.cc: ...here.
* theo/tufa_2008/compute_a.cc: Move...
* theo/publis/icip2009/compute_a.cc: ...here.
Update.
compute_a.cc | 366 ++++++++++++++++++++++++++++++-----------------------------
1 file changed, 190 insertions(+), 176 deletions(-)
Index: theo/publis/icip2009/compute_a.cc
--- theo/publis/icip2009/compute_a.cc (revision 0)
+++ theo/publis/icip2009/compute_a.cc (working copy)
@@ -1,4 +1,5 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -25,7 +26,7 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-/// \file sandbox/geraud/tufa/compute_a.cc
+/// \file sandbox/theo/publis/icip2009/compute_a.cc
#include <mln/core/image/image2d.hh>
#include <mln/core/image/image_if.hh>
@@ -47,6 +48,7 @@
#include <mln/accu/count.hh>
#include <mln/opt/at.hh>
+#include <mln/set/card.hh>
@@ -80,6 +82,16 @@
}
+ template <typename P>
+ p_array<P> reverse(const p_array<P>& arr)
+ {
+ p_array<P> out;
+ mln_bkd_piter(p_array<P>) p(arr);
+ for_all(p)
+ out.insert(p);
+ return out;
+ }
+
//------------------------------- compute_a
@@ -87,14 +99,16 @@
template <typename I, typename N, typename A>
mln_ch_value(I, mln_result(A))
- compute_a(const I& f, const N& nbh, A, unsigned& n_regmins)
+ compute_a(const I& f, const N& nbh, A, unsigned& n_regmins,
+ bool echo = false)
{
- typedef p_array<mln_psite(I)> S;
+ typedef mln_site(I) P;
+ typedef p_array<P> S;
S s = level::sort_psites_increasing(f);
// s maps increasing attributes.
- mln_ch_value(I, mln_site(I)) par;
- mln_ch_value(I, mln_site(I)) zpar;
+ mln_ch_value(I, P) par;
+ mln_ch_value(I, P) zpar;
mln_ch_value(I, bool) deja_vu, flag;
mln_ch_value(I, A) attr;
@@ -122,7 +136,7 @@
// First Pass.
{
- mln_site(I) r;
+ P r;
mln_fwd_piter(S) p(s);
mln_niter(N) n(nbh, p);
for_all(p)
@@ -138,230 +152,211 @@
r = find_root__(zpar, n);
if (r != p)
{
- // Fully compressed union.
- zpar(r) = p;
- attr(p).take(attr(r));
+ par(r) = p; // Min-tree computation.
+ zpar(r) = p; // Fully compressed union.
+
+ attr(p).take(attr(r)); // Attribute computation.
if (f(r) == f(p))
{
- // Weak-Union; only for flat zones.
- par(r) = p;
-
+ // Flat zones.
if (flag(p) == false && flag(r) == false)
{
// Two non-reg-min components merge (same flat
// zone) so we had an extra invalidation.
++n_regmins;
}
+ else
flag(p) = flag(p) && flag(r);
--n_regmins; // So we get the number of flat zones
// minus the non-reg-min flat zones.
}
else
{
- mln_invariant(f(r) < f(p));
+ mln_invariant(f(r) < f(p)); // Increasing browsing.
if (flag(p) == true)
+ {
--n_regmins; // Invalidation.
flag(p) = false;
}
}
}
+ }
deja_vu(p) = true;
}
+
} // end of First Pass.
std::cout << "n reg min = " << n_regmins << std::endl;
- {
- unsigned n = 0;
- mln_fwd_piter(S) p(s);
- for_all(p)
- if (par(p) == p && flag(p))
- ++n;
- mln_assertion(n == n_regmins);
- }
-
-
- // The attr image is not correct on flat zones since there is
- // no back-propagation of the attribute value of the component
- // root. For instance with f="v v v" we get attr="1 2 3"
- // instead of "3 3 3". So a finalization is required.
+ // Output is the attribute image.
mln_ch_value(I, mln_result(A)) a;
initialize(a, f);
data::paste(attr, a);
- // Finalization.
+
+ // Back-propagate flags to non-representant component sites.
{
mln_bkd_piter(S) p(s); // Reverse.
-
- unsigned n_non_compressed_par = 0;
for_all(p)
- {
- a(p) = a(par(p));
- if (par(par(p)) != par(p))
- ++ n_non_compressed_par;
- }
- std::cout << "n_non_compressed_par = " << n_non_compressed_par << std::endl;
+ if (f(par(p)) == f(p) && flag(par(p)) != flag(p))
+ flag(p) = flag(par(p));
+ if (echo)
+ debug::println("flag", flag);
}
- // TODO: compress at least the reg minima!
+ unsigned
+ n_sites = 0,
+ n_roots = 0,
+ n_nodes = 0;
+
+ // Tree canonization
{
- image2d<unsigned> regmin;
- initialize(regmin, f);
- {
- unsigned i_regmin = 0;
- mln_bkd_piter(S) p(s);
+ mln_bkd_piter(S) p(s); // Reverse.
for_all(p)
{
+ P q = par(p);
+ if (f(par(q)) == f(q))
+ par(p) = par(q);
+ ++n_sites;
if (par(p) == p)
+ ++n_roots;
+ if (par(p) == p || f(par(p)) != f(p))
+ ++n_nodes;
+ }
+
+ // Test.
{
- if (flag(p))
- regmin(p) = ++i_regmin;
- else
- regmin(p) = 0;
+ mln_piter(S) p(s);
+ for_all(p)
+ {
+ P q = par(p);
+ if (q == p || par(q) == q) // Either p or par(p) is root.
+ continue;
+ if (f(q) == f(p))
+ // p and par(p) within a flat zone
+ // so q=par(p) is the representant
+ mln_invariant(f(par(q)) != f(q));
}
- else
- regmin(p) = regmin(par(p));
}
}
- debug::println("f", f);
- debug::println("flag", flag);
- // We can see that some point are at true for components that
- // are not reg min; flag is a candidate to be compressed...
+ std::cout << "%age nodes = "
+ << (float(n_nodes) / n_sites * 100.f) << std::endl
+ << std::endl;
+
- debug::println("regmin", regmin);
+ {
+ // The attr image is not correct on flat zones since there is
+ // no back-propagation of the attribute value of the component
+ // root. For instance with f="v v v" we get attr="1 2 3"
+ // instead of "3 3 3". So a finalization is required.
+ mln_bkd_piter(S) p(s); // Reverse.
+ for_all(p)
+ if (f(par(p)) == f(p))
+ a(p) = a(par(p));
+ }
- // TODO:
- // On veut tester ici dans quel ordre on voit les
- // reg min lorsque a croit. Pour tous les points d'un reg min,
- // est-ce que le root est vu en premier ?
+ // Display tree.
+ if (echo)
+ {
+ mln_ch_value(I, char) tree;
+ initialize(tree, f);
+ data::fill(tree, ' ');
+ mln_piter(I) p(f.domain());
+ for_all(p)
+ if (par(p) == p) // Root.
+ tree(p) = '@';
+ else
+ if (f(par(p)) != f(p)) // Representative.
+ tree(p) = 'o';
+ else
+ tree(p) = '.';
+ debug::println(tree);
+ }
- image2d<bool> seen;
- initialize(seen, f);
- data::fill(seen, false);
+ {
+ mln_ch_value(I, unsigned) nchildren;
+ initialize(nchildren, f);
+ data::fill(nchildren, 0);
- s = level::sort_psites_increasing(a);
- mln_bkd_piter(S) p(s);
+ mln_fwd_piter(S) p(s);
for_all(p)
+ if (f(par(p)) != f(p))
{
- if (regmin(p) == 0)
- continue;
- // p is in a regional minimum.
- if (par(p) != p) // A non-root point.
- {
- mln_assertion(regmin(par(p)) != 0); // Root in a regional minimum.
- mln_assertion(regmin(par(p)) == regmin(p)); // and the same as p.
- mln_assertion(seen(par(p)));
- }
- seen(p) = true;
+ // Since the tree is canonized, par(p) is a node
+ // (a component representative):
+ P q = par(p);
+ mln_invariant(par(q) == q || f(par(q)) != f(q));
+ ++nchildren(par(p));
}
- debug::println(seen);
-// if (flag(p))
-// std::cout << a(p) << ' ' << p << ' ' << (par(p) == p) << std::endl;
+ if (echo)
+ debug::println("nchildren", nchildren);
+ // Test.
+ {
+ typedef morpho::tree::data<I,S> T;
+ S s_ = reverse(s);
+ T t(f, s_, nbh);
+
+ typedef typename T::function C;
+ mln_ch_value(C, unsigned) ref;
+ initialize(ref, t.f());
+ data::fill(ref, 0);
+
+ mln_fwd_piter(T) p(t.domain());
+ for_all(p)
+ if (t.is_a_non_root_node(p))
+ {
+ mln_invariant(t.is_a_node(t.parent(p)));
+ ++ref(t.parent(p));
}
- return a;
+ mln_invariant((nchildren | t.domain()) == ref);
+ }
}
- //------------------------------- filtering
+ // Tests.
+ {
+ {
+ unsigned n_ref;
+ mln_ch_value(I, unsigned) ref;
+ ref = labeling::regional_minima(f, nbh, n_ref);
+ // debug::println("ref", ref);
+
+ mln_assertion(n_regmins == n_ref);
+ mln_assertion(((pw::value(ref) != 0) | ref.domain()) == flag);
+ }
+ {
+ unsigned n = 0;
+ mln_fwd_piter(S) p(s);
+ for_all(p)
+ if (f(par(p)) != f(p) && flag(p))
+ ++n;
+ mln_assertion(n == n_regmins);
+ }
+ } // end of Tests.
-// template <typename I, typename A, typename N>
-// mln_concrete(I) filtering(const I& f, const A& a, const N& nbh,
-// unsigned n_regmins, unsigned n_wanted)
-// {
-// typedef p_array<mln_psite(I)> S;
-// S s = level::sort_psites_increasing(a);
-
-// // s maps increasing attributes.
-
-// mln_concrete(I) out;
-// initialize(out, f);
-
-// mln_ch_value(I, mln_site(I)) par;
-// mln_ch_value(I, bool) deja_vu, flag;
-
-// // Initialization.
-// {
-// initialize(par, f);
-// mln_piter(A) p(par.domain());
-// for_all(p)
-// par(p) = p;
-// initialize(deja_vu, f);
-// data::fill(deja_vu, false);
-
-// // flag
-// initialize(flag, f);
-// data::fill(flag, true);
-// }
-
-
-// int counter = 0;
-// // We are trying to count the number of merges of regional minima...
-
-
-// // First Pass.
-// {
-// mln_site(I) r;
-// mln_fwd_piter(S) p(s);
-// mln_niter(N) n(nbh, p);
-// for_all(p)
-// {
-// for_all(n)
-// if (a.domain().has(n) && deja_vu(n))
-// {
-// r = find_root__(par, n);
-// if (r != p)
-// if (a(r) == a(p))
-// {
-// par(r) = p; // Union.
-// if (flag(r) == true && flag(p) == true)
-// --counter;
-// flag(p) = flag(p) && flag(r);
-// }
-// else // a(r) != a(p)
-// {
-// if (flag(r) == true && flag(p) == true)
-// ++counter;
-// mln_invariant(a(p) > a(r));
-// flag(p) = false;
-// }
-// }
-// deja_vu(p) = true;
-// }
-// std::cout << counter << std::endl;
-// }
-
-// // // Second Pass.
-// // {
-// // mln_bkd_piter(S) p(s);
-// // for_all(p)
-// // if (par(p) == p)
-// // out(p) = f(p);
-// // else
-// // out(p) = out(par(p));
-// // }
-// return out;
-// }
+ return a;
+ } // compute
@@ -370,43 +365,62 @@
-int main(int, char* argv[])
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm echo" << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
{
using namespace mln;
using value::int_u8;
+ if (argc != 3)
+ usage(argv);
+
+ int echo = std::atoi(argv[2]);
+ if (echo != 0 && echo != 1)
+ usage(argv);
+
+
+ neighb2d nbh = c4();
+
+
typedef image2d<int_u8> I;
I f;
io::pgm::load(f, argv[1]);
- // debug::println(f);
+ if (echo)
+ debug::println("f", f);
accu::count<point2d> area;
unsigned n_regmins;
- image2d<unsigned> a = compute_a(f, c4(), area, n_regmins);
- // debug::println(a);
-// {
-// // Test of 'n_regmins'.
-// unsigned ref;
-// labeling::regional_minima(f, c4(), ref);
-// mln_assertion(n_regmins == ref);
-// }
-
-// {
-// // Test of 'a'.
-// typedef p_array<point2d> S;
-// S s = level::sort_psites_decreasing(f);
-// morpho::tree::data<I,S> t(f, s, c4());
-// accu::count< util::pix<I> > area;
-// image2d<unsigned> ref = morpho::tree::compute_attribute_image(area, t);
-// mln_assertion(a == ref);
-// }
+ image2d<unsigned> a = compute_a(f, nbh, area, n_regmins, echo);
+ if (echo)
+ debug::println("a", a);
+
+
+
+
+ {
+ // Test of 'a'.
+ typedef p_array<point2d> S;
+ S s = level::sort_psites_decreasing(f);
+ morpho::tree::data<I,S> t(f, s, nbh);
+ accu::count< util::pix<I> > area;
+ image2d<unsigned> a_ref = morpho::tree::compute_attribute_image(area, t);
+ // debug::println("a_ref", a_ref);
+ mln_assertion(a == a_ref);
+ }
// unsigned n_wanted = 10;
-// I g = filtering(f, a, c4(), n_regmins, n_wanted);
+// I g = filtering(f, a, nbh, n_regmins, n_wanted);
}
Property changes on: theo/publis/icip2009/compute_a.cc
___________________________________________________________________
Added: svn:mergeinfo
Property changes on: theo/publis/icip2009/regmin_count.cc
___________________________________________________________________
Added: svn:mergeinfo
1
0
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2009-02-13 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Create a sandbox for DICOM support..
* fabien/dicom/load.hh: Load implementation.
* fabien/dicom/save.hh: Save implementation.
* fabien/igr/igr.cc: Minor fixes.
---
dicom/load.hh | 547 +++++++++++++++++++++++++++
dicom/save.hh | 1171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
igr/igr.cc | 2
3 files changed, 1719 insertions(+), 1 deletion(-)
Index: trunk/milena/sandbox/fabien/igr/igr.cc
===================================================================
--- trunk/milena/sandbox/fabien/igr/igr.cc (revision 3374)
+++ trunk/milena/sandbox/fabien/igr/igr.cc (revision 3375)
@@ -41,7 +41,7 @@
#include <mln/io/cloud/all.hh>
#include <mln/io/dump/all.hh>
-#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/alias/neigyyhb2d.hh>
#include <mln/core/alias/neighb3d.hh>
#include <mln/labeling/flat_zones.hh>
#include <mln/labeling/background.hh>
Index: trunk/milena/sandbox/fabien/dicom/save.hh
===================================================================
--- trunk/milena/sandbox/fabien/dicom/save.hh (revision 0)
+++ trunk/milena/sandbox/fabien/dicom/save.hh (revision 3375)
@@ -0,0 +1,1171 @@
+/*
+ *
+ * Copyright (C) 1994-2005, OFFIS
+ *
+ * This software and supporting documentation were developed by
+ *
+ * Kuratorium OFFIS e.V.
+ * Healthcare Information and Communication Systems
+ * Escherweg 2
+ * D-26121 Oldenburg, Germany
+ *
+ * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY
+ * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
+ * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
+ * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
+ *
+ * Module: dcmdata
+ *
+ * Author: Andreas Barth
+ *
+ * Purpose: create a Dicom FileFormat or DataSet from an ASCII-dump
+ *
+ * Last Update: $Author: onken $
+ * Update Date: $Date: 2005/12/16 09:07:03 $
+ * CVS/RCS Revision: $Revision: 1.51 $
+ * Status: $State: Exp $
+ *
+ * CVS/RCS Log at end of file
+ *
+ */
+
+/*
+ * Input File Description:
+ * The input file be an output of dcmdump. One element (Tag, VR, value) must
+ * be written into one line separated by arbitrary spaces or tab characters.
+ * A # begins a comment that ends at the line end. Empty lines are allowed.
+ * This parts of a line have the following syntax:
+ * Tag: (gggg,eeee)
+ * with gggg and eeee are 4 character hexadecimal values representing
+ * group- and element-tag. Spaces and Tabs can be anywhere in a Tag
+ * specification
+ * VR: Value Representation must be written as 2 characters as in Part 6
+ * of the DICOM 3.0 standard. No Spaces or Tabs are allowed between the
+ * two characters. If the VR can determined from the Tag, this part of
+ * a line is optional.
+ * Value: There are several rules for writing values:
+ * 1. US, SS, SL, UL, FD, FL are written as
+ * decimal strings that can be read by scanf.
+ * 2. AT is written as (gggg,eeee) with additional spaces stripped off
+ * automatically and gggg and eeee being decimal strings that
+ * can be read by scanf.
+ * 3. OB, OW values are written as byte or word hexadecimal values
+ * separated by '\' character. Alternatively, OB or OW values can
+ * be read from a separate file by writing the filename prefixed
+ * by a '=' character (e.g. =largepixeldata.dat). The contents of
+ * the file will be read as is. OW data is expected to be little
+ * endian ordered and will be swapped if necessary. No checks will
+ * be made to ensure that the amount of data is reasonable in terms
+ * of other attributes such as Rows or Columns.
+ * 4. UI is written as =Name in data dictionary or as
+ * unique identifer string (see 6.) , e.g. [1.2.840.....]
+ * 5. Strings without () <> [] spaces, tabs and # can be
+ * written directly
+ * 6. Other strings with must be surrounded by [ ]. No
+ * bracket structure is passed. The value ends at the last ] in
+ * the line. Anything after the ] is interpreted as comment.
+ * 7. ( < are interpreted special and may not be used when writing
+ * an input file by hand as beginning characters of a string.
+ * Multiple Value are separated by \
+ * The sequence of lines must not be ordered but they can.
+ * References in DICOM Directories are not supported.
+ * Semantic errors are not detected.
+ *
+ * Examples:
+ * (0008,0020) DA [19921012] # 8, 1 StudyDate
+ * (0008,0016) UI =MRImageStorage # 26, 1 SOPClassUID
+ * (0002,0012) UI [1.2.276.0.7230010.100.1.1]
+ * (0020,0032) DS [0.0\0.0] # 8, 2 ImagePositionPatient
+ * (0028,0009) AT (3004,000c) # 4, 1 FrameIncrementPointer
+ * (0028,0010) US 256 # 4, 1 Rows
+ * (0002,0001) OB 01\00
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"
+
+#define INCLUDE_CSTDLIB
+#define INCLUDE_CSTDIO
+#define INCLUDE_CCTYPE
+#include "dcmtk/ofstd/ofstdinc.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_STAT_H
+#include <stat.h>
+#endif
+#ifdef HAVE_GUSI_H
+#include <GUSI.h>
+#endif
+
+#include "dcmtk/ofstd/ofstream.h"
+#include "dcmtk/dcmdata/dctk.h"
+#include "dcmtk/dcmdata/dcdebug.h"
+#include "dcmtk/dcmdata/cmdlnarg.h"
+#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/ofstd/ofstd.h"
+#include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */
+
+#ifdef WITH_ZLIB
+#include <zlib.h> /* for zlibVersion() */
+#endif
+
+#define OFFIS_CONSOLE_APPLICATION "dump2dcm"
+
+static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
+ OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
+
+#define SHORTCOL 3
+#define LONGCOL 21
+
+// Maximum Line Size
+
+const unsigned int DCM_DumpMaxLineSize = 4096;
+
+
+// Field definition separators
+
+#define DCM_DumpCommentChar '#'
+#define DCM_DumpTagDelim ')'
+#define DCM_DumpOpenString '['
+#define DCM_DumpCloseString ']'
+#define DCM_DumpOpenDescription '('
+#define DCM_DumpOpenFile '<'
+#define DCM_DumpCloseFile '>'
+
+static void
+stripWhitespace(char* s)
+{
+ char* p;
+
+ if (s == NULL) return;
+
+ p = s;
+ while (*s != '\0') {
+ if (isspace(*s) == OFFalse) {
+ *p++ = *s;
+ }
+ s++;
+ }
+ *p = '\0';
+}
+
+static char*
+stripTrailingWhitespace(char* s)
+{
+ int i, n;
+ if (s == NULL) return s;
+
+ n = strlen(s);
+ for (i = n - 1; i >= 0 && isspace(s[i]); i--)
+ s[i] = '\0';
+ return s;
+}
+
+
+static char *
+stripPrecedingWhitespace(char * s)
+{
+ char * p;
+ if (s == NULL) return s;
+
+ for(p = s; *p && isspace(*p); p++)
+ ;
+
+ return p;
+}
+
+static OFBool
+onlyWhitespace(const char* s)
+{
+ int len = strlen(s);
+ int charsFound = OFFalse;
+
+ for (int i=0; (!charsFound) && (i<len); i++) {
+ charsFound = !isspace(s[i]);
+ }
+ return (!charsFound)?(OFTrue):(OFFalse);
+}
+
+static char*
+getLine(char* line, int maxLineLen, FILE* f, const unsigned long lineNumber)
+{
+ char* s;
+
+ s = fgets(line, maxLineLen, f);
+
+ // if line is too long, throw rest of it away
+ if (s && strlen(s) == size_t(maxLineLen-1) && s[maxLineLen-2] != '\n')
+ {
+ int c = fgetc(f);
+ while(c != '\n' && c != EOF)
+ c = fgetc(f);
+ CERR << "line " << lineNumber << " too long." << endl;
+ }
+
+ /* strip any trailing white space */
+ stripTrailingWhitespace(s);
+
+ return s;
+}
+
+static OFBool
+isaCommentLine(const char* s)
+{
+ OFBool isComment = OFFalse; /* assumption */
+ int len = strlen(s);
+ int i = 0;
+ for (i=0; i<len && isspace(s[i]); i++) /*loop*/;
+ isComment = (s[i] == DCM_DumpCommentChar);
+ return isComment;
+}
+
+static OFBool
+parseTag(char* & s, DcmTagKey& key)
+{
+ OFBool ok = OFTrue;
+ char * p;
+ unsigned int g, e;
+
+ // find tag begin
+ p = strchr(s, DCM_DumpTagDelim);
+ if (p)
+ {
+ // string all white spaces and read tag
+ int len = p-s+1;
+ p = new char[len+1];
+ OFStandard::strlcpy(p, s, len+1);
+ stripWhitespace(p);
+ s += len;
+
+ if (sscanf(p, "(%x,%x)", &g, &e) == 2) {
+ key.set(g, e);
+ } else {
+ ok = OFFalse;
+ }
+ delete[] p;
+ }
+ else ok = OFFalse;
+
+ return ok;
+}
+
+
+static OFBool
+parseVR(char * & s, DcmEVR & vr)
+{
+ OFBool ok = OFTrue;
+
+ s = stripPrecedingWhitespace(s);
+
+ // Are there two upper characters?
+ if (isupper(*s) && isupper(*(s+1)))
+ {
+ char c_vr[3];
+ OFStandard::strlcpy(c_vr, s, 3);
+ // Convert to VR
+ DcmVR dcmVR(c_vr);
+ vr = dcmVR.getEVR();
+ s+=2;
+ }
+ else if ((*s == 'p')&&(*(s+1) == 'i'))
+ {
+ vr = EVR_pixelItem;
+ s+=2;
+ }
+ else if (((*s == 'o')&&(*(s+1) == 'x')) || ((*s == 'x')&&(*(s+1) == 's')) ||
+ (*s == 'n')&&(*(s+1) == 'a') || ((*s == 'u')&&(*(s+1) == 'p')))
+ {
+ // swallow internal VRs
+ vr = EVR_UNKNOWN;
+ s+=2;
+ }
+ else ok = OFFalse;
+
+ return ok;
+}
+
+
+static int
+searchLastClose(char *s, char closeChar)
+{
+ // search last close bracket in a line
+ // no bracket structure will be considered
+
+ char * found = NULL;
+ char * p = s;
+
+ while(p && *p)
+ {
+ p = strchr(p, closeChar);
+ if (p)
+ {
+ found = p;
+ p++;
+ }
+ }
+
+ if (found)
+ return (found - s) + 1;
+ else
+ return 0;
+}
+
+
+static int
+searchCommentOrEol(char *s)
+{
+ char * comment = strchr(s, DCM_DumpCommentChar);
+ if (comment)
+ return comment - s;
+ else if (s)
+ return strlen(s);
+ else
+ return 0;
+}
+
+
+static char*
+convertNewlineCharacters(char* s)
+{
+ // convert the string "\n" into the \r\n combination required by DICOM
+ if (s == NULL || s[0] == '\0') return s;
+ int len = strlen(s);
+ int i = 0;
+ for (i=0; i<(len-1); i++) {
+ if (s[i] == '\\' && s[i+1] == 'n') {
+ s[i] = '\r';
+ s[i+1] = '\n';
+ i++;
+ }
+ }
+
+ return s;
+}
+
+static OFBool
+parseValue(char * & s, char * & value, const DcmEVR & vr)
+{
+ OFBool ok = OFTrue;
+ int len;
+ value = NULL;
+
+ s = stripPrecedingWhitespace(s);
+
+ switch (*s)
+ {
+ case DCM_DumpOpenString:
+ len = searchLastClose(s, DCM_DumpCloseString);
+ if (len == 0)
+ ok = OFFalse;
+ else if (len > 2)
+ {
+ value = new char[len-1];
+ OFStandard::strlcpy(value, s+1, len-1);
+ value = convertNewlineCharacters(value);
+ }
+ else
+ value = NULL;
+ break;
+
+ case DCM_DumpOpenDescription:
+ /* need to distinguish vr=AT from description field */
+ /* NB: if the vr is unknown this workaround will not succeed */
+ if (vr == EVR_AT)
+ {
+ len = searchLastClose(s, DCM_DumpTagDelim);
+ if (len >= 11) // (gggg,eeee) allow non-significant spaces
+ {
+ char *pv = s;
+ DcmTagKey tag;
+ if (parseTag(pv, tag)) // check for valid tag format
+ {
+ value = new char[len+1];
+ OFStandard::strlcpy(value, s, len+1);
+ stripWhitespace(value);
+ } else
+ ok = OFFalse; // skip description
+ }
+ else
+ ok = OFFalse; // skip description
+ }
+ break;
+
+ case DCM_DumpOpenFile:
+ ok = OFFalse; // currently not supported
+ break;
+
+ case DCM_DumpCommentChar:
+ break;
+
+ default:
+ len = searchCommentOrEol(s);
+ if (len)
+ {
+ value = new char[len+1];
+ OFStandard::strlcpy(value, s, len+1);
+ stripTrailingWhitespace(value);
+ }
+ break;
+ }
+ return ok;
+}
+
+
+static unsigned long
+fileSize(const char *fname)
+{
+ struct stat s;
+ unsigned long nbytes = 0;
+
+ if (stat(fname, &s) == 0) {
+ nbytes = s.st_size;
+ }
+ return nbytes;
+}
+
+static OFCondition
+putFileContentsIntoElement(DcmElement* elem, const char* filename)
+{
+ FILE* f = NULL;
+ OFCondition ec = EC_Normal;
+
+ if ((f = fopen(filename, "rb")) == NULL) {
+ CERR << "ERROR: cannot open binary data file: " << filename << endl;
+ return EC_InvalidTag;
+ }
+
+ unsigned long len = fileSize(filename);
+ unsigned long buflen = len;
+ if (buflen & 1) buflen++; /* if odd then make even (DICOM required even length values) */
+
+ Uint8* buf = new Uint8[buflen];
+ if (buf == NULL) {
+ CERR << "ERROR: out of memory reading binary data file: " << filename << endl;
+ ec = EC_MemoryExhausted;
+ } else if (fread(buf, 1, OFstatic_cast(size_t, len), f) != len) {
+ CERR << "ERROR: error reading binary data file: " << filename << ": ";
+ perror(NULL);
+ ec = EC_CorruptedData;
+ } else {
+ /* assign buffer to attribute */
+ DcmEVR evr = elem->getVR();
+ if (evr == EVR_OB) {
+ /* put 8 bit OB data into the attribute */
+ ec = elem->putUint8Array(buf, buflen);
+ } else if (evr == EVR_OW) {
+ /* put 16 bit OW data into the attribute */
+ swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, buf, buflen, sizeof(Uint16));
+ ec = elem->putUint16Array(OFreinterpret_cast(Uint16 *, buf), buflen / 2);
+ } else if (evr == EVR_pixelItem) {
+ /* pixel item not yet supported */
+ }
+ }
+
+ fclose(f);
+ delete[] buf;
+ return ec;
+}
+
+static OFCondition
+insertIntoSet(DcmStack & stack, DcmTagKey tagkey, DcmEVR vr, char * value)
+{
+ // insert new Element into dataset or metaheader
+
+ OFCondition l_error = EC_Normal;
+ OFCondition newElementError = EC_Normal;
+
+ if (stack.empty())
+ l_error = EC_CorruptedData;
+
+ if (l_error == EC_Normal)
+ {
+ DcmElement * newElement = NULL;
+ DcmObject * topOfStack = stack.top();
+
+ // convert tagkey to tag including VR
+ DcmTag tag(tagkey);
+ DcmVR dcmvr(vr);
+
+ const DcmEVR tagvr = tag.getEVR();
+ if (tagvr != vr && vr != EVR_UNKNOWN && tagvr != EVR_UNKNOWN &&
+ (tagkey != DCM_LUTData || (vr != EVR_US && vr != EVR_SS && vr != EVR_OW)) &&
+ (tagvr != EVR_xs || (vr != EVR_US && vr != EVR_SS)) &&
+ (tagvr != EVR_ox || (vr != EVR_OB && vr != EVR_OW)) &&
+ (tagvr != EVR_na || vr != EVR_pixelItem))
+ {
+ CERR << "Warning: Tag " << tag << " with wrong VR "
+ << dcmvr.getVRName() << " found, correct is "
+ << tag.getVR().getVRName() << endl;
+ }
+
+ if (vr != EVR_UNKNOWN)
+ tag.setVR(dcmvr);
+
+ // create new element
+ newElementError = newDicomElement(newElement, tag);
+
+ if (newElementError == EC_Normal)
+ {
+ // tag describes an Element
+ if (!newElement)
+ // Tag was ambiguous
+ l_error = EC_InvalidVR;
+ else
+ {
+ // fill value
+ if (value)
+ {
+ if (value[0] == '=' && (tag.getEVR() == EVR_OB || tag.getEVR() == EVR_OW))
+ {
+ /*
+ * Special case handling for OB or OW data.
+ * Allow a value beginning with a '=' character to represent
+ * a file containing data to be used as the attribute value.
+ * A '=' character is not a normal value since OB and OW values
+ * must be written as multivalued hexidecimal (e.g. "00\ff\0d\8f");
+ */
+ l_error = putFileContentsIntoElement(newElement, value+1);
+ }
+ else if (tag.getEVR() == EVR_pixelItem)
+ {
+ /* pixel items not yet supported */
+ l_error = EC_InvalidTag;
+ } else {
+ l_error = newElement->putString(value);
+ }
+ }
+
+ // insert element into hierarchy
+ if (l_error == EC_Normal)
+ {
+ switch(topOfStack->ident())
+ {
+ case EVR_item:
+ case EVR_dirRecord:
+ case EVR_dataset:
+ case EVR_metainfo:
+ {
+ DcmItem *item = OFstatic_cast(DcmItem *, topOfStack);
+ item -> insert(newElement);
+ if (newElement->ident() == EVR_SQ || newElement->ident() == EVR_pixelSQ)
+ stack.push(newElement);
+ }
+ break;
+ default:
+ l_error = EC_InvalidTag;
+ break;
+ }
+ }
+ }
+ }
+ else if (newElementError == EC_SequEnd)
+ {
+ // pop stack if stack object was a sequence
+ if (topOfStack->ident() == EVR_SQ || topOfStack->ident() == EVR_pixelSQ)
+ stack.pop();
+ else
+ l_error = EC_InvalidTag;
+ }
+ else if (newElementError == EC_ItemEnd)
+ {
+ // pop stack if stack object was an item
+ switch (topOfStack->ident())
+ {
+ case EVR_item:
+ case EVR_dirRecord:
+ case EVR_dataset:
+ case EVR_metainfo:
+ stack.pop();
+ break;
+
+ default:
+ l_error = EC_InvalidTag;
+ break;
+ }
+ }
+ else if (newElementError == EC_InvalidTag)
+ {
+ if (tag.getXTag() == DCM_Item)
+ {
+ DcmItem * item = NULL;
+ if (topOfStack->getTag().getXTag() == DCM_DirectoryRecordSequence)
+ {
+ // an Item must be pushed to the stack
+ item = new DcmDirectoryRecord(tag, 0);
+ OFstatic_cast(DcmSequenceOfItems *, topOfStack) -> insert(item);
+ stack.push(item);
+ }
+ else if (topOfStack->ident() == EVR_SQ)
+ {
+ // an item must be pushed to the stack
+ item = new DcmItem(tag);
+ OFstatic_cast(DcmSequenceOfItems *, topOfStack) -> insert(item);
+ stack.push(item);
+ }
+ else
+ l_error = EC_InvalidTag;
+ }
+ else
+ l_error = EC_InvalidTag;
+ }
+ else
+ {
+ l_error = EC_InvalidTag;
+ }
+ }
+
+ return l_error;
+}
+
+static OFBool
+readDumpFile(DcmMetaInfo * metaheader, DcmDataset * dataset,
+ FILE * infile, const char * ifname, const OFBool stopOnErrors,
+ const unsigned long maxLineLength)
+{
+ char * lineBuf = new char[maxLineLength];
+ int lineNumber = 0;
+ OFBool errorOnThisLine = OFFalse;
+ char * parse = NULL;
+ char * value = NULL;
+ DcmEVR vr = EVR_UNKNOWN;
+ int errorsEncountered = 0;
+ DcmTagKey tagkey;
+ DcmStack metaheaderStack;
+ DcmStack datasetStack;
+
+ if (metaheader)
+ metaheaderStack.push(metaheader);
+
+ datasetStack.push(dataset);
+
+ while(getLine(lineBuf, int(maxLineLength), infile, lineNumber+1))
+ {
+ lineNumber++;
+
+ // ignore empty lines and comment lines
+ if (onlyWhitespace(lineBuf))
+ continue;
+ if (isaCommentLine(lineBuf))
+ continue;
+
+ errorOnThisLine = OFFalse;
+
+ parse = &lineBuf[0];
+
+ // parse tag an the line
+ if (!parseTag(parse, tagkey))
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": "<< ifname << ": "
+ << "no Tag found (line " << lineNumber << ")"<< endl;
+ errorOnThisLine = OFTrue;
+ }
+
+ // parse optional VR
+ if (!errorOnThisLine && !parseVR(parse, vr))
+ vr = EVR_UNKNOWN;
+
+ // parse optional value
+ if (!errorOnThisLine && !parseValue(parse, value, vr))
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": "<< ifname << ": "
+ << "incorrect value specification (line " << lineNumber << ")"<< endl;
+ errorOnThisLine = OFTrue;
+ }
+
+
+ // insert new element that consists of tag, VR, and value
+ if (!errorOnThisLine)
+ {
+ OFCondition l_error = EC_Normal;
+ if (tagkey.getGroup() == 2)
+ {
+ if (metaheader)
+ l_error = insertIntoSet(metaheaderStack, tagkey, vr, value);
+ }
+ else
+ l_error = insertIntoSet(datasetStack, tagkey, vr, value);
+
+ if (value)
+ {
+ delete[] value;
+ value = NULL;
+ }
+ if (l_error != EC_Normal)
+ {
+ errorOnThisLine = OFTrue;
+ CERR << OFFIS_CONSOLE_APPLICATION ": " << ifname << ": Error in creating Element: "
+ << l_error.text() << " (line " << lineNumber << ")"<< endl;
+ }
+
+ }
+
+ if (errorOnThisLine)
+ errorsEncountered++;
+ }
+
+
+ // test blocking structure
+ if (metaheader && metaheaderStack.card() != 1)
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": " << ifname << ": Block Error in metaheader" << endl;
+ errorsEncountered++;
+ }
+
+ if (datasetStack.card() != 1)
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": " << ifname << ": Block Error in dataset" << endl;
+ errorsEncountered++;
+ }
+
+ delete[] lineBuf;
+
+ if (errorsEncountered)
+ {
+ CERR << errorsEncountered << " Errors found in " << ifname << endl;
+ return !stopOnErrors;
+ }
+ else
+ return OFTrue;
+}
+
+// ********************************************
+
+int main(int argc, char *argv[])
+{
+#ifdef HAVE_GUSI_H
+ GUSISetup(GUSIwithSIOUXSockets);
+ GUSISetup(GUSIwithInternetSockets);
+#endif
+
+ SetDebugLevel(( 0 ));
+
+ OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION , "Convert ASCII dump to DICOM file", rcsid);
+ OFCommandLine cmd;
+
+ cmd.setOptionColumns(LONGCOL, SHORTCOL);
+ cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
+
+ cmd.addParam("dumpfile-in", "dump input filename");
+ cmd.addParam("dcmfile-out", "DICOM output filename");
+
+ cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
+ cmd.addOption("--help", "-h", "print this help text and exit");
+ cmd.addOption("--version", "print version information and exit", OFTrue /* exclusive */);
+ cmd.addOption("--verbose", "-v", "verbose mode, print processing details");
+ cmd.addOption("--debug", "-d", "debug mode, print debug information");
+
+ cmd.addGroup("input options:", LONGCOL, SHORTCOL + 2);
+ cmd.addOption("--line", "+l", 1, "[m]ax-length: integer",
+ "maximum line length m (default 4096)");
+
+ cmd.addGroup("output options:");
+ cmd.addSubGroup("output file format:");
+ cmd.addOption("--write-file", "+F", "write file format (default)");
+ cmd.addOption("--write-dataset", "-F", "write data set without file meta information");
+ cmd.addSubGroup("output transfer syntax:");
+ cmd.addOption("--write-xfer-little", "+te", "write with explicit VR little endian (default)");
+ cmd.addOption("--write-xfer-big", "+tb", "write with explicit VR big endian TS");
+ cmd.addOption("--write-xfer-implicit", "+ti", "write with implicit VR little endian TS");
+ cmd.addSubGroup("error handling:");
+ cmd.addOption("--stop-on-error", "-E", "do not write if dump is damaged (default)");
+ cmd.addOption("--ignore-errors", "+E", "attempt to write even if dump is damaged");
+ cmd.addSubGroup("post-1993 value representations:");
+ cmd.addOption("--enable-new-vr", "+u", "enable support for new VRs (UN/UT) (default)");
+ cmd.addOption("--disable-new-vr", "-u", "disable support for new VRs, convert to OB");
+ cmd.addSubGroup("group length encoding:");
+ cmd.addOption("--group-length-recalc", "+g=", "recalculate group lengths if present (default)");
+ cmd.addOption("--group-length-create", "+g", "always write with group length elements");
+ cmd.addOption("--group-length-remove", "-g", "always write without group length elements");
+ cmd.addSubGroup("length encoding in sequences and items:");
+ cmd.addOption("--length-explicit", "+e", "write with explicit lengths (default)");
+ cmd.addOption("--length-undefined", "-e", "write with undefined lengths");
+ cmd.addSubGroup("data set trailing padding (not with --write-dataset):");
+ cmd.addOption("--padding-retain", "-p=", "do not change padding\n(default if not --write-dataset)");
+ cmd.addOption("--padding-off", "-p", "no padding (implicit if --write-dataset)");
+ cmd.addOption("--padding-create", "+p", 2, "[f]ile-pad [i]tem-pad: integer",
+ "align file on multiple of f bytes\nand items on multiple of i bytes");
+
+ int opt_debugMode = 0;
+ const char* ifname = NULL;
+ const char* ofname = NULL;
+ E_TransferSyntax oxfer = EXS_LittleEndianExplicit;
+ E_EncodingType oenctype = EET_ExplicitLength;
+ E_GrpLenEncoding oglenc = EGL_recalcGL;
+ E_PaddingEncoding opadenc = EPD_withoutPadding;
+ OFCmdUnsignedInt opt_filepad = 0;
+ OFCmdUnsignedInt opt_itempad = 0;
+ OFCmdUnsignedInt opt_linelength = DCM_DumpMaxLineSize;
+ OFBool verbosemode = OFFalse;
+ OFBool stopOnErrors = OFTrue;
+ OFBool createFileFormat = OFTrue;
+
+ /* evaluate command line */
+ prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
+ if (app.parseCommandLine(cmd, argc, argv, OFCommandLine::ExpandWildcards))
+ {
+ /* check exclusive options first */
+
+ if (cmd.getParamCount() == 0)
+ {
+ if (cmd.findOption("--version"))
+ {
+ app.printHeader(OFTrue /*print host identifier*/); // uses ofConsole.lockCerr()
+ CERR << endl << "External libraries used:";
+#ifdef WITH_ZLIB
+ CERR << endl << "- ZLIB, Version " << zlibVersion() << endl;
+#else
+ CERR << " none" << endl;
+#endif
+ return 0;
+ }
+ }
+
+ /* command line parameters */
+
+ cmd.getParam(1, ifname);
+ cmd.getParam(2, ofname);
+
+ if (cmd.findOption("--verbose")) verbosemode = OFTrue;
+ if (cmd.findOption("--debug")) opt_debugMode = 5;
+
+ if (cmd.findOption("--line"))
+ {
+ app.checkValue(cmd.getValueAndCheckMin(opt_linelength, 80));
+ }
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--write-file")) createFileFormat = OFTrue;
+ if (cmd.findOption("--write-dataset")) createFileFormat = OFFalse;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--write-xfer-little")) oxfer = EXS_LittleEndianExplicit;
+ if (cmd.findOption("--write-xfer-big")) oxfer = EXS_BigEndianExplicit;
+ if (cmd.findOption("--write-xfer-implicit")) oxfer = EXS_LittleEndianImplicit;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--stop-on-error")) stopOnErrors = OFTrue;
+ if (cmd.findOption("--ignore-errors")) stopOnErrors = OFFalse;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--enable-new-vr"))
+ {
+ dcmEnableUnknownVRGeneration.set(OFTrue);
+ dcmEnableUnlimitedTextVRGeneration.set(OFTrue);
+ }
+ if (cmd.findOption("--disable-new-vr"))
+ {
+ dcmEnableUnknownVRGeneration.set(OFFalse);
+ dcmEnableUnlimitedTextVRGeneration.set(OFFalse);
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--group-length-recalc")) oglenc = EGL_recalcGL;
+ if (cmd.findOption("--group-length-create")) oglenc = EGL_withGL;
+ if (cmd.findOption("--group-length-remove")) oglenc = EGL_withoutGL;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--length-explicit")) oenctype = EET_ExplicitLength;
+ if (cmd.findOption("--length-undefined")) oenctype = EET_UndefinedLength;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--padding-retain"))
+ {
+ if (!createFileFormat) app.printError("--padding-retain not allowed with --write-dataset");
+ opadenc = EPD_noChange;
+ }
+ if (cmd.findOption("--padding-off")) opadenc = EPD_withoutPadding;
+ if (cmd.findOption("--padding-create"))
+ {
+ if (!createFileFormat) app.printError("--padding-create not allowed with --write-dataset");
+ app.checkValue(cmd.getValueAndCheckMin(opt_filepad, 0));
+ app.checkValue(cmd.getValueAndCheckMin(opt_itempad, 0));
+ opadenc = EPD_withPadding;
+ }
+ cmd.endOptionBlock();
+
+ }
+
+ DcmFileFormat fileformat;
+ DcmMetaInfo * metaheader = fileformat.getMetaInfo();
+ DcmDataset * dataset = fileformat.getDataset();
+
+ SetDebugLevel((opt_debugMode));
+
+ /* make sure data dictionary is loaded */
+ if (!dcmDataDict.isDictionaryLoaded()) {
+ CERR << "Warning: no data dictionary loaded, "
+ << "check environment variable: "
+ << DCM_DICT_ENVIRONMENT_VARIABLE << endl;
+ }
+
+ if (verbosemode)
+ COUT << "reading dump file: " << ifname << endl;
+
+ // open input dump file
+ if ((ifname == NULL) || (strlen(ifname) == 0))
+ {
+ CERR << "invalid input filename: <empty string>" << endl;
+ return 1;
+ }
+ FILE * dumpfile = fopen(ifname, "r");
+ if (!dumpfile)
+ {
+ CERR << "input file does not exist: " << ifname << endl;
+ return 1;
+ }
+
+ // read dump file into metaheader and dataset
+ if (readDumpFile(metaheader, dataset, dumpfile, ifname, stopOnErrors,
+ OFstatic_cast(unsigned long, opt_linelength)))
+ {
+ // write into file format or dataset
+ if (verbosemode)
+ COUT << "writing DICOM file" << endl;
+
+ OFCondition l_error = fileformat.saveFile(ofname, oxfer, oenctype, oglenc, opadenc,
+ OFstatic_cast(Uint32, opt_filepad), OFstatic_cast(Uint32, opt_itempad), !createFileFormat);
+
+ if (l_error == EC_Normal)
+ COUT << "dump successfully converted." << endl;
+ else
+ {
+ CERR << "Error: " << l_error.text()
+ << ": writing file: " << ofname << endl;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+//*******************************
+
+/*
+** CVS/RCS Log:
+** $Log: dump2dcm.cc,v $
+** Revision 1.51 2005/12/16 09:07:03 onken
+** - Added variable initialization to avoid compiler warning
+**
+** Revision 1.50 2005/12/08 15:40:50 meichel
+** Changed include path schema for all DCMTK header files
+**
+** Revision 1.49 2004/07/13 09:43:10 meichel
+** Fixed memory leak occuring when raw data is read from file.
+**
+** Revision 1.48 2004/03/05 09:59:00 joergr
+** Avoid wrong warning for LUTData (0028,3006) having a VR of US or SS.
+** Added initial "hooks" for (compressed) pixel items.
+** Added "ignore errors" option (similar to dcmdump).
+**
+** Revision 1.47 2004/01/16 10:53:16 joergr
+** Adapted type casts to new-style typecast operators defined in ofcast.h.
+** Removed acknowledgements with e-mail addresses from CVS log.
+**
+** Revision 1.46 2003/11/05 16:15:27 meichel
+** Removed useless "--write-xfer-same" command line option
+**
+** Revision 1.45 2002/12/05 13:59:29 joergr
+** Fixed typo.
+**
+** Revision 1.44 2002/11/27 12:07:18 meichel
+** Adapted module dcmdata to use of new header file ofstdinc.h
+**
+** Revision 1.43 2002/11/26 08:43:02 meichel
+** Replaced all includes for "zlib.h" with <zlib.h>
+** to avoid inclusion of zlib.h in the makefile dependencies.
+**
+** Revision 1.42 2002/09/23 17:52:04 joergr
+** Prepared code for future support of 'config.guess' host identifiers.
+**
+** Revision 1.41 2002/09/23 13:50:42 joergr
+** Added new command line option "--version" which prints the name and version
+** number of external libraries used.
+**
+** Revision 1.40 2002/08/21 10:14:16 meichel
+** Adapted code to new loadFile and saveFile methods, thus removing direct
+** use of the DICOM stream classes.
+**
+** Revision 1.39 2002/04/16 13:38:55 joergr
+** Added configurable support for C++ ANSI standard includes (e.g. streams).
+**
+** Revision 1.38 2001/12/11 14:00:39 joergr
+** Fixed bug in 'dump2dcm' parser causing AT attribute values to be ignored.
+**
+** Revision 1.37 2001/11/09 15:50:53 joergr
+** Renamed some of the getValue/getParam methods to avoid ambiguities reported
+** by certain compilers.
+**
+** Revision 1.36 2001/09/25 17:21:01 meichel
+** Adapted dcmdata to class OFCondition
+**
+** Revision 1.35 2001/06/01 15:48:30 meichel
+** Updated copyright header
+**
+** Revision 1.34 2000/04/14 15:42:54 meichel
+** Global VR generation flags are now derived from OFGlobal and, thus,
+** safe for use in multi-thread applications.
+**
+** Revision 1.33 2000/03/08 16:26:06 meichel
+** Updated copyright header.
+**
+** Revision 1.32 2000/03/06 18:09:38 joergr
+** Avoid empty statement in the body of if-statements (MSVC6 reports warnings).
+**
+** Revision 1.31 2000/03/03 14:05:16 meichel
+** Implemented library support for redirecting error messages into memory
+** instead of printing them to stdout/stderr for GUI applications.
+**
+** Revision 1.30 2000/02/29 11:48:51 meichel
+** Removed support for VS value representation. This was proposed in CP 101
+** but never became part of the standard.
+**
+** Revision 1.29 2000/02/23 15:11:36 meichel
+** Corrected macro for Borland C++ Builder 4 workaround.
+**
+** Revision 1.28 2000/02/10 16:02:51 joergr
+** Enhanced handling of PixelData/Item element. Externally stored raw data is
+** now always imported as little endian and swapped if necessary. This change
+** reflects the new 'export' feature of dcmdump.
+**
+** Revision 1.27 2000/02/01 10:11:58 meichel
+** Avoiding to include <stdlib.h> as extern "C" on Borland C++ Builder 4,
+** workaround for bug in compiler header files.
+**
+** Revision 1.26 1999/05/03 14:13:40 joergr
+** Minor code purifications to keep Sun CC 2.0.1 quiet.
+**
+** Revision 1.25 1999/04/27 17:50:53 joergr
+** Adapted console applications to new OFCommandLine and OFConsoleApplication
+** functionality.
+**
+** Revision 1.24 1999/04/27 12:23:27 meichel
+** Prevented dcmdata applications from opening a file with empty filename,
+** leads to application crash on Win32.
+**
+** Revision 1.23 1999/03/31 09:24:23 meichel
+** Updated copyright header in module dcmdata
+**
+** Revision 1.22 1999/03/29 10:14:15 meichel
+** Adapted command line options of dcmdata applications to new scheme.
+**
+** Revision 1.21 1999/03/22 16:16:01 meichel
+** dump2dcm now allows to include the contents of binary files
+** as OB/OW values while converting a dump to a DICOM file.
+**
+** Revision 1.20 1999/01/07 14:13:12 meichel
+** Corrected bug in dump2dcm that prevented the correct processing of
+** dumps created with dcmdump if they contained the "internal" VR markers
+** "xs" (US or SS) or "ox" (OB or OW).
+**
+** Revision 1.19 1998/01/27 10:51:27 meichel
+** Removed some unused variables, meaningless const modifiers
+** and unreached statements.
+**
+** Revision 1.18 1998/01/14 14:41:15 hewett
+** Modified existing -u command line option to also disable generation
+** of UT and VS (previously just disabled generation of UN).
+**
+** Revision 1.17 1997/08/05 07:34:54 andreas
+** Corrected Error handling of SQ in dump2dcm
+**
+** Revision 1.16 1997/07/21 07:59:02 andreas
+** - Deleted support for DcmPixelItems and DcmPixelSequences in dump2dcm
+** ToDo: New support should be added in the future compatible to
+** the new DcmPixel class.
+** - Replace all boolean types (BOOLEAN, CTNBOOLEAN, DICOM_BOOL, BOOL)
+** with one unique boolean type OFBool.
+**
+** Revision 1.15 1997/07/03 15:09:40 andreas
+** - removed debugging functions Bdebug() and Edebug() since
+** they write a static array and are not very useful at all.
+** Cdebug and Vdebug are merged since they have the same semantics.
+** The debugging functions in dcmdata changed their interfaces
+** (see dcmdata/include/dcdebug.h)
+**
+** Revision 1.14 1997/05/30 06:44:57 andreas
+** - fixed scanf format problem leading to warnings on 64 bit machines.
+**
+** Revision 1.13 1997/05/29 15:52:52 meichel
+** Added constant for dcmtk release date in dcuid.h.
+** All dcmtk applications now contain a version string
+** which is displayed with the command line options ("usage" message)
+** and which can be queried in the binary with the "ident" command.
+**
+** Revision 1.12 1997/05/22 13:26:25 hewett
+** Modified the test for presence of a data dictionary to use the
+** method DcmDataDictionary::isDictionaryLoaded().
+**
+** Revision 1.11 1997/05/20 07:57:12 andreas
+** - Removed obsolete applications file2ds and ds2file. The functionality of these
+** applications is now peformed by dcmconv. Unified calling parameters
+** are implemented in dump2dcm, dcmdump and dcmconv.
+**
+** Revision 1.10 1997/05/16 08:31:06 andreas
+** - Revised handling of GroupLength elements and support of
+** DataSetTrailingPadding elements. The enumeratio E_GrpLenEncoding
+** got additional enumeration values (for a description see dctypes.h).
+** addGroupLength and removeGroupLength methods are replaced by
+** computeGroupLengthAndPadding. To support Padding, the parameters of
+** element and sequence write functions changed.
+**
+** Revision 1.9 1997/04/18 08:06:56 andreas
+** - Minor corrections: correct some warnings of the SUN-C++ Compiler
+** concerning the assignments of wrong types and inline compiler
+** errors
+** - The put/get-methods for all VRs did not conform to the C++-Standard
+** draft. Some Compilers (e.g. SUN-C++ Compiler, Metroworks
+** CodeWarrier, etc.) create many warnings concerning the hiding of
+** overloaded get methods in all derived classes of DcmElement.
+** So the interface of all value representation classes in the
+** library are changed rapidly, e.g.
+** OFCondition get(Uint16 & value, const unsigned long pos);
+** becomes
+** OFCondition getUint16(Uint16 & value, const unsigned long pos);
+** All (retired) "returntype get(...)" methods are deleted.
+** For more information see dcmdata/include/dcelem.h
+**
+** Revision 1.8 1997/03/27 15:47:25 hewett
+** Added command line switche to allow generation of UN to be
+** disabled (it is enabled by default).
+**
+** Revision 1.7 1996/09/24 16:13:51 hewett
+** Added preliminary support for the Macintosh environment (GUSI library).
+**
+** Revision 1.6 1996/05/02 17:00:23 hewett
+** Corrected program name in usage description.
+**
+** Revision 1.5 1996/05/02 15:55:11 hewett
+** Stopped whitespace being stripped from inside value strings when
+** no [] delimiter present. Now only leading and trailing whitespace
+** is stripped.
+**
+** Revision 1.4 1996/04/27 12:13:01 hewett
+** Corrected bug in last bug-fix. A tag value [some text] was being
+** parsed as an empty string. Now both [] and [some text] appear to
+** work as intended.
+**
+** Revision 1.3 1996/03/22 12:38:44 andreas
+** Correct some mistakes: handling [] as empty string (no value field)
+** handling =Name correct if Name is not correct
+**
+** Revision 1.2 1996/03/12 15:11:39 hewett
+** Added call to prepareCmdLineArgs to enable command line arguments
+** in environments which do not provide them.
+**
+** Revision 1.1 1996/01/29 13:36:38 andreas
+** dump2dcm added convert ASCII descriptions into DICOM files
+**
+**
+*/
Index: trunk/milena/sandbox/fabien/dicom/load.hh
===================================================================
--- trunk/milena/sandbox/fabien/dicom/load.hh (revision 0)
+++ trunk/milena/sandbox/fabien/dicom/load.hh (revision 3375)
@@ -0,0 +1,547 @@
+/*
+ *
+ * Copyright (C) 1994-2005, OFFIS
+ *
+ * This software and supporting documentation were developed by
+ *
+ * Kuratorium OFFIS e.V.
+ * Healthcare Information and Communication Systems
+ * Escherweg 2
+ * D-26121 Oldenburg, Germany
+ *
+ * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY
+ * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
+ * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
+ * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
+ *
+ * Module: dcmdata
+ *
+ * Author: Gerd Ehlers
+ *
+ * Purpose: List the contents of a dicom file
+ *
+ * Last Update: $Author: meichel $
+ * Update Date: $Date: 2005/12/08 15:40:46 $
+ * CVS/RCS Revision: $Revision: 1.55 $
+ * Status: $State: Exp $
+ *
+ * CVS/RCS Log at end of file
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofstream.h"
+#include "dcmtk/dcmdata/dctk.h"
+#include "dcmtk/dcmdata/dcdebug.h"
+#include "dcmtk/dcmdata/cmdlnarg.h"
+#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */
+#include "dcmtk/dcmdata/dcistrmz.h" /* for dcmZlibExpectRFC1950Encoding */
+
+#define INCLUDE_CSTDLIB
+#define INCLUDE_CSTRING
+#include "dcmtk/ofstd/ofstdinc.h"
+
+#ifdef WITH_ZLIB
+#include <zlib.h> /* for zlibVersion() */
+#endif
+
+#define OFFIS_CONSOLE_APPLICATION "dcmdump"
+
+static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
+ OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
+
+#ifdef HAVE_GUSI_H
+ /* needed for Macintosh */
+#include <GUSI.h>
+#include <SIOUX.h>
+#endif
+
+static int dumpFile(ostream & out,
+ const char *ifname,
+ const E_FileReadMode readMode,
+ const E_TransferSyntax xfer,
+ const size_t printFlags,
+ const OFBool loadIntoMemory,
+ const OFBool stopOnErrors,
+ const OFBool writePixelData,
+ const char *pixelDirectory);
+
+// ********************************************
+
+static OFBool printAllInstances = OFTrue;
+static OFBool prependSequenceHierarchy = OFFalse;
+static int printTagCount = 0;
+static const int MAX_PRINT_TAG_NAMES = 1024;
+static const char* printTagNames[MAX_PRINT_TAG_NAMES];
+static const DcmTagKey* printTagKeys[MAX_PRINT_TAG_NAMES];
+static OFCmdUnsignedInt maxReadLength = 4096; // default is 4 KB
+
+static OFBool addPrintTagName(const char* tagName)
+{
+ if (printTagCount >= MAX_PRINT_TAG_NAMES) {
+ CERR << "error: too many print Tag options (max: " << MAX_PRINT_TAG_NAMES << ")" << endl;
+ return OFFalse;
+ }
+
+ unsigned int group = 0xffff;
+ unsigned int elem = 0xffff;
+ if (sscanf( tagName, "%x,%x", &group, &elem ) != 2 )
+ {
+ /* it is a name */
+ const DcmDataDictionary& globalDataDict = dcmDataDict.rdlock();
+ const DcmDictEntry *dicent = globalDataDict.findEntry(tagName);
+ if( dicent == NULL ) {
+ CERR << "error: unrecognised tag name: '" << tagName << "'" << endl;
+ dcmDataDict.unlock();
+ return OFFalse;
+ } else {
+ /* note for later */
+ printTagKeys[printTagCount] = new DcmTagKey(dicent->getKey());
+ }
+ dcmDataDict.unlock();
+ } else {
+ /* tag name has format xxxx,xxxx */
+ /* do not lookup in dictionary, tag could be private */
+ printTagKeys[printTagCount] = NULL;
+ }
+
+ printTagNames[printTagCount] = strcpy(OFstatic_cast(char*, malloc(strlen(tagName)+1)), tagName);
+ printTagCount++;
+ return OFTrue;
+}
+
+#define SHORTCOL 3
+#define LONGCOL 20
+
+int main(int argc, char *argv[])
+{
+ int opt_debugMode = 0;
+ OFBool loadIntoMemory = OFTrue;
+ size_t printFlags = DCMTypes::PF_shortenLongTagValues /*| DCMTypes::PF_showTreeStructure*/;
+ OFBool printFilename = OFFalse;
+ OFBool writePixelData = OFFalse;
+ E_FileReadMode readMode = ERM_autoDetect;
+ E_TransferSyntax xfer = EXS_Unknown;
+ OFBool stopOnErrors = OFTrue;
+ const char *current = NULL;
+ const char *pixelDirectory = NULL;
+
+
+#ifdef HAVE_GUSI_H
+ /* needed for Macintosh */
+ /* set options for the Metrowerks CodeWarrior SIOUX console */
+ SIOUXSettings.autocloseonquit = OFFalse;
+ SIOUXSettings.asktosaveonclose = OFFalse;
+ SIOUXSettings.showstatusline = OFTrue;
+ SIOUXSettings.setupmenus = OFTrue;
+ /* set options for the GUSI sockets library */
+ GUSISetup(GUSIwithSIOUXSockets);
+ GUSISetup(GUSIwithInternetSockets);
+#endif
+
+ SetDebugLevel(( 0 ));
+
+ OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Dump DICOM file and data set", rcsid);
+ OFCommandLine cmd;
+ cmd.setOptionColumns(LONGCOL, SHORTCOL);
+ cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
+
+ cmd.addParam("dcmfile-in", "DICOM input filename to be dumped", OFCmdParam::PM_MultiMandatory);
+
+ cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
+ cmd.addOption("--help", "-h", "print this help text and exit");
+ cmd.addOption("--version", "print version information and exit", OFTrue /* exclusive */);
+#ifdef USE_EXPERIMENTAL_QUIET_MODE
+ cmd.addOption("--quiet", "-q", "quiet mode, print no warnings and errors");
+#endif
+ cmd.addOption("--debug", "-d", "debug mode, print debug information");
+
+ cmd.addGroup("input options:");
+ cmd.addSubGroup("input file format:");
+ cmd.addOption("--read-file", "+f", "read file format or data set (default)");
+ cmd.addOption("--read-file-only", "+fo", "read file format only");
+ cmd.addOption("--read-dataset", "-f", "read data set without file meta information");
+ cmd.addSubGroup("input transfer syntax:");
+ cmd.addOption("--read-xfer-auto", "-t=", "use TS recognition (default)");
+ cmd.addOption("--read-xfer-detect", "-td", "ignore TS specified in the file meta header");
+ cmd.addOption("--read-xfer-little", "-te", "read with explicit VR little endian TS");
+ cmd.addOption("--read-xfer-big", "-tb", "read with explicit VR big endian TS");
+ cmd.addOption("--read-xfer-implicit", "-ti", "read with implicit VR little endian TS");
+ cmd.addSubGroup("parsing of odd-length attributes:");
+ cmd.addOption("--accept-odd-length", "+ao", "accept odd length attributes (default)");
+ cmd.addOption("--assume-even-length", "+ae", "assume real length is one byte larger");
+ cmd.addSubGroup("handling of undefined length UN elements:");
+ cmd.addOption("--enable-cp246", "+ui", "read undefined len UN as implicit VR (default)");
+ cmd.addOption("--disable-cp246", "-ui", "read undefined len UN as explicit VR");
+ cmd.addSubGroup("handling of defined length UN elements:");
+ cmd.addOption("--retain-un", "-uc", "retain elements as UN (default)");
+ cmd.addOption("--convert-un", "+uc", "convert to real VR if known");
+ cmd.addSubGroup("automatic data correction:");
+ cmd.addOption("--enable-correction", "+dc", "enable automatic data correction (default)");
+ cmd.addOption("--disable-correction", "-dc", "disable automatic data correction");
+#ifdef WITH_ZLIB
+ cmd.addSubGroup("bitstream format of deflated input:");
+ cmd.addOption("--bitstream-deflated", "+bd", "expect deflated bitstream (default)");
+ cmd.addOption("--bitstream-zlib", "+bz", "expect deflated zlib bitstream");
+#endif
+
+ cmd.addGroup("output options:");
+ cmd.addSubGroup("printing:");
+ cmd.addOption("--load-all", "+M", "load very long tag values (default)");
+ cmd.addOption("--load-short", "-M", "do not load very long values (e.g. pixel data)");
+ cmd.addOption("--max-read-length", "+R", 1, "[k]bytes: integer [4..4194302] (default: 4)",
+ "set threshold for long values to k kbytes");
+ cmd.addOption("--print-all", "+L", "print long tag values completely");
+ cmd.addOption("--print-short", "-L", "print long tag values shortened (default)");
+ cmd.addOption("--print-filename", "+F", "print header with filename for each input file");
+
+ cmd.addSubGroup("error handling:");
+ cmd.addOption("--stop-on-error", "-E", "do not print if file is damaged (default)");
+ cmd.addOption("--ignore-errors", "+E", "attempt to print even if file is damaged");
+
+ cmd.addSubGroup("searching:");
+ cmd.addOption("--search", "+P", 1, "[t]ag: \"xxxx,xxxx\" or a data dictionary name",
+ "print the value of tag t\nthis option can be specified multiple times\n(default: the complete file is printed)");
+
+ cmd.addOption("--search-all", "+s", "print all instances of searched tags (default)");
+ cmd.addOption("--search-first", "-s", "only print first instance of searched tags");
+
+ cmd.addOption("--prepend", "+p", "prepend sequence hierarchy to printed tag,\ndenoted by: (xxxx,xxxx).(xxxx,xxxx).*\n(only with --search-all or --search-first)");
+ cmd.addOption("--no-prepend", "-p", "do not prepend hierarchy to tag (default)");
+
+ cmd.addSubGroup("writing:");
+ cmd.addOption("--write-pixel", "+W", 1, "[d]irectory : string",
+ "write pixel data to a .raw file stored in d\n(little endian, filename created automatically)");
+
+ /* evaluate command line */
+ prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
+ if (app.parseCommandLine(cmd, argc, argv, OFCommandLine::ExpandWildcards))
+ {
+ /* check exclusive options first */
+
+ if (cmd.getParamCount() == 0)
+ {
+ if (cmd.findOption("--version"))
+ {
+ app.printHeader(OFTrue /*print host identifier*/); // uses ofConsole.lockCerr()
+ CERR << endl << "External libraries used:";
+#ifdef WITH_ZLIB
+ CERR << endl << "- ZLIB, Version " << zlibVersion() << endl;
+#else
+ CERR << " none" << endl;
+#endif
+ return 0;
+ }
+ }
+
+ /* options */
+
+#ifdef USE_EXPERIMENTAL_QUIET_MODE
+ if (cmd.findOption("--quiet"))
+ {
+ // tbd: disable ofConsole output!
+ app.setQuietMode();
+ }
+#endif
+ if (cmd.findOption("--debug")) opt_debugMode = 5;
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--read-file")) readMode = ERM_autoDetect;
+ if (cmd.findOption("--read-file-only")) readMode = ERM_fileOnly;
+ if (cmd.findOption("--read-dataset")) readMode = ERM_dataset;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--read-xfer-auto"))
+ xfer = EXS_Unknown;
+ if (cmd.findOption("--read-xfer-detect"))
+ dcmAutoDetectDatasetXfer.set(OFTrue);
+ if (cmd.findOption("--read-xfer-little"))
+ {
+ app.checkDependence("--read-xfer-little", "--read-dataset", readMode == ERM_dataset);
+ xfer = EXS_LittleEndianExplicit;
+ }
+ if (cmd.findOption("--read-xfer-big"))
+ {
+ app.checkDependence("--read-xfer-big", "--read-dataset", readMode == ERM_dataset);
+ xfer = EXS_BigEndianExplicit;
+ }
+ if (cmd.findOption("--read-xfer-implicit"))
+ {
+ app.checkDependence("--read-xfer-implicit", "--read-dataset", readMode == ERM_dataset);
+ xfer = EXS_LittleEndianImplicit;
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--accept-odd-length"))
+ {
+ dcmAcceptOddAttributeLength.set(OFTrue);
+ }
+ if (cmd.findOption("--assume-even-length"))
+ {
+ dcmAcceptOddAttributeLength.set(OFFalse);
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--enable-cp246"))
+ {
+ dcmEnableCP246Support.set(OFTrue);
+ }
+ if (cmd.findOption("--disable-cp246"))
+ {
+ dcmEnableCP246Support.set(OFFalse);
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--retain-un"))
+ {
+ dcmEnableUnknownVRConversion.set(OFFalse);
+ }
+ if (cmd.findOption("--convert-un"))
+ {
+ dcmEnableUnknownVRConversion.set(OFTrue);
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--enable-correction"))
+ {
+ dcmEnableAutomaticInputDataCorrection.set(OFTrue);
+ }
+ if (cmd.findOption("--disable-correction"))
+ {
+ dcmEnableAutomaticInputDataCorrection.set(OFFalse);
+ }
+ cmd.endOptionBlock();
+
+#ifdef WITH_ZLIB
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--bitstream-deflated"))
+ {
+ dcmZlibExpectRFC1950Encoding.set(OFFalse);
+ }
+ if (cmd.findOption("--bitstream-zlib"))
+ {
+ dcmZlibExpectRFC1950Encoding.set(OFTrue);
+ }
+ cmd.endOptionBlock();
+#endif
+
+ if (cmd.findOption("--max-read-length"))
+ {
+ app.checkValue(cmd.getValueAndCheckMinMax(maxReadLength, 4, 4194302));
+ maxReadLength *= 1024; // convert kbytes to bytes
+ }
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--load-all")) loadIntoMemory = OFTrue;
+ if (cmd.findOption("--load-short")) loadIntoMemory = OFFalse;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--print-all")) printFlags &= ~DCMTypes::PF_shortenLongTagValues;
+ if (cmd.findOption("--print-short")) printFlags |= DCMTypes::PF_shortenLongTagValues;
+ cmd.endOptionBlock();
+
+ if (cmd.findOption("--print-filename"))
+ printFilename = OFTrue;
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--stop-on-error")) stopOnErrors = OFTrue;
+ if (cmd.findOption("--ignore-errors")) stopOnErrors = OFFalse;
+ cmd.endOptionBlock();
+
+ if (cmd.findOption("--search", 0, OFCommandLine::FOM_First))
+ {
+ do
+ {
+ app.checkValue(cmd.getValue(current));
+ if (!addPrintTagName(current)) return 1;
+ } while (cmd.findOption("--search", 0, OFCommandLine::FOM_Next));
+ }
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--search-all"))
+ {
+ app.checkDependence("--search-all", "--search", printTagCount>0);
+ printAllInstances = OFTrue;
+ }
+ if (cmd.findOption("--search-first"))
+ {
+ app.checkDependence("--search-first", "--search", printTagCount>0);
+ printAllInstances = OFFalse;
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--prepend"))
+ {
+ app.checkDependence("--prepend", "--search", printTagCount>0);
+ prependSequenceHierarchy = OFTrue;
+ }
+ if (cmd.findOption("--no-prepend"))
+ {
+ app.checkDependence("--no-prepend", "--search", printTagCount>0);
+ prependSequenceHierarchy = OFFalse;
+ }
+ cmd.endOptionBlock();
+
+ if (cmd.findOption("--write-pixel"))
+ {
+ app.checkValue(cmd.getValue(pixelDirectory));
+ writePixelData = OFTrue;
+ }
+ }
+
+ SetDebugLevel((opt_debugMode));
+
+ /* make sure data dictionary is loaded */
+ if (!dcmDataDict.isDictionaryLoaded())
+ {
+ CERR << "Warning: no data dictionary loaded, "
+ << "check environment variable: "
+ << DCM_DICT_ENVIRONMENT_VARIABLE;
+ }
+
+ int errorCount = 0;
+ int count = cmd.getParamCount();
+ for (int i=1; i<=count; i++)
+ {
+ cmd.getParam(i, current);
+ if (printFilename)
+ {
+ /* a newline separates two consecutive "dumps" */
+ if (i > 1)
+ COUT << endl;
+ /* print header with filename */
+ COUT << "# " << OFFIS_CONSOLE_APPLICATION << " (" << i << "/" << count << "): " << current << endl;
+ }
+ errorCount += dumpFile(COUT, current, readMode, xfer, printFlags, loadIntoMemory, stopOnErrors,
+ writePixelData, pixelDirectory);
+ }
+
+ return errorCount;
+}
+
+static void printResult(ostream& out, DcmStack& stack, size_t printFlags)
+{
+ unsigned long n = stack.card();
+ if (n == 0) {
+ return;
+ }
+
+ if (prependSequenceHierarchy) {
+ /* print the path leading up to the top stack elem */
+ for (unsigned long i=n-1; i>=1; i--) {
+ DcmObject *dobj = stack.elem(i);
+ /* do not print if a DCM_Item as this is not
+ * very helpful to distinguish instances.
+ */
+ if (dobj != NULL && dobj->getTag().getXTag() != DCM_Item) {
+ char buf[512];
+ sprintf(buf, "(%x,%x).",
+ OFstatic_cast(unsigned, dobj->getGTag()),
+ OFstatic_cast(unsigned, dobj->getETag()));
+ out << buf;
+ }
+ }
+ }
+
+ /* print the tag and its value */
+ DcmObject *dobj = stack.top();
+ dobj->print(out, printFlags);
+}
+
+static int dumpFile(ostream & out,
+ const char *ifname,
+ const E_FileReadMode readMode,
+ const E_TransferSyntax xfer,
+ const size_t printFlags,
+ const OFBool loadIntoMemory,
+ const OFBool stopOnErrors,
+ const OFBool writePixelData,
+ const char *pixelDirectory)
+{
+ int result = 0;
+
+ if ((ifname == NULL) || (strlen(ifname) == 0))
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION << ": invalid filename: <empty string>" << endl;
+ return 1;
+ }
+
+ DcmFileFormat dfile;
+ DcmObject *dset = &dfile;
+
+ if (readMode == ERM_dataset) dset = dfile.getDataset();
+
+ // Load file
+
+ OFCondition cond = dfile.loadFile(ifname, xfer, EGL_noChange, maxReadLength, readMode);
+
+ // Read error
+
+ if (! cond.good())
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION << ": error: " << dfile.error().text()
+ << ": reading file: "<< ifname << endl;
+
+ result = 1;
+ if (stopOnErrors) return result;
+ }
+
+ if (loadIntoMemory) dfile.loadAllDataIntoMemory();
+
+ if (printTagCount == 0)
+ {
+ if (writePixelData)
+ {
+ OFString str = ifname;
+ OFString rname = pixelDirectory;
+ if ((rname.length() > 0) && (rname[rname.length() - 1] != PATH_SEPARATOR))
+ rname += PATH_SEPARATOR;
+ size_t pos = str.find_last_of(PATH_SEPARATOR);
+ if (pos == OFString_npos)
+ rname += str;
+ else
+ rname += str.substr(pos + 1);
+ size_t counter = 0;
+ dset->print(out, printFlags, 0 /*level*/, rname.c_str(), &counter);
+ } else
+ dset->print(out, printFlags);
+ } else {
+ /* only print specified tags */
+ for (int i=0; i<printTagCount; i++)
+ {
+ unsigned int group = 0xffff;
+ unsigned int elem = 0xffff;
+ DcmTagKey searchKey;
+ const char* tagName = printTagNames[i];
+ if (printTagKeys[i]) searchKey = *printTagKeys[i];
+ else if (sscanf( tagName, "%x,%x", &group, &elem ) == 2 ) searchKey.set(group, elem);
+ else {
+ CERR << "Internal ERROR in File " << __FILE__ << ", Line "
+ << __LINE__ << endl
+ << "-- Named tag inconsistency" << endl;
+ abort();
+ }
+
+ DcmStack stack;
+ if (dset->search(searchKey, stack, ESM_fromHere, OFTrue) == EC_Normal)
+ {
+ printResult(out, stack, printFlags);
+ if (printAllInstances)
+ {
+ while (dset->search(searchKey, stack, ESM_afterStackTop, OFTrue) == EC_Normal)
+ printResult(out, stack, printFlags);
+ }
+ }
+ }
+ }
+
+ return result;
+}
1
0
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-02-13 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Add unit test for n_max.hh.
* mln/labeling/all.hh: Update for n_max.hh
* tests/labeling/Makefile.am: Update for n_max.cc
* tests/labeling/n_max.cc: Unit test for n_max().
---
mln/labeling/all.hh | 1
tests/labeling/Makefile.am | 2 +
tests/labeling/n_max.cc | 70 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+)
Index: trunk/milena/tests/labeling/n_max.cc
===================================================================
--- trunk/milena/tests/labeling/n_max.cc (revision 0)
+++ trunk/milena/tests/labeling/n_max.cc (revision 3374)
@@ -0,0 +1,70 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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.
+
+/// \file tests/labeling/n_max.cc
+///
+/// Test on mln::labeling::n_max.
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/value/label_16.hh>
+
+#include <mln/labeling/flat_zones.hh>
+#include <mln/labeling/compute.hh>
+#include <mln/labeling/n_max.hh>
+
+#include <mln/fun/v2b/threshold.hh>
+#include <mln/level/transform.hh>
+
+#include <mln/accu/count.hh>
+
+#include <mln/io/pgm/all.hh>
+
+#include "tests/data.hh"
+
+
+int main()
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::label_16;
+
+ image2d<int_u8> lena = io::pgm::load<int_u8>(MLN_IMG_DIR "/lena.pgm");
+
+ image2d<bool> threshold = level::transform(lena, fun::v2b::threshold<int_u8>(100));
+ label_16 nlabels;
+ image2d<label_16> labels = labeling::flat_zones(threshold, c4(), nlabels);
+ accu::count<int_u8> a_;
+
+ util::array<unsigned> a = labeling::compute(a_, threshold, labels, nlabels);
+ util::array<label_16> arr_big = labeling::n_max<label_16>(a, 3);
+
+ mln_assertion(arr_big[1] == 4);
+ mln_assertion(arr_big[2] == 6);
+ mln_assertion(arr_big[3] == 323);
+}
Index: trunk/milena/tests/labeling/Makefile.am
===================================================================
--- trunk/milena/tests/labeling/Makefile.am (revision 3373)
+++ trunk/milena/tests/labeling/Makefile.am (revision 3374)
@@ -10,6 +10,7 @@
flat_zones \
foreground \
level \
+ n_max \
regional_maxima \
regional_minima \
relabel
@@ -21,6 +22,7 @@
flat_zones_SOURCES = flat_zones.cc
foreground_SOURCES = foreground.cc
level_SOURCES = level.cc
+n_max_SOURCES = n_max.cc
regional_maxima_SOURCES = regional_maxima.cc
regional_minima_SOURCES = regional_minima.cc
relabel_SOURCES = relabel.cc
Index: trunk/milena/mln/labeling/all.hh
===================================================================
--- trunk/milena/mln/labeling/all.hh (revision 3373)
+++ trunk/milena/mln/labeling/all.hh (revision 3374)
@@ -60,6 +60,7 @@
# include <mln/labeling/flat_zones.hh>
# include <mln/labeling/foreground.hh>
# include <mln/labeling/level.hh>
+# include <mln/labeling/n_max.hh>
# include <mln/labeling/regional_maxima.hh>
# include <mln/labeling/regional_minima.hh>
1
0
https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Fix labeling fill holes and add a 3D ball window.
* mln/labeling/fill_holes.hh: Fix.
* mln/labeling/all.hh: Update.
* tests/labeling/fill_holes.cc: New.
* tests/labeling/Makefile.am: Update.
* mln/win/ball3d.hh: New.
* mln/win/all.hh: Update.
mln/labeling/all.hh | 4 ++-
mln/labeling/fill_holes.hh | 14 +++++-----
mln/win/all.hh | 11 ++++----
mln/win/ball3d.hh | 41 ++++++++++++++++----------------
tests/labeling/Makefile.am | 2 +
tests/labeling/fill_holes.cc | 55 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 94 insertions(+), 33 deletions(-)
Index: mln/win/ball3d.hh
--- mln/win/ball3d.hh (revision 3368)
+++ mln/win/ball3d.hh (working copy)
@@ -1,5 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
-// (LRDE)
+// Copyright (C) 2007, 2008, 2009 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -26,39 +26,39 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_WIN_DISK2D_HH
-# define MLN_WIN_DISK2D_HH
+#ifndef MLN_WIN_BALL3D_HH
+# define MLN_WIN_BALL3D_HH
-/// \file mln/win/disk2d.hh
+/// \file mln/win/ball3d.hh
///
-/// Definition of the mln::win::disk2d window.
+/// Definition of the mln::win::ball3d window.
# include <mln/core/internal/classical_window_base.hh>
-# include <mln/core/alias/dpoint2d.hh>
+# include <mln/core/alias/dpoint3d.hh>
namespace mln
{
- mln_internal_add_classical_window_trait(disk2d);
+ mln_internal_add_classical_window_trait(ball3d);
namespace win
{
- /*! \brief Disk window defined on the 2D square grid.
+ /*! \brief Ball (sphere) window defined on the 3D square grid.
*
- * A disk2d is centered and symmetric.
+ * A ball3d is centered and symmetric.
*
*/
- struct disk2d : public internal::classical_window_base< dpoint2d, disk2d >
+ struct ball3d : public internal::classical_window_base< dpoint3d, ball3d >
{
/*! \brief Constructor.
*
* \param[in] length Length, thus diameter.
*
*/
- disk2d(unsigned length);
+ ball3d(unsigned length);
/*! \brief Give the disk diameter.
*/
@@ -80,7 +80,7 @@
# ifndef MLN_INCLUDE_ONLY
inline
- disk2d::disk2d(unsigned length)
+ ball3d::ball3d(unsigned length)
: length_(length)
{
mln_precondition(length % 2 == 1);
@@ -90,26 +90,27 @@
r2 = static_cast<def::coord>(r * r);
for (def::coord a = minus_r; a <= r; ++a)
for (def::coord b = minus_r; b <= r; ++b)
- if (a * a + b * b <= r2)
- insert(dpoint2d(a, b));
+ for (def::coord c = minus_r; c <= r; ++c)
+ if (a * a + b * b + c * c <= r2)
+ insert(dpoint3d(a, b, c));
}
inline
- unsigned disk2d::length() const
+ unsigned ball3d::length() const
{
return length_;
}
inline
- unsigned disk2d::delta_() const
+ unsigned ball3d::delta_() const
{
return length_ / 2;
}
inline
- void disk2d::print_(std::ostream& ostr) const
+ void ball3d::print_(std::ostream& ostr) const
{
- ostr << "[disk2d: length=" << length_ << ']';
+ ostr << "[ball3d: length=" << length_ << ']';
}
# endif // ! MLN_INCLUDE_ONLY
@@ -120,4 +121,4 @@
-#endif // ! MLN_WIN_DISK2D_HH
+#endif // ! MLN_WIN_BALL3D_HH
Property changes on: mln/win/ball3d.hh
___________________________________________________________________
Added: svn:mergeinfo
Index: mln/win/all.hh
--- mln/win/all.hh (revision 3372)
+++ mln/win/all.hh (working copy)
@@ -1,4 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+// Copyright (C) 2007, 2008 EPITA, 2009 Research and Development
+// Laboratory (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -28,10 +29,9 @@
#ifndef MLN_WIN_ALL_HH
# define MLN_WIN_ALL_HH
-/*! \file mln/win/all.hh
- *
- * \brief File that includes all win-related routines.
- */
+/// \file mln/win/all.hh
+///
+/// File that includes all win-related routines.
namespace mln
@@ -46,6 +46,7 @@
// Types.
# include <mln/win/backdiag2d.hh>
+# include <mln/win/ball3d.hh>
# include <mln/win/cube3d.hh>
# include <mln/win/cuboid3d.hh>
# include <mln/win/diag2d.hh>
Index: mln/labeling/all.hh
--- mln/labeling/all.hh (revision 3372)
+++ mln/labeling/all.hh (working copy)
@@ -1,4 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+// Copyright (C) 2007, 2008, 2009 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -55,6 +56,7 @@
# include <mln/labeling/background.hh>
# include <mln/labeling/blobs.hh>
# include <mln/labeling/compute.hh>
+# include <mln/labeling/fill_holes.hh>
# include <mln/labeling/flat_zones.hh>
# include <mln/labeling/foreground.hh>
# include <mln/labeling/level.hh>
Index: mln/labeling/fill_holes.hh
--- mln/labeling/fill_holes.hh (revision 3372)
+++ mln/labeling/fill_holes.hh (working copy)
@@ -36,10 +36,9 @@
# include <mln/labeling/background.hh>
# include <mln/labeling/compute.hh>
+# include <mln/core/image/image_if.hh>
# include <mln/accu/count.hh>
-# include <mln/value/int_u8.hh>
-
namespace mln
{
@@ -81,19 +80,20 @@
mln_precondition(exact(input).is_valid());
mln_precondition(exact(nbh).is_valid());
- using value::int_u8;
-
mln_ch_value(I, bool) output;
initialize(output, input);
data::fill(output, false);
- accu::count<int_u8> a_;
mln_ch_value(I, L) lbls = labeling::background(input, nbh, nlabels);
+
+ accu::count<mln_value(I)> a_;
util::array<unsigned> arr = labeling::compute(a_, input, lbls, nlabels);
+
int bg_count = 0;
int bg_lbl = 0;
- for (int i = 0; i < arr.nelements(); ++i)
+ // We start at 1 to ignore the object.
+ for (int i = 1; i < arr.nelements(); ++i)
{
if (arr[i] > bg_count)
{
@@ -102,7 +102,7 @@
}
}
- data::fill((output | pw::value(lbls) != bg_lbl).rw(), true);
+ data::fill((output | (pw::value(lbls) != bg_lbl)).rw(), true);
trace::exiting("labeling::fill_holes");
return output;
Index: tests/labeling/fill_holes.cc
--- tests/labeling/fill_holes.cc (revision 0)
+++ tests/labeling/fill_holes.cc (revision 0)
@@ -0,0 +1,55 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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.
+
+/// \file tests/labeling/fill_holes.cc
+///
+/// Test on mln::labeling::fill_holes.
+
+#include <mln/core/image/image2d.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/labeling/fill_holes.hh>
+#include <mln/value/label_8.hh>
+
+#include <mln/debug/println.hh>
+#include <mln/io/pbm/save.hh>
+
+#include "tests/data.hh"
+
+
+int main()
+{
+ using namespace mln;
+
+ image2d<bool> pic = io::pbm::load(MLN_IMG_DIR "/picasso.pbm");
+ debug::println(pic);
+ value::label_8 n;
+ image2d<bool> out = labeling::fill_holes(pic, c4(), n);
+ debug::println(out);
+ io::pbm::save(out, "out.pbm");
+// mln_assertion(n == 33);
+}
Index: tests/labeling/Makefile.am
--- tests/labeling/Makefile.am (revision 3372)
+++ tests/labeling/Makefile.am (working copy)
@@ -6,6 +6,7 @@
background \
blobs \
compute \
+ fill_holes \
flat_zones \
foreground \
level \
@@ -16,6 +17,7 @@
background_SOURCES = background.cc
blobs_SOURCES = blobs.cc
compute_SOURCES = compute.cc
+fill_holes_SOURCES = fill_holes.cc
flat_zones_SOURCES = flat_zones.cc
foreground_SOURCES = foreground.cc
level_SOURCES = level.cc
1
0
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add source for command executables.
* theo/igr/dump2pgm.cc: Move and rename as...
* theo/exec/dump2pnm.cc: ...this.
Update to also handle pbm and ppm.
* theo/igr/pgms2dump.cc: Move and rename as...
* theo/exec/pnms2dump.cc: ...this.
Update to also handle pbm and ppm.
* theo/exec/clean_holes.cc: New.
* theo/exec/threshold_low.cc: New.
* theo/exec/dump2cloud.cc: New.
* theo/exec/closing_area.cc: New.
* theo/exec/closing_isotropic.cc: New.
clean_holes.cc | 66 +++++++++++++++++++++++++++++++++++++++++++
closing_area.cc | 60 +++++++++++++++++++++++++++++++++++++++
closing_isotropic.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++++
dump2cloud.cc | 34 ++++++++++++++++++++++
dump2pnm.cc | 77 +++++++++++++++++++++++++++++++++++++++++++++------
pnms2dump.cc | 71 +++++++++++++++++++++++++++++++++++++++++++----
threshold_low.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 433 insertions(+), 15 deletions(-)
Index: theo/exec/clean_holes.cc
--- theo/exec/clean_holes.cc (revision 0)
+++ theo/exec/clean_holes.cc (revision 0)
@@ -0,0 +1,66 @@
+#include "filetype.hh"
+
+#include <mln/value/label_16.hh>
+#include <mln/labeling/fill_holes.hh>
+#include <mln/logical/not.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.xxx output.xxx" << std::endl
+ << " Clean holes." << std::endl
+ << " xxx is pbm (2D) or dump (3D)." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 3)
+ usage(argv);
+
+ trace::entering("main");
+
+ std::string filename = argv[1];
+
+ switch (get_filetype(argv[1]))
+ {
+ case filetype::pbm:
+ {
+ image2d<bool> ima, out;
+ io::pbm::load(ima, argv[1]);
+ value::label_16 n;
+ out = labeling::fill_holes(ima, c4(), n);
+ out = labeling::fill_holes(logical::not_(out), c4(), n);
+ io::pbm::save(out, argv[2]);
+ }
+ break;
+
+ case filetype::dump:
+ {
+ image3d<bool> ima, out;
+ io::dump::load(ima, argv[1]);
+ value::label_16 n;
+ out = labeling::fill_holes(ima, c6(), n);
+ out = labeling::fill_holes(logical::not_(out), c6(), n);
+ io::dump::save(out, argv[2]);
+ }
+ break;
+
+ case filetype::unknown:
+ std::cerr << "unknown filename extension!" << std::endl;
+ usage(argv);
+ break;
+
+ default:
+ std::cerr << "file type not handled!" << std::endl;
+ usage(argv);
+ }
+
+ trace::exiting("main");
+}
Index: theo/exec/threshold_low.cc
--- theo/exec/threshold_low.cc (revision 0)
+++ theo/exec/threshold_low.cc (revision 0)
@@ -0,0 +1,69 @@
+#include "filetype.hh"
+
+#include <mln/core/routine/duplicate.hh>
+#include <mln/pw/all.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.xxx low output.xxx" << std::endl
+ << " Low threshold." << std::endl
+ << " xxx is pbm (2D) or dump (3D)." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 4)
+ usage(argv);
+
+
+ trace::entering("main");
+
+ std::string filename = argv[1];
+
+ int low = std::atoi(argv[2]);
+ if (low < 0 || low > 255)
+ {
+ std::cerr << "bad threshold!" << std::endl;
+ usage(argv);
+ }
+
+
+
+ switch (get_filetype(argv[1]))
+ {
+ case filetype::pgm:
+ {
+ image2d<int_u8> ima;
+ io::pgm::load(ima, argv[1]);
+ io::pbm::save(duplicate((pw::value(ima) < pw::cst(low)) | ima.domain()), argv[3]);
+ }
+ break;
+
+ case filetype::dump:
+ {
+ image3d<int_u8> ima;
+ io::dump::load(ima, argv[1]);
+ io::dump::save(duplicate((pw::value(ima) < pw::cst(low)) | ima.domain()), argv[3]);
+ }
+ break;
+
+ case filetype::unknown:
+ std::cerr << "unknown filename extension!" << std::endl;
+ usage(argv);
+ break;
+
+ default:
+ std::cerr << "file type not handled!" << std::endl;
+ usage(argv);
+ }
+
+ trace::exiting("main");
+}
Index: theo/exec/dump2cloud.cc
--- theo/exec/dump2cloud.cc (revision 0)
+++ theo/exec/dump2cloud.cc (revision 0)
@@ -0,0 +1,34 @@
+#include "filetype.hh"
+
+#include <mln/io/cloud/save.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.dump output.txt" << std::endl
+ << " Dump (binary, 3D) to cloud." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+
+ if (argc != 3)
+ usage(argv);
+
+ trace::entering("main");
+
+ std::string filename = argv[1];
+
+ image3d<bool> vol;
+ io::dump::load(vol, argv[1]);
+ p_array<point3d> arr;
+ convert::from_to(vol, arr);
+ io::cloud::save(arr, argv[2]);
+
+ trace::exiting("main");
+}
Index: theo/exec/dump2pnm.cc
--- theo/exec/dump2pnm.cc (revision 3368)
+++ theo/exec/dump2pnm.cc (working copy)
@@ -1,17 +1,15 @@
+#include "filetype.hh"
-#include <mln/core/image/image2d.hh>
-#include <mln/make/image3d.hh>
+#include <mln/literal/black.hh>
#include <mln/debug/slices_2d.hh>
-#include <mln/value/int_u8.hh>
-#include <mln/io/dump/load.hh>
-#include <mln/io/pgm/save.hh>
-
void usage(char* argv[])
{
- std::cerr << "usage: " << argv[0] << " input.dump output.pgm" << std::endl;
+ std::cerr << "usage: " << argv[0] << " input.dump output.pnm" << std::endl;
+ std::cerr << " It works with binary (pbm), gray-level (int_u8), and color (rgb8) images." << std::endl;
+ std::cerr << " Sample use: binary input.dump -> output.pbm" << std::endl;
abort();
}
@@ -20,15 +18,76 @@
int main(int argc, char* argv[])
{
using namespace mln;
- using value::int_u8;
if (argc != 3)
usage(argv);
- image3d<int_u8> vol;
+ trace::entering("main");
+
+ std::string filename = argv[2];
+
+ switch (get_filetype(argv[2]))
+ {
+ case filetype::pbm:
+ {
+ image3d<bool> vol;
io::dump::load(vol, argv[1]);
+ bool bg = false;
+ image2d<bool> ima = debug::slices_2d(vol, 1.f, bg);
+ io::pbm::save(ima, argv[2]);
+ }
+ break;
+ case filetype::pgm:
+ {
+ using value::int_u8;
+ image3d<int_u8> vol;
+ io::dump::load(vol, argv[1]);
int_u8 bg = 0;
image2d<int_u8> ima = debug::slices_2d(vol, 1.f, bg);
io::pgm::save(ima, argv[2]);
}
+ break;
+
+ case filetype::ppm:
+ {
+ using value::rgb8;
+ image3d<rgb8> vol;
+ io::dump::load(vol, argv[1]);
+ rgb8 bg = literal::black;
+ image2d<rgb8> ima = debug::slices_2d(vol, 1.f, bg);
+ io::ppm::save(ima, argv[2]);
+ }
+ break;
+
+ case filetype::dump:
+ {
+ std::cerr << "Output shall not be a dump file!" << std::endl;
+ usage(argv);
+ }
+ break;
+
+ case filetype::unknown:
+ std::cerr << "unknown filename extension!" << std::endl;
+ usage(argv);
+ break;
+
+ default:
+ std::cerr << "file type not handled!" << std::endl;
+ usage(argv);
+ }
+
+ trace::exiting("main");
+
+
+
+
+// using namespace mln;
+// using value::int_u8;
+
+// if (argc != 3)
+// usage(argv);
+
+// std::string filename = argv[2];
+
+}
Property changes on: theo/exec/dump2pnm.cc
___________________________________________________________________
Added: svn:mergeinfo
Index: theo/exec/pnms2dump.cc
--- theo/exec/pnms2dump.cc (revision 3368)
+++ theo/exec/pnms2dump.cc (working copy)
@@ -1,16 +1,14 @@
+#include "filetype.hh"
-#include <mln/core/image/image2d.hh>
#include <mln/make/image3d.hh>
-#include <mln/value/int_u8.hh>
-#include <mln/io/pgm/load.hh>
-#include <mln/io/dump/save.hh>
void usage(char* argv[])
{
- std::cerr << "usage: " << argv[0] << " output.dump input1.pgm .. inputn.pgm" << std::endl;
+ std::cerr << "usage: " << argv[0] << " output.dump input1.xxx .. inputn.xxx" << std::endl;
+ std::cerr << " It works with binary (pbm), gray-level (int_u8), and color (rgb8) images." << std::endl;
abort();
}
@@ -20,12 +18,35 @@
{
using namespace mln;
using value::int_u8;
- typedef image2d<int_u8> I;
if (argc < 3)
usage(argv);
+ trace::entering("main");
+
+ std::string filename = argv[2];
+ switch (get_filetype(argv[2]))
+ {
+ case filetype::pbm:
+ {
+ typedef image2d<bool> I;
+ util::array<I> arr;
+ for (int i = 2; i < argc; ++i)
+ {
+ I ima;
+ io::pbm::load(ima, argv[i]);
+ arr.append(ima);
+ }
+ image3d<bool> vol = make::image3d(arr);
+ io::dump::save(vol, argv[1]);
+ }
+ break;
+
+ case filetype::pgm:
+ {
+ using value::int_u8;
+ typedef image2d<int_u8> I;
util::array<I> arr;
for (int i = 2; i < argc; ++i)
{
@@ -36,3 +57,41 @@
image3d<int_u8> vol = make::image3d(arr);
io::dump::save(vol, argv[1]);
}
+ break;
+
+ case filetype::ppm:
+ {
+ using value::rgb8;
+ typedef image2d<rgb8> I;
+ util::array<I> arr;
+ for (int i = 2; i < argc; ++i)
+ {
+ I ima;
+ io::ppm::load(ima, argv[i]);
+ arr.append(ima);
+ }
+ image3d<rgb8> vol = make::image3d(arr);
+ io::dump::save(vol, argv[1]);
+ }
+ break;
+
+ case filetype::dump:
+ {
+ std::cerr << "Output shall not be a dump file!" << std::endl;
+ usage(argv);
+ }
+ break;
+
+ case filetype::unknown:
+ std::cerr << "unknown filename extension!" << std::endl;
+ usage(argv);
+ break;
+
+ default:
+ std::cerr << "file type not handled!" << std::endl;
+ usage(argv);
+ }
+
+ trace::exiting("main");
+
+}
Property changes on: theo/exec/pnms2dump.cc
___________________________________________________________________
Added: svn:mergeinfo
Index: theo/exec/closing_area.cc
--- theo/exec/closing_area.cc (revision 0)
+++ theo/exec/closing_area.cc (revision 0)
@@ -0,0 +1,60 @@
+#include "filetype.hh"
+#include <mln/morpho/closing_area.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.xxx lambda output.xxx" << std::endl
+ << " Area closing." << std::endl
+ << " xxx in { pgm, dump }" << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 4)
+ usage(argv);
+
+ trace::entering("main");
+
+ std::string filename = argv[1];
+ unsigned lambda = atoi(argv[2]);
+
+ switch (get_filetype(argv[1]))
+ {
+ case filetype::pgm:
+ {
+ image2d<int_u8> ima, clo;
+ io::pgm::load(ima, argv[1]);
+ clo = morpho::closing_area(ima, c4(), lambda);
+ io::pgm::save(clo, argv[3]);
+ }
+ break;
+
+ case filetype::dump:
+ {
+ image3d<int_u8> ima, clo;
+ io::dump::load(ima, argv[1]);
+ clo = morpho::closing_area(ima, c6(), lambda);
+ io::dump::save(clo, argv[3]);
+ }
+ break;
+
+ case filetype::unknown:
+ std::cerr << "unknown filename extension!" << std::endl;
+ usage(argv);
+ break;
+
+ default:
+ std::cerr << "file type not handled!" << std::endl;
+ usage(argv);
+ }
+
+ trace::exiting("main");
+}
Index: theo/exec/closing_isotropic.cc
--- theo/exec/closing_isotropic.cc (revision 0)
+++ theo/exec/closing_isotropic.cc (revision 0)
@@ -0,0 +1,71 @@
+#include "filetype.hh"
+
+#include <mln/morpho/closing.hh>
+#include <mln/win/disk2d.hh>
+#include <mln/win/ball3d.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.xxx r output.xxx" << std::endl
+ << " Closing with an isotropic structuring element." << std::endl
+ << " xxx is pbm (2D) or dump (3D)." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+
+ if (argc != 4)
+ usage(argv);
+
+ trace::entering("main");
+
+ int r = std::atoi(argv[2]);
+ if (r < 0)
+ {
+ std::cerr << "bad radius!" << std::endl;
+ usage(argv);
+ }
+
+
+ std::string filename = argv[1];
+
+ switch (get_filetype(argv[1]))
+ {
+ case filetype::pbm:
+ {
+ image2d<bool> ima, out;
+ io::pbm::load(ima, argv[1]);
+ out = morpho::closing(ima, win::disk2d(2 * r + 1));
+ io::pbm::save(out, argv[3]);
+ }
+ break;
+
+ case filetype::dump:
+ {
+ image3d<bool> ima, out;
+ io::dump::load(ima, argv[1]);
+ out = morpho::closing(ima, win::ball3d(2 * r + 1));
+ io::dump::save(out, argv[3]);
+ }
+ break;
+
+ case filetype::unknown:
+ std::cerr << "unknown filename extension!" << std::endl;
+ usage(argv);
+ break;
+
+ default:
+ std::cerr << "file type not handled!" << std::endl;
+ usage(argv);
+ }
+
+
+
+ trace::exiting("main");
+}
1
0
13 Feb '09
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-02-13 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Add n_max() function to compute n maxima in an array.
* mln/labeling/n_max.hh: Implement the n_max() function.
---
n_max.hh | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
Index: trunk/milena/mln/labeling/n_max.hh
===================================================================
--- trunk/milena/mln/labeling/n_max.hh (revision 0)
+++ trunk/milena/mln/labeling/n_max.hh (revision 3371)
@@ -0,0 +1,90 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// 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, 51 Franklin Street, Fifth Floor,
+// 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 MLN_LABELING_N_MAX_HH
+# define MLN_LABELING_N_MAX_HH
+
+# include <mln/core/concept/image.hh>
+# include <mln/util/array.hh>
+
+/// \file mln/labeling/mean_values.hh
+///
+/// Construct from a count accumulator of a labeled image an array with
+/// the ordered n biggest labels
+///
+/// \return an array starting at index 1
+
+
+namespace mln
+{
+
+ namespace labeling
+ {
+
+ template <typename L, typename V>
+ util::array<L>
+ n_max(const util::array<V>& in_arr, unsigned n);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename L, typename V>
+ util::array<L>
+ n_max(const util::array<V>& in_arr, unsigned n)
+ {
+ trace::entering("mln::labeling::n_max");
+
+ util::array<L> output(n + 1, 0);
+
+ int swap = 0;
+ for (unsigned i = 0; i < in_arr.nelements(); ++i)
+ {
+ if (in_arr[i] > in_arr[output[n]])
+ {
+ output[n] = i;
+ }
+ int j = n - 1;
+ while (j > 0 && in_arr[output[j]] < in_arr[output[j + 1]])
+ {
+ swap = output[j];
+ output[j] = output[j + 1];
+ output[j + 1] = swap;
+ --j;
+ }
+ }
+
+ trace::exiting("mln::labeling::n_max");
+ return output;
+ }
+
+# endif // !MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::labeling
+
+} // end of namespace mln
+
+#endif // ! MLN_LABELING_N_MAX_HH
1
0
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2009-02-13 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Call the n_max() function..
* fabien/igr/igr.cc: Call the n_max() function
instead of doing the computation.
---
igr.cc | 61 ++++---------------------------------------------------------
1 file changed, 4 insertions(+), 57 deletions(-)
Index: trunk/milena/sandbox/fabien/igr/igr.cc
===================================================================
--- trunk/milena/sandbox/fabien/igr/igr.cc (revision 3369)
+++ trunk/milena/sandbox/fabien/igr/igr.cc (revision 3370)
@@ -53,6 +53,7 @@
#include <mln/labeling/blobs.hh>
#include <mln/labeling/compute.hh>
#include <mln/labeling/fill_holes.hh>
+#include <mln/labeling/n_max.hh>
#include <mln/level/compare.hh>
#include <mln/level/transform.hh>
@@ -119,67 +120,13 @@
initialize(big_second, input);
data::fill(big_second, false);
-// mln_ch_value(I, bool) in_bool;
-// initialize(in_bool, input);
-// data::fill(in_bool, false);
-
- unsigned big_third_count = 0;
- unsigned big_third_lbl = 0;
- unsigned big_second_count = 0;
- unsigned big_second_lbl = 0;
- unsigned big_first_count = 0;
- unsigned big_first_lbl = 0;
- for (int i = 0; i < a.nelements(); ++i)
- {
- if (a[i] > big_third_count)
- {
- big_third_count = a[i];
- big_third_lbl = i;
- }
- if (big_third_count > big_second_count)
- {
- int swap = big_second_count;
- int swap_lbl = big_second_lbl;
- big_second_count = big_third_count;
- big_second_lbl = big_third_lbl;
- big_third_count = swap;
- big_third_lbl = swap_lbl;
- }
- if (big_second_count > big_first_count)
- {
- int swap = big_first_count;
- int swap_lbl = big_first_lbl;
- big_first_count = big_second_count;
- big_first_lbl = big_second_lbl;
- big_second_count = swap;
- big_second_lbl = swap_lbl;
- }
- }
- data::fill((big_second | (pw::value(labels) == big_second_lbl)).rw(), true);
- mln_VAR(big_third, threshold | pw::value(labels) == big_third_lbl);
-// data::fill((in_bool | (pw::value(labels) == big_second_lbl || pw::value(labels) == big_third_lbl)).rw(), true);
+ util::array<L> arr_big = labeling::n_max<L>(a, 3);
+ data::fill((big_second | (pw::value(labels) == arr_big[2])).rw(), true);
+ mln_VAR(big_third, threshold | pw::value(labels) == arr_big[3]);
// Fill holes.
big_second = labeling::fill_holes(big_second, nbh, nlabels);
-// box<mln_site(I)> h_box = geom::bbox((in_bool | pw::value(labels) == big_second_lbl).domain());
- //h_box.enlarge(1);
-
- //mln_ch_value(I, L) h_lbls = labeling::background(big_second /*in_bool | h_box*/, nbh, nlabels);
- //util::array<unsigned> arr_holes = labeling::compute(a_, big_second /*in_bool | h_box*/, h_lbls, nlabels);
- //int bg_count = 0;
- //int bg_lbl = 0;
- //for (int i = 0; i < arr_holes.nelements(); ++i)
- //{
- // if (arr_holes[i] > bg_count)
- // {
- // bg_count = a[i];
- // bg_lbl = i;
- // }
- //}
- //data::fill((/*(*/big_second /*in_bool | h_box).rw()*/ | pw::value(h_lbls) != bg_lbl).rw(), true);
-
- /*return level::transform(h_lbls, L_to_int_u8<label_16>());*/
// Gradient.
1
0