https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Augment ICDAR-HSC.
* icdar/2009/hsc/line_to_words.hh: New.
* icdar/2009/hsc/input_to_wsl.cc: Add some log.
* icdar/2009/hsc/line_to_words.cc: New.
* icdar/2009/hsc/ws_to_wsl.hh (pass): New.
(ws_to_wslines): Use the 'pass' routine.
* theo/icdar/hsc/reduce.sh: New.
* theo/icdar/hsc/words.sh: New.
icdar/2009/hsc/input_to_wsl.cc | 5 +
icdar/2009/hsc/line_to_words.cc | 45 +++++++++++++++
icdar/2009/hsc/line_to_words.hh | 114 ++++++++++++++++++++++++++++++++++++++++
icdar/2009/hsc/ws_to_wsl.hh | 48 ++++++++++++++--
theo/icdar/hsc/reduce.sh | 4 +
theo/icdar/hsc/words.sh | 7 ++
6 files changed, 215 insertions(+), 8 deletions(-)
Index: icdar/2009/hsc/line_to_words.hh
--- icdar/2009/hsc/line_to_words.hh (revision 0)
+++ icdar/2009/hsc/line_to_words.hh (revision 0)
@@ -0,0 +1,114 @@
+
+#include <mln/value/int_u.hh>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/transform/distance_front.hh>
+#include <mln/make/w_window2d_int.hh>
+#include <mln/win/rectangle2d.hh>
+
+#include <mln/morpho/closing/structural.hh>
+#include <mln/morpho/closing/area.hh>
+#include <mln/morpho/elementary/dilation.hh>
+#include <mln/morpho/watershed/flooding.hh>
+
+
+
+namespace mln
+{
+
+
+ image2d<bool> // Fwd decl.
+ reduce_negate(const image2d<bool>& input);
+
+
+
+ template <typename L>
+ image2d<L>
+ line_to_words(const image2d<bool>& input, L& n_words)
+ {
+ // Parameters.
+
+ const unsigned
+ height = 5,
+ width = 11,
+ l_area = 500;
+
+ // end of Parameters.
+
+
+ image2d<bool>
+ sub = reduce_negate(input),
+ clo = morpho::closing::structural(sub,
+ win::rectangle2d(height,
+ width));
+
+ int ww[] = { 00, 11, 0, 11, 0,
+ 11, 7, 5, 7, 11,
+ 00, 5, 0, 5, 0,
+ 11, 7, 5, 7, 11,
+ 00, 11, 0, 11, 0 };
+
+ typedef value::int_u<12> int_u12;
+ image2d<int_u12>
+ dmap = transform::distance_front(clo,
+ c4(), make::w_window2d_int(ww),
+ mln_max(int_u12)),
+ dmap_ = morpho::closing::area(dmap, c4(), l_area);
+
+ image2d<L> ws =
morpho::elementary::dilation(morpho::watershed::flooding(dmap_,
+ c4(),
+ n_words),
+ c4());
+
+ image2d<L> output(input.domain());
+
+ {
+ const int
+ min_row = input.domain().pmin().row(),
+ min_col = input.domain().pmin().col();
+
+ mln_piter_(box2d) p(input.domain());
+ for_all(p)
+ if (input(p))
+ output(p) = 0;
+ else
+ output(p) = ws.at_((p.row() - min_row) / 2,
+ (p.col() - min_col) / 2);
+ }
+
+ return output;
+ }
+
+
+
+ image2d<bool>
+ reduce_negate(const image2d<bool>& input)
+ {
+ const int
+ min_row = input.domain().pmin().row(),
+ min_col = input.domain().pmin().col(),
+ max_row = input.domain().pmax().row(),
+ max_col = input.domain().pmax().col();
+
+ image2d<bool> output(input.nrows() / 2,
+ input.ncols() / 2);
+
+ for (int row = min_row; row <= max_row; row += 2)
+ for (int col = min_col; col <= max_col; col += 2)
+ {
+ unsigned count = 0;
+ if (input.at_(row, col) == false) ++count;
+ if (input.at_(row, col + 1) == false) ++count;
+ if (input.at_(row + 1, col) == false) ++count;
+ if (input.at_(row + 1, col + 1) == false) ++count;
+ output.at_((row - min_row) / 2,
+ (col - min_col) / 2) = (count >= 2);
+ }
+ return output;
+ }
+
+
+
+} // ! mln
Index: icdar/2009/hsc/input_to_wsl.cc
--- icdar/2009/hsc/input_to_wsl.cc (revision 3629)
+++ icdar/2009/hsc/input_to_wsl.cc (working copy)
@@ -115,6 +115,11 @@
int_u8 n_basins;
ws = morpho::watershed::flooding(clo, c4(), n_basins);
+# ifdef LOG
+ io::pgm::save(ws, "tmp_ws.pgm");
+ io::ppm::save(debug::colorize(rgb8(), ws, n_basins), "tmp_ws.ppm");
+# endif
+
image2d<int_u8> wsl = ws_to_wslines(input, small, ws, n_basins);
Index: icdar/2009/hsc/line_to_words.cc
--- icdar/2009/hsc/line_to_words.cc (revision 0)
+++ icdar/2009/hsc/line_to_words.cc (revision 0)
@@ -0,0 +1,45 @@
+#include <mln/value/int_u8.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/save.hh>
+
+#include <sandbox/icdar/2009/hsc/line_to_words.hh>
+
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " line.pbm
output.pgm" << std::endl
+ << " HSC @ ICDAR'2009" << std::endl
+ << " line.pbm: a 2D image of a line (text is black; background is
white)" << std::endl
+ << " output.pgm: output image where words are labeled (int_u8)"
<< std::endl
+ << " 0 is the background label." << 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");
+
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ int_u8 n_words;
+ image2d<int_u8> output = line_to_words(input, n_words);
+
+ io::pgm::save(output, argv[2]);
+
+
+ trace::exiting("main");
+}
Index: icdar/2009/hsc/ws_to_wsl.hh
--- icdar/2009/hsc/ws_to_wsl.hh (revision 3629)
+++ icdar/2009/hsc/ws_to_wsl.hh (working copy)
@@ -1,3 +1,5 @@
+#include <cmath>
+
#include <mln/core/var.hh>
#include <mln/core/image/image2d.hh>
@@ -101,13 +103,17 @@
if (n_ == 0)
return;
mean_ /= n_;
- algebra::mat<2,1,float> mu;
cov_ = cov_ / n_ - to_mat(mean_) * trans(mean_);
float
a = cov_(0, 0), b = cov_(0, 1),
c = cov_(1, 0), d = cov_(1, 1),
r = a * d - b * c;
+
+ float D = std::sqrt((a - d) * (a - d) + 4 * b * c);
+ lambda1_ = 0.5 * (a + d + D);
+ lambda2_ = 0.5 * (a + d - D);
+
if (r > -0.001f && r < 0.001f) // too close to 0
{
n_ = 0; // invalidation
@@ -174,12 +180,16 @@
return valid_;
}
+ float lambda1() const { return lambda1_; }
+ float lambda2() const { return lambda2_; }
+
protected:
bool valid_;
unsigned n_;
algebra::vec<2,float> mean_;
algebra::mat<2,2,float> cov_, cov_1_;
+ float lambda1_, lambda2_;
};
@@ -225,6 +235,31 @@
+ bool
+ pass(const util::array<mahalanobis>& m,
+ unsigned l, unsigned r)
+ {
+ float
+ // vertical std deviations
+ vs_l = std::sqrt(m[l].cov()(0, 0)),
+ vs_r = std::sqrt(m[r].cov()(0, 0)),
+ // vertical distance
+ vd = std::abs(m[l].mean()[0] - m[r].mean()[0]),
+ // horizontal std deviations
+ hs_l = std::sqrt(m[l].cov()(1, 1)),
+ hs_r = std::sqrt(m[r].cov()(1, 1)),
+ // horizontal means (column coordinates)
+ hm_l = m[l].mean()[1],
+ hm_r = m[r].mean()[1];
+
+ bool
+ v_criterion = (vd < 5 * std::sqrt(vs_l * vs_r)), // FIXME: say 4?
+ h_criterion = (hm_r - 1 * hs_r > hm_l + 1 * hs_l); // FIXME: say 1.5?
+
+ return v_criterion && h_criterion;
+ }
+
+
template <typename L>
image2d<L>
@@ -296,7 +331,8 @@
if (m[v2].col() < v_col)
{
// v2 <-- v
- if (d_ < d_left_min)
+ if (pass(m, v2, v.id())
+ && d_ < d_left_min)
{
d_left_min = d_;
v_left_best = v2;
@@ -305,7 +341,8 @@
else
{
// v --> v2
- if (d_ < d_right_min)
+ if (pass(m, v.id(), v2)
+ && d_ < d_right_min)
{
d_right_min = d_;
v_right_best = v2;
@@ -319,7 +356,6 @@
}
-
util::array<L> parent(n_basins + 1);
// Computing parent.
@@ -334,11 +370,7 @@
continue;
unsigned r = v_right[l];
if (v_left[r] != l)
- {
- // std::cout << '.' << std::endl;
continue;
- }
- // std::cout << l << " -> " << r << std::endl;
parent[l] = r;
}
Index: theo/icdar/hsc/reduce.sh
--- theo/icdar/hsc/reduce.sh (revision 0)
+++ theo/icdar/hsc/reduce.sh (revision 0)
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+convert -negate -geometry 50% +compress -depth 8 $1 ${1%.pbm}_50p.pbm
+convert -depth 8 +compress ${1%.pbm}_50p.pbm ${1%.pbm}_50p.pgm
Property changes on: theo/icdar/hsc/reduce.sh
___________________________________________________________________
Added: svn:executable
+ *
Index: theo/icdar/hsc/words.sh
--- theo/icdar/hsc/words.sh (revision 0)
+++ theo/icdar/hsc/words.sh (revision 0)
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+./+bin/closing_rectangle $1 5 11 tmp_small_clo.pbm
+./+bin/distance_thick tmp_small_clo.pbm tmp_dist.pgm
+./+bin/closing_area tmp_dist.pgm 500 tmp_clo.pgm
+./+bin/watershed_flooding tmp_clo.pgm tmp_ws.pgm
+./+bin/watershed_superpose ${1%pbm}pgm tmp_ws.pgm ${1%pbm}ppm
Property changes on: theo/icdar/hsc/words.sh
___________________________________________________________________
Added: svn:executable
+ *