* scribo/binarization/otsu.hh: New routine.
* src/binarization/Makefile.am,
* src/binarization/otsu.cc: New tool.
* tests/binarization/Makefile.am,
* tests/binarization/otsu.cc,
* tests/binarization/otsu.ref.pbm: New test data.
---
scribo/ChangeLog | 13 ++
scribo/scribo/binarization/otsu.hh | 137 +++++++++++++++++++++
scribo/src/binarization/Makefile.am | 12 ++-
scribo/src/binarization/{sauvola.cc => otsu.cc} | 14 +--
scribo/tests/binarization/Makefile.am | 5 +-
scribo/tests/binarization/{sauvola.cc => otsu.cc} | 6 +-
scribo/tests/binarization/otsu.ref.pbm | Bin 0 -> 32884 bytes
7 files changed, 170 insertions(+), 17 deletions(-)
create mode 100644 scribo/scribo/binarization/otsu.hh
copy scribo/src/binarization/{sauvola.cc => otsu.cc} (84%)
copy scribo/tests/binarization/{sauvola.cc => otsu.cc} (90%)
create mode 100644 scribo/tests/binarization/otsu.ref.pbm
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 29d33f5..1962f38 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,3 +1,16 @@
+2011-10-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Add Otsu's binarization implementation.
+
+ * scribo/binarization/otsu.hh: New routine.
+
+ * src/binarization/Makefile.am,
+ * src/binarization/otsu.cc: New tool.
+
+ * tests/binarization/Makefile.am,
+ * tests/binarization/otsu.cc,
+ * tests/binarization/otsu.ref.pbm: New test data.
+
2011-09-19 Guillaume Lazzara <z(a)lrde.epita.fr>
Fix paths in the SCRIBO viewer.
diff --git a/scribo/scribo/binarization/otsu.hh b/scribo/scribo/binarization/otsu.hh
new file mode 100644
index 0000000..c96a207
--- /dev/null
+++ b/scribo/scribo/binarization/otsu.hh
@@ -0,0 +1,137 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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 SCRIBO_BINARIZATION_OTSU_HH
+# define SCRIBO_BINARIZATION_OTSU_HH
+
+# include <mln/core/concept/image.hh>
+# include <mln/util/array.hh>
+# include <mln/geom/nsites.hh>
+# include <mln/geom/ncols.hh>
+# include <mln/geom/nrows.hh>
+# include <mln/histo/compute.hh>
+
+# include <scribo/binarization/global_threshold.hh>
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ using namespace mln;
+
+ /*! An implementation of Otsu's binarization algorithm.
+
+ It is based on Ocropus's implementation.
+
http://code.google.com/p/ocropus/
+
+ \param[in] input A gray-scale image.
+
+ \return A binary image. True for foreground, False for
+ background.
+ */
+ template <typename I>
+ mln_ch_value(I,bool)
+ otsu(const Image<I>& input);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename I>
+ mln_ch_value(I,bool)
+ otsu(const Image<I>& input_)
+ {
+ trace::entering("scribo::binarization::otsu");
+
+ const I& input = exact(input_);
+ mln_precondition(input.is_valid());
+ mlc_is_a(mln_value(I), value::Scalar)::check();
+ // FIXME: Check that input value is gray level.
+
+ mln_value(I) maxval = mln_max(mln_value(I));
+ unsigned nsites = geom::nsites(input);
+
+ /* Histogram generation */
+ histo::array<mln_value(I)> hist = mln::histo::compute(input);
+
+
+ /* calculation of probability density */
+ util::array<double> pdf(hist.nvalues()); //probability distribution
+ for(int i = 0; i< maxval; ++i)
+ pdf[i] = (double)hist[i] / nsites;
+
+
+ util::array<double> cdf(hist.nvalues()); //cumulative probability
distribution
+ util::array<double> myu(hist.nvalues()); // mean value for separation
+
+ /* cdf & myu generation */
+ cdf[0] = pdf[0];
+ myu[0] = 0.0; /* 0.0 times prob[0] equals zero */
+
+ for(int i = 1; i < maxval; ++i)
+ {
+ cdf[i] = cdf[i-1] + pdf[i];
+ myu[i] = myu[i-1] + i*pdf[i];
+ }
+
+ /* sigma maximization
+ sigma stands for inter-class variance
+ and determines optimal threshold value */
+ int threshold = 0;
+ double max_sigma = 0.0;
+ util::array<double> sigma(hist.nvalues()); // inter-class variance
+
+ for(int i = 0; i < maxval - 1; ++i)
+ {
+ if(cdf[i] != 0.0 && cdf[i] != 1.0)
+ {
+ double p1p2 = cdf[i] * (1.0 - cdf[i]);
+ double mu1mu2diff = myu[maxval - 1] * cdf[i] - myu[i];
+ sigma[i] = mu1mu2diff * mu1mu2diff / p1p2;
+ }
+ else
+ sigma[i] = 0.0;
+ if(sigma[i] > max_sigma)
+ {
+ max_sigma = sigma[i];
+ threshold = i;
+ }
+ }
+
+ // Computing final result.
+ mln_ch_value(I,bool) output = global_threshold(input, threshold);
+
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_BINARIZATION_OTSU_HH
diff --git a/scribo/src/binarization/Makefile.am b/scribo/src/binarization/Makefile.am
index 557a30a..fc96572 100644
--- a/scribo/src/binarization/Makefile.am
+++ b/scribo/src/binarization/Makefile.am
@@ -1,5 +1,5 @@
-# Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
-# (LRDE).
+# Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+# Laboratory (LRDE).
#
# This file is part of Olena.
#
@@ -45,12 +45,20 @@ if HAVE_MAGICKXX
sauvola_ms_debug
utilexec_PROGRAMS = \
+ otsu \
sauvola \
sauvola_ms \
sauvola_ms_fg \
sauvola_ms_split
+
+ otsu_SOURCES = otsu.cc
+ otsu_CPPFLAGS = $(AM_CPPFLAGS) \
+ $(MAGICKXX_CPPFLAGS)
+ otsu_LDFLAGS = $(AM_LDFLAGS) \
+ $(MAGICKXX_LDFLAGS)
+
sauvola_ms_fg_SOURCES = sauvola_ms_fg.cc
sauvola_ms_fg_CPPFLAGS = $(AM_CPPFLAGS) \
$(MAGICKXX_CPPFLAGS)
diff --git a/scribo/src/binarization/sauvola.cc b/scribo/src/binarization/otsu.cc
similarity index 84%
copy from scribo/src/binarization/sauvola.cc
copy to scribo/src/binarization/otsu.cc
index 518937b..7673363 100644
--- a/scribo/src/binarization/sauvola.cc
+++ b/scribo/src/binarization/otsu.cc
@@ -1,5 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
-// Laboratory (LRDE)
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -31,7 +30,7 @@
#include <mln/data/transform.hh>
#include <mln/fun/v2v/rgb_to_luma.hh>
-#include <scribo/binarization/sauvola.hh>
+#include <scribo/binarization/otsu.hh>
#include <scribo/debug/option_parser.hh>
#include <scribo/debug/logger.hh>
@@ -57,9 +56,7 @@ static const scribo::debug::opt_data opt_desc[] =
// name, description, arguments, check args function, number of args, default arg
{ "debug-prefix", "Enable debug image outputs. Prefix image name with
that "
"given prefix.", "<prefix>", 0, 1, 0 },
- { "k", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.34" },
{ "verbose", "Enable verbose mode", 0, 0, 0, 0 },
- { "win-size", "Window size", "<size>", 0, 1,
"101" },
{0, 0, 0, 0, 0, 0}
};
@@ -86,11 +83,6 @@ int main(int argc, char *argv[])
trace::entering("main");
bool verbose = options.is_set("verbose");
- unsigned w = atoi(options.opt_value("win-size").c_str());
- double k = atof(options.opt_value("k").c_str());
-
- if (verbose)
- std::cout << "Using w=" << w << " and k="
<< k << std::endl;
image2d<value::rgb8> input;
io::magick::load(input, options.arg("input.*"));
@@ -99,7 +91,7 @@ int main(int argc, char *argv[])
image2d<value::int_u8>
input_1_gl = data::transform(input,
mln::fun::v2v::rgb_to_luma<value::int_u8>());
- image2d<bool> out = scribo::binarization::sauvola(input_1_gl, w, k);
+ image2d<bool> out = scribo::binarization::otsu(input_1_gl);
io::pbm::save(out, options.arg("output.pbm"));
diff --git a/scribo/tests/binarization/Makefile.am
b/scribo/tests/binarization/Makefile.am
index a23d125..b8ab2d9 100644
--- a/scribo/tests/binarization/Makefile.am
+++ b/scribo/tests/binarization/Makefile.am
@@ -22,17 +22,20 @@ include $(top_srcdir)/scribo/tests/tests.mk
EXTRA_DIST = \
sauvola_ms.ref.pbm \
- sauvola.ref.pbm
+ sauvola.ref.pbm \
+ otsu.ref.pbm
check_PROGRAMS = \
global_threshold \
local_threshold \
+ otsu \
sauvola \
sauvola_ms
global_threshold_SOURCES = global_threshold.cc
local_threshold_SOURCES = local_threshold.cc
+otsu_SOURCES = otsu.cc
sauvola_SOURCES = sauvola.cc
sauvola_ms_SOURCES = sauvola_ms.cc
diff --git a/scribo/tests/binarization/sauvola.cc b/scribo/tests/binarization/otsu.cc
similarity index 90%
copy from scribo/tests/binarization/sauvola.cc
copy to scribo/tests/binarization/otsu.cc
index 33eb59f..fd4c7f2 100644
--- a/scribo/tests/binarization/sauvola.cc
+++ b/scribo/tests/binarization/otsu.cc
@@ -32,7 +32,7 @@
#include <mln/io/pbm/load.hh>
#include <mln/io/pbm/save.hh>
-#include <scribo/binarization/sauvola.hh>
+#include <scribo/binarization/otsu.hh>
#include "tests/data.hh"
@@ -43,10 +43,10 @@ int main()
image2d<value::int_u8> input;
io::pgm::load(input, MILENA_IMG_DIR "/lena.pgm");
- image2d<bool> bin = scribo::binarization::sauvola(input, 101);
+ image2d<bool> bin = scribo::binarization::otsu(input);
image2d<bool> ref;
- io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/sauvola.ref.pbm");
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/otsu.ref.pbm");
mln_assertion(bin == ref);
}
diff --git a/scribo/tests/binarization/otsu.ref.pbm
b/scribo/tests/binarization/otsu.ref.pbm
new file mode 100644
index 0000000000000000000000000000000000000000..5d74fe2f7f9327077937993d23c86ef51aa03a17
GIT binary patch
literal 32884
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
B%WVJv
literal 0
HcmV?d00001
--
1.7.2.5