This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Olena, a generic and efficient image processing platform".
The branch exp/scribo-z has been updated
via 5c627b019540ecc6dbf4cb21630354289adf6f6b (commit)
via 85cda080414cc6e05d8ee49246a2171eb7f4fbae (commit)
via e8373a069ad3b882f9a927c8d318643645069c1e (commit)
via 4bf89fb72cfe41e98d7df23be2cc79bb37173c39 (commit)
from a6a8d2a44d746824876f24c53af69f83036ddaf3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
5c627b0 primitive/extract/components.hh: Use labeling::value_and_compute.
85cda08 Introduce labeling::value_and_compute.
e8373a0 Add a fast rotation tool.
4bf89fb Add a new routine to highlight text areas in an image.
-----------------------------------------------------------------------
Summary of changes:
milena/ChangeLog | 11 +
milena/mln/canvas/labeling/video.hh | 8 +-
milena/mln/labeling/value.hh | 16 +-
milena/mln/labeling/value_and_compute.hh | 241 ++++++++++++++++++
scribo/ChangeLog | 22 ++
scribo/debug/highlight_text_area.hh | 255 ++++++++++++++++++++
scribo/primitive/extract/components.hh | 5 +-
scribo/src/debug/Makefile.am | 15 +-
.../subsample.cc => debug/highlight_text_area.cc} | 62 ++++--
scribo/src/preprocessing/Makefile.am | 10 +
scribo/src/preprocessing/rotate_90.cc | 51 ++++
scribo/src/text_in_picture.cc | 53 +----
12 files changed, 674 insertions(+), 75 deletions(-)
create mode 100644 milena/mln/labeling/value_and_compute.hh
create mode 100644 scribo/debug/highlight_text_area.hh
copy scribo/src/{preprocessing/subsample.cc => debug/highlight_text_area.cc} (57%)
create mode 100644 scribo/src/preprocessing/rotate_90.cc
hooks/post-receive
--
Olena, a generic and efficient image processing platform
* apps/mesh-segm-skel/mesh-complex-segm.cc,
* apps/mesh-segm-skel/mesh-complex-skel.cc,
* apps/mesh-segm-skel/mesh-complex-max-curv-segm.cc,
* apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc:
Convert the floating point value input to an unsigned integer
image to avoid precision errors due to float comparisons.
---
milena/ChangeLog | 11 ++++
.../mesh-segm-skel/mesh-complex-max-curv-segm.cc | 39 ++++++++----
.../mesh-segm-skel/mesh-complex-max-curv-skel.cc | 61 +++++++++++++-------
milena/apps/mesh-segm-skel/mesh-complex-segm.cc | 24 ++++++--
milena/apps/mesh-segm-skel/mesh-complex-skel.cc | 41 ++++++++++---
5 files changed, 127 insertions(+), 49 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 009db1b..8d0f1be 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,16 @@
2010-06-14 Roland Levillain <roland(a)lrde.epita.fr>
+ Improve the precision of some mesh-segm-skel apps.
+
+ * apps/mesh-segm-skel/mesh-complex-segm.cc,
+ * apps/mesh-segm-skel/mesh-complex-skel.cc,
+ * apps/mesh-segm-skel/mesh-complex-max-curv-segm.cc,
+ * apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc:
+ Convert the floating point value input to an unsigned integer
+ image to avoid precision errors due to float comparisons.
+
+2010-06-14 Roland Levillain <roland(a)lrde.epita.fr>
+
New application: mesh-complex-max-curv-skel.
* apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc: New.
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-max-curv-segm.cc b/milena/apps/mesh-segm-skel/mesh-complex-max-curv-segm.cc
index 477ccdf..1f43381 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-max-curv-segm.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-max-curv-segm.cc
@@ -75,25 +75,26 @@ int main(int argc, char* argv[])
`----------------*/
// Image type.
- typedef mln::float_2complex_image3df ima_t;
+ typedef mln::float_2complex_image3df float_ima_t;
// Dimension of the image (and therefore of the complex).
- static const unsigned D = ima_t::dim;
+ static const unsigned D = float_ima_t::dim;
// Geometry of the image.
- typedef mln_geom_(ima_t) G;
+ typedef mln_geom_(float_ima_t) G;
mln::bin_2complex_image3df bin_input;
mln::io::off::load(bin_input, input_filename);
- std::pair<ima_t, ima_t> curv = mln::geom::mesh_curvature(bin_input.domain());
+ std::pair<float_ima_t, float_ima_t> curv =
+ mln::geom::mesh_curvature(bin_input.domain());
// Compute the pseudo_inverse curvature at each vertex.
- ima_t input(bin_input.domain());
- mln::p_n_faces_fwd_piter<D, G> v(input.domain(), 0);
+ float_ima_t float_ima(bin_input.domain());
+ mln::p_n_faces_fwd_piter<D, G> v(float_ima.domain(), 0);
for_all(v)
{
float h = (curv.first(v) + curv.second(v)) / 2;
// Pseudo-inverse curvature.
float h_inv = 1 / pi * (atan(-h) + pi / 2);
- input(v) = h_inv;
+ float_ima(v) = h_inv;
// FIXME: The program should allow the user to choose the kind
// of measure.
// input(v) = mln::math::max(mln::math::sqr(curv.first(v)),
@@ -101,7 +102,7 @@ int main(int argc, char* argv[])
}
// Values on edges.
- mln::p_n_faces_fwd_piter<D, G> e(input.domain(), 1);
+ mln::p_n_faces_fwd_piter<D, G> e(float_ima.domain(), 1);
typedef mln::complex_lower_neighborhood<D, G> adj_vertices_nbh_t;
adj_vertices_nbh_t adj_vertices_nbh;
mln_niter_(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, e);
@@ -113,14 +114,26 @@ int main(int argc, char* argv[])
// Iterate on vertices (0-faces).
for_all(adj_v)
{
- s += input(adj_v);
+ s += float_ima(adj_v);
++n;
}
- input(e) = s / n;
+ float_ima(e) = s / n;
// An edge should be adjacent to exactly two vertices.
mln_invariant(n <= 2);
}
+ // Convert the float image into an unsigned image because some
+ // algorithms do not handle float images well.
+ /* FIXME: This is bad: float images should be handled as-is. At
+ least, we should use a decent conversion, using an optimal affine
+ transformation (stretching/shrinking) or any other kind of
+ interpolation. */
+ typedef mln::unsigned_2complex_image3df ima_t;
+ ima_t ima(float_ima.domain());
+ mln_piter_(ima_t) p(float_ima.domain());
+ for_all(p)
+ ima(p) = 1000 * float_ima(p);
+
/*-----------------.
| Simplification. |
`-----------------*/
@@ -131,7 +144,7 @@ int main(int argc, char* argv[])
adj_edges_nbh_t;
adj_edges_nbh_t adj_edges_nbh;
- ima_t closed_input = mln::morpho::closing::area(input, adj_edges_nbh, lambda);
+ ima_t closed_ima = mln::morpho::closing::area(ima, adj_edges_nbh, lambda);
/*------.
| WST. |
@@ -141,7 +154,7 @@ int main(int argc, char* argv[])
not constrained the domain of the image to 1-faces only.
It would be great if we could use something like this:
- closed_input | mln::p_faces<1, D, G>(closed_input.domain())
+ closed_ima | mln::p_faces<1, D, G>(closed_ima.domain())
as input of the WST. */
@@ -150,7 +163,7 @@ int main(int argc, char* argv[])
wst_val_t nbasins;
typedef mln::unsigned_2complex_image3df wst_ima_t;
wst_ima_t wshed =
- mln::morpho::meyer_wst(closed_input, adj_edges_nbh, nbasins);
+ mln::morpho::meyer_wst(closed_ima, adj_edges_nbh, nbasins);
std::cout << "nbasins = " << nbasins << std::endl;
// Label polygons (i.e., propagate labels from edges to polygons).
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc b/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc
index 6265a25..a174dd6 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc
@@ -75,37 +75,38 @@ main(int argc, char* argv[])
| Complex image. |
`----------------*/
- // Image type.
- typedef mln::float_2complex_image3df ima_t;
+ // Curvature image type.
+ typedef mln::float_2complex_image3df float_ima_t;
// Dimension of the image (and therefore of the complex).
- static const unsigned D = ima_t::dim;
+ static const unsigned D = float_ima_t::dim;
// Geometry of the image.
- typedef mln_geom_(ima_t) G;
+ typedef mln_geom_(float_ima_t) G;
mln::bin_2complex_image3df bin_input;
mln::io::off::load(bin_input, input_filename);
- std::pair<ima_t, ima_t> curv = mln::geom::mesh_curvature(bin_input.domain());
+ std::pair<float_ima_t, float_ima_t> curv =
+ mln::geom::mesh_curvature(bin_input.domain());
// Compute the pseudo_inverse curvature at each vertex.
- ima_t input(bin_input.domain());
- mln::p_n_faces_fwd_piter<D, G> v(input.domain(), 0);
+ float_ima_t float_ima(bin_input.domain());
+ mln::p_n_faces_fwd_piter<D, G> v(float_ima.domain(), 0);
for_all(v)
{
// FIXME: The program should allow the user to choose the kind
- // of measure.
+ // of measure (curvature).
#if 0
float h = (curv.first(v) + curv.second(v)) / 2;
// Pseudo-inverse curvature.
float h_inv = 1 / pi * (atan(-h) + pi / 2);
- input(v) = h_inv;
+ float_ima(v) = h_inv;
#endif
// Max curvature.
- input(v) = mln::math::max(mln::math::sqr(curv.first(v)),
- mln::math::sqr(curv.second(v)));
+ float_ima(v) = mln::math::max(mln::math::sqr(curv.first(v)),
+ mln::math::sqr(curv.second(v)));
}
// Values on triangles.
- mln::p_n_faces_fwd_piter<D, G> t(input.domain(), 2);
+ mln::p_n_faces_fwd_piter<D, G> t(float_ima.domain(), 2);
// For each triangle (2-face) T, iterate on the the set of vertices
// (0-faces) transitively adjacent to T.
typedef mln::complex_m_face_neighborhood<D, G> adj_vertices_nbh_t;
@@ -123,21 +124,34 @@ main(int argc, char* argv[])
// Iterate on vertices (0-faces).
for_all(adj_v)
{
- s += input(adj_v);
+ s += float_ima(adj_v);
++n;
}
- input(t) = s / n;
+ float_ima(t) = s / n;
// A triangle should be adjacent to exactly two vertices.
mln_invariant(n <= 3);
}
+ // Convert the float image into an unsigned image because some
+ // algorithms do not handle float images well.
+ /* FIXME: This is bad: float images should be handled as-is. At
+ least, we should use a decent conversion, using an optimal affine
+ transformation (stretching/shrinking) or any other kind of
+ interpolation. */
+ typedef mln::unsigned_2complex_image3df ima_t;
+ ima_t ima(float_ima.domain());
+ // Process only triangles, as edges and vertices are set afterwards
+ // (see FIXME below).
+ for_all(t)
+ ima(t) = 1000 * float_ima(t);
+
/* FIXME: Workaround: Set maximal values on vertices and edges to
exclude them from the set of minimal values. */
for_all(v)
- input(v) = mln_max(float);
- mln::p_n_faces_fwd_piter<D, G> e(input.domain(), 1);
+ ima(v) = mln_max(mln_value_(ima_t));
+ mln::p_n_faces_fwd_piter<D, G> e(float_ima.domain(), 1);
for_all(e)
- input(e) = mln_max(float);
+ ima(e) = mln_max(mln_value_(ima_t));
/*-----------------.
| Simplification. |
@@ -147,7 +161,7 @@ main(int argc, char* argv[])
typedef mln::complex_lower_dim_connected_n_face_neighborhood<D, G> nbh_t;
nbh_t nbh;
- ima_t closed_input = mln::morpho::closing::area(input, nbh, lambda);
+ ima_t closed_ima = mln::morpho::closing::area(ima, nbh, lambda);
/*---------------.
| Local minima. |
@@ -161,7 +175,7 @@ main(int argc, char* argv[])
to 2-faces. */
typedef mln_ch_value_(ima_t, label_t) label_ima_t;
label_ima_t minima =
- mln::labeling::regional_minima(closed_input, nbh, nminima);
+ mln::labeling::regional_minima(closed_ima, nbh, nminima);
typedef mln::complex_higher_neighborhood<D, G> higher_nbh_t;
higher_nbh_t higher_nbh;
@@ -201,7 +215,7 @@ main(int argc, char* argv[])
for_all(adj_e)
if (minima(adj_e) == mln::literal::zero)
{
- // If V is adjcent to a non-minimal triangle, then it must
+ // If V is adjacent to a non-minimal triangle, then it must
// not belong to a minima.
ref_adj_minimum = mln::literal::zero;
break;
@@ -223,6 +237,13 @@ main(int argc, char* argv[])
| Initial binary image. |
`-----------------------*/
+ /* Careful: creating ``holes'' in the surface obviously changes its
+ topology, but it may also split a single connected component in
+ two or more components, resulting in a disconnected skeleton. We
+ may want to improve this step either by forbidding any splitting,
+ or by incrementally ``digging'' a regional minima as long as no
+ splitting occurs. */
+
typedef mln_ch_value_(ima_t, bool) bin_ima_t;
bin_ima_t surface(minima.domain());
mln::data::fill(surface, true);
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-segm.cc b/milena/apps/mesh-segm-skel/mesh-complex-segm.cc
index 8d349fe..655a46c 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-segm.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-segm.cc
@@ -66,15 +66,27 @@ int main(int argc, char* argv[])
| Complex image. |
`----------------*/
- // Image type.
- typedef mln::float_2complex_image3df ima_t;
+ // Input type.
+ typedef mln::float_2complex_image3df float_input_t;
// Dimension of the image (and therefore of the complex).
- static const unsigned D = ima_t::dim;
+ static const unsigned D = float_input_t::dim;
// Geometry of the image.
- typedef mln_geom_(ima_t) G;
-
- ima_t input;
- mln::io::off::load(input, input_filename);
+ typedef mln_geom_(float_input_t) G;
+
+ float_input_t float_input;
+ mln::io::off::load(float_input, input_filename);
+
+ // Convert the float image into an unsigned image because some
+ // algorithms do not handle float images well.
+ /* FIXME: This is bad: float images should be handled as-is. At
+ least, we should use a decent conversion, using an optimal affine
+ transformation (stretching/shrinking) or any other kind of
+ interpolation. */
+ typedef mln::unsigned_2complex_image3df ima_t;
+ ima_t input(float_input.domain());
+ mln_piter_(ima_t) p(input.domain());
+ for_all(p)
+ input(p) = 1000 * float_input(p);
// Values on edges.
mln::p_n_faces_fwd_piter<D, G> e(input.domain(), 1);
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-skel.cc b/milena/apps/mesh-segm-skel/mesh-complex-skel.cc
index b7e1f1f..5cd97b4 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-skel.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-skel.cc
@@ -72,23 +72,37 @@ main(int argc, char* argv[])
`----------------*/
// Image type.
- typedef mln::float_2complex_image3df ima_t;
+ typedef mln::float_2complex_image3df float_input_t;
// Dimension of the image (and therefore of the complex).
- static const unsigned D = ima_t::dim;
+ static const unsigned D = float_input_t::dim;
// Geometry of the image.
- typedef mln_geom_(ima_t) G;
-
- ima_t input;
- mln::io::off::load(input, input_filename);
+ typedef mln_geom_(float_input_t) G;
+
+ float_input_t float_input;
+ mln::io::off::load(float_input, input_filename);
+
+ // Convert the float image into an unsigned image because some
+ // algorithms do not handle float images well.
+ /* FIXME: This is bad: float images should be handled as-is. At
+ least, we should use a decent conversion, using an optimal affine
+ transformation (stretching/shrinking) or any other kind of
+ interpolation. */
+ typedef mln::unsigned_2complex_image3df ima_t;
+ ima_t input(float_input.domain());
+ // Process only triangles, as edges and vertices are set afterwards
+ // (see FIXME below).
+ mln::p_n_faces_fwd_piter<D, G> t(input.domain(), 2);
+ for_all(t)
+ input(t) = 1000 * float_input(t);
/* FIXME: Workaround: Set maximal values on vertices and edges to
exclude them from the set of minimal values. */
mln::p_n_faces_fwd_piter<D, G> v(input.domain(), 0);
for_all(v)
- input(v) = mln_max(float);
+ input(v) = mln_max(mln_value_(ima_t));
mln::p_n_faces_fwd_piter<D, G> e(input.domain(), 1);
for_all(e)
- input(e) = mln_max(float);
+ input(e) = mln_max(mln_value_(ima_t));
/*-----------------.
| Simplification. |
@@ -126,7 +140,7 @@ main(int argc, char* argv[])
for_all(adj_t)
if (minima(adj_t) == mln::literal::zero)
{
- // If E is adjcent to a non-minimal triangle, then it must
+ // If E is adjacent to a non-minimal triangle, then it must
// not belong to a minima.
ref_adj_minimum = mln::literal::zero;
break;
@@ -152,7 +166,7 @@ main(int argc, char* argv[])
for_all(adj_e)
if (minima(adj_e) == mln::literal::zero)
{
- // If V is adjcent to a non-minimal triangle, then it must
+ // If V is adjacent to a non-minimal triangle, then it must
// not belong to a minima.
ref_adj_minimum = mln::literal::zero;
break;
@@ -174,6 +188,13 @@ main(int argc, char* argv[])
| Initial binary image. |
`-----------------------*/
+ /* Careful: creating ``holes'' in the surface obviously changes its
+ topology, but it may also split a single connected component in
+ two or more components, resulting in a disconnected skeleton. We
+ may want to improve this step either by forbidding any splitting,
+ or by incrementally ``digging'' a regional minima as long as no
+ splitting occurs. */
+
typedef mln_ch_value_(ima_t, bool) bin_ima_t;
bin_ima_t surface(minima.domain());
mln::data::fill(surface, true);
--
1.5.6.5