olena-2.0-8-gfc1b111 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. --- 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@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@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
participants (1)
-
Guillaume Lazzara