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
September 2009
- 9 participants
- 188 discussions
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2009-09-17 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Fix index value bug.
* fabien/mln/core/image/cache.hh: Fix index value bug.
* fabien/tests/core/image/tiled2d.cc: Minor update.
---
mln/core/image/cache.hh | 2 +-
tests/core/image/tiled2d.cc | 6 +-----
2 files changed, 2 insertions(+), 6 deletions(-)
Index: trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc
===================================================================
--- trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4491)
+++ trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4492)
@@ -43,7 +43,7 @@
mln_piter_(tiled2d<rgb8>) p(tiled_ima.domain());
for_all(p)
- if (p.row() % 256 == 0)
+ if (p.row() % 16 == 0)
{
//std::cout << tiled_ima(p);
tiled_ima(p) = literal::green;
@@ -51,9 +51,5 @@
//mln_assertion(tiled_ima(p) == ima(p));
}
- /*for_all(p)
- if (p.col() % 16 == 0)
- tiled_ima(p) = literal::purple;*/
-
return 0;
}
Index: trunk/milena/sandbox/fabien/mln/core/image/cache.hh
===================================================================
--- trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 4491)
+++ trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 4492)
@@ -171,7 +171,7 @@
else // We must find which page to discard.
{
unsigned min = this->order_[0];
- unsigned new_index = 0;
+ new_index = 0;
for (unsigned i = 1; i < this->pages_.nelements(); ++i)
{
if (this->order_[i] < min)
1
0
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2009-09-16 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Implement basic LRU cache algorithm.
* fabien/mln/core/image/cache.hh: Implement basic LRU cache
algorithm.
* fabien/tests/core/image/tiled2d.cc: Minor update.
---
mln/core/image/cache.hh | 67 +++++++++++++++++++++++++++++++++++---------
tests/core/image/tiled2d.cc | 2 -
2 files changed, 55 insertions(+), 14 deletions(-)
Index: trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc
===================================================================
--- trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4490)
+++ trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4491)
@@ -43,7 +43,7 @@
mln_piter_(tiled2d<rgb8>) p(tiled_ima.domain());
for_all(p)
- if (p.row() % 7 == 0)
+ if (p.row() % 256 == 0)
{
//std::cout << tiled_ima(p);
tiled_ima(p) = literal::green;
Index: trunk/milena/sandbox/fabien/mln/core/image/cache.hh
===================================================================
--- trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 4490)
+++ trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 4491)
@@ -49,10 +49,13 @@
void set_number_pages(unsigned number_pages);
V read(mln_psite(D) p);
void write(const mln_psite(D)& p, const V& value);
+ unsigned insert_new_page(const mln_psite(D)& p);
protected:
util::array<page<D, V>* > pages_;
+ util::array<unsigned> order_;
+ unsigned count_;
unsigned number_pages_;
// Image info.
@@ -70,7 +73,8 @@
inline
cache<D, V>::cache(D domain, std::streampos pos, unsigned ncols, std::fstream* f)
{
- this->number_pages_ = 1;
+ this->number_pages_ = 5; // Default value.
+ this->count_ = 1;
this->domain_ = domain;
this->pos_ = pos;
@@ -85,6 +89,7 @@
for (unsigned i = 0; i < this->pages_.nelements(); ++i)
delete this->pages_[i];
this->pages_.clear();
+ this->order_.clear();
}
template <typename D, typename V>
@@ -92,6 +97,10 @@
void
cache<D, V>::set_number_pages(unsigned number_pages)
{
+ if (number_pages == 0)
+ {
+ // FIXME: We must not allow that.
+ }
if (number_pages < this->number_pages_)
{
// FIXME: Prune pages array.
@@ -110,15 +119,9 @@
return this->pages_[i]->read(p);
}
- // If we have not found a valid page, we just add one.
- // FIXME: We should test that we have room for a new page.
- page<D, V>* new_page = new page<D, V>(this->domain_,
- p,
- this->pos_,
- this->ncols_,
- this->f_);
- this->pages_.append(new_page);
- return new_page->read(p);
+ // In case we have not found a valid page, we insert a new one.
+ unsigned new_page_index = insert_new_page(p);
+ return this->pages_[new_page_index]->read(p);
}
template <typename D, typename V>
@@ -136,19 +139,57 @@
}
}
+ // In case we have not found a valid page, we insert a new one.
if (!found)
{
- // If we have not found a valid page, we just add one.
- // FIXME: We should test that we have room for a new page.
+ unsigned new_page_index = insert_new_page(p);
+ this->pages_[new_page_index]->write(p, value);
+ }
+ }
+
+ // Basic LRU cache algorithm implementation.
+ template <typename D, typename V>
+ inline
+ unsigned
+ cache<D, V>::insert_new_page(const mln_psite(D)& p)
+ {
page<D, V>* new_page = new page<D, V>(this->domain_,
p,
this->pos_,
this->ncols_,
this->f_);
+
+ unsigned new_index;
+
+ // If there is still room for a new page.
+ if (this->pages_.nelements() < this->number_pages_)
+ {
this->pages_.append(new_page);
- new_page->write(p, value);
+ this->order_.append(this->count_++);
+ new_index = this->pages_.nelements() - 1;
+ }
+ else // We must find which page to discard.
+ {
+ unsigned min = this->order_[0];
+ unsigned new_index = 0;
+ for (unsigned i = 1; i < this->pages_.nelements(); ++i)
+ {
+ if (this->order_[i] < min)
+ {
+ min = this->order_[i];
+ new_index = i;
}
}
+ delete this->pages_[new_index];
+ this->pages_[new_index] = new_page;
+ for (unsigned i = 0; i < this->order_.nelements(); ++i)
+ this->order_[i] -= min;
+ this->count_ -= min;
+ this->order_[new_index] = this->count_++;
+ }
+
+ return new_index;
+ }
# endif // ! MLN_INCLUDE_ONLY
1
0
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2009-09-16 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Add experimental cache support in 2D tiled image.
* fabien/mln/core/image/cache.hh: Implement cache management.
* fabien/mln/core/image/page.hh: Implement page management.
* fabien/mln/core/image/tiled2d.hh: Add cache management.
* fabien/tests/core/image/Makefile: Minor update.
* fabien/tests/core/image/tiled2d.cc: Minor update.
---
mln/core/image/cache.hh | 159 ++++++++++++++++++++++++++++++++++++++++++++
mln/core/image/page.hh | 155 ++++++++++++++++++++++++++++++++++++++++++
mln/core/image/tiled2d.hh | 37 ++++++----
tests/core/image/Makefile | 2
tests/core/image/tiled2d.cc | 7 +
5 files changed, 345 insertions(+), 15 deletions(-)
Index: trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc
===================================================================
--- trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4489)
+++ trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4490)
@@ -43,10 +43,13 @@
mln_piter_(tiled2d<rgb8>) p(tiled_ima.domain());
for_all(p)
- if (p.col() % 16 == 0)
+ if (p.row() % 7 == 0)
+ {
+ //std::cout << tiled_ima(p);
tiled_ima(p) = literal::green;
- //std::cout << tiled_ima(p) << std::endl;
+ //std::cout << " -> " << tiled_ima(p) << std::endl;
//mln_assertion(tiled_ima(p) == ima(p));
+ }
/*for_all(p)
if (p.col() % 16 == 0)
Index: trunk/milena/sandbox/fabien/tests/core/image/Makefile
===================================================================
--- trunk/milena/sandbox/fabien/tests/core/image/Makefile (revision 4489)
+++ trunk/milena/sandbox/fabien/tests/core/image/Makefile (revision 4490)
@@ -3,5 +3,7 @@
LIBS = `Magick++-config --cppflags --cxxflags --ldflags --libs`
INC = -I../../../ -I../../../../../
+all: tiled2d
+
tiled2d: tiled2d.cc
${CXX} ${CXXFLAGS} ${INC} $^ -o tiled2d
Index: trunk/milena/sandbox/fabien/mln/core/image/cache.hh
===================================================================
--- trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 0)
+++ trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 4490)
@@ -0,0 +1,159 @@
+// Copyright (C) 2009 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 MLN_CORE_IMAGE_CACHE_HH
+# define MLN_CORE_IMAGE_CACHE_HH
+
+/// \file
+/// Definition of the basic mln::cache class.
+
+#include <mln/util/array.hh>
+
+#include <mln/core/image/page.hh>
+
+
+namespace mln
+{
+
+ template <typename D, typename V>
+ class cache
+ {
+ public:
+
+ // Constructor
+ cache(D domain, std::streampos pos, unsigned ncols, std::fstream* f);
+ ~cache();
+
+ void set_number_pages(unsigned number_pages);
+ V read(mln_psite(D) p);
+ void write(const mln_psite(D)& p, const V& value);
+
+ protected:
+
+ util::array<page<D, V>* > pages_;
+ unsigned number_pages_;
+
+ // Image info.
+ D domain_;
+ std::streampos pos_;
+ unsigned ncols_;
+ std::fstream* f_;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename D, typename V>
+ inline
+ cache<D, V>::cache(D domain, std::streampos pos, unsigned ncols, std::fstream* f)
+ {
+ this->number_pages_ = 1;
+
+ this->domain_ = domain;
+ this->pos_ = pos;
+ this->ncols_ = ncols;
+ this->f_ = f;
+ }
+
+ template <typename D, typename V>
+ inline
+ cache<D, V>::~cache()
+ {
+ for (unsigned i = 0; i < this->pages_.nelements(); ++i)
+ delete this->pages_[i];
+ this->pages_.clear();
+ }
+
+ template <typename D, typename V>
+ inline
+ void
+ cache<D, V>::set_number_pages(unsigned number_pages)
+ {
+ if (number_pages < this->number_pages_)
+ {
+ // FIXME: Prune pages array.
+ }
+ this->number_pages_ = number_pages;
+ }
+
+ template <typename D, typename V>
+ inline
+ V
+ cache<D, V>::read(mln_psite(D) p)
+ {
+ for (unsigned i = 0; i < this->pages_.nelements(); ++i)
+ {
+ if (this->pages_[i]->has(p))
+ return this->pages_[i]->read(p);
+ }
+
+ // If we have not found a valid page, we just add one.
+ // FIXME: We should test that we have room for a new page.
+ page<D, V>* new_page = new page<D, V>(this->domain_,
+ p,
+ this->pos_,
+ this->ncols_,
+ this->f_);
+ this->pages_.append(new_page);
+ return new_page->read(p);
+ }
+
+ template <typename D, typename V>
+ inline
+ void
+ cache<D, V>::write(const mln_psite(D)& p, const V& value)
+ {
+ bool found = false;
+ for (unsigned i = 0; !found && i < this->pages_.nelements(); ++i)
+ {
+ if (this->pages_[i]->has(p))
+ {
+ this->pages_[i]->write(p, value);
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ // If we have not found a valid page, we just add one.
+ // FIXME: We should test that we have room for a new page.
+ page<D, V>* new_page = new page<D, V>(this->domain_,
+ p,
+ this->pos_,
+ this->ncols_,
+ this->f_);
+ this->pages_.append(new_page);
+ new_page->write(p, value);
+ }
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_IMAGE_CACHE_HH
Index: trunk/milena/sandbox/fabien/mln/core/image/tiled2d.hh
===================================================================
--- trunk/milena/sandbox/fabien/mln/core/image/tiled2d.hh (revision 4489)
+++ trunk/milena/sandbox/fabien/mln/core/image/tiled2d.hh (revision 4490)
@@ -39,6 +39,8 @@
# include <mln/fun/i2v/all_to.hh>
# include <mln/value/proxy.hh>
+# include <mln/core/image/cache.hh>
+
namespace mln
@@ -63,6 +65,7 @@
std::string file_;
bool loaded_;
T value_;
+ cache<box2d, T>* cache_;
box2d b_; // theoretical box
unsigned bdr_;
@@ -323,8 +326,11 @@
data< tiled2d<T> >::deallocate_()
{
if (this->loaded_)
+ {
+ delete this->cache_;
this->f_->close();
}
+ }
template <typename T>
inline
@@ -428,13 +434,18 @@
{
this_->data_->f_ = new std::fstream(this->data_->file_.c_str());
this_->data_->loaded_ = true;
+ this_->data_->cache_ = new cache<box2d, T>(this_->data_->b_,
+ this_->data_->pos_,
+ this_->ncols(),
+ this_->data_->f_);
}
- std::streampos offset = this_->data_->pos_;
+ /*std::streampos offset = this_->data_->pos_;
offset += (this_->ncols() * p.row() + p.col()) * sizeof(T);
this_->data_->f_->seekg(offset);
this_->data_->f_->get((char*)(&this_->data_->value_), sizeof(T) + 1); // FIXME: I don't know why
// I have to add +1.
- return this_->data_->value_;
+ return this_->data_->value_;*/
+ return this_->data_->cache_->read(p);
}
template <typename T>
@@ -442,15 +453,17 @@
void
tiled2d<T>::write_(const point2d& p, const T& value)
{
- if (!this->data_->loaded_)
+ mln::tiled2d<T>* this_ = const_cast<mln::tiled2d<T>* >(this); // Trust me, I have to do this(_).
+ if (!this_->data_->loaded_)
{
- this->data_->f_ = new std::fstream(this->data_->file_.c_str());
- this->data_->loaded_ = true;
+ this_->data_->f_ = new std::fstream(this->data_->file_.c_str());
+ this_->data_->loaded_ = true;
+ this_->data_->cache_ = new cache<box2d, T>(this_->data_->b_,
+ this_->data_->pos_,
+ this_->ncols(),
+ this_->data_->f_);
}
- std::streampos offset = this->data_->pos_;
- offset += (this->ncols() * p.row() + p.col()) * sizeof(T);
- this->data_->f_->seekp(offset);
- this->data_->f_->write((char*)(&value), sizeof(T));
+ this_->data_->cache_->write(p, value);
}
@@ -462,8 +475,7 @@
tiled2d<T>::at_(unsigned row, unsigned col) const
{
mln_precondition(this->has(point2d(row, col)));
- //FIXME: use the cache Luke.
- return this->data_->value_;
+ return this->data_->cache_(point2d(row, col));
}
template <typename T>
@@ -472,8 +484,7 @@
tiled2d<T>::at_(unsigned row, unsigned col)
{
mln_precondition(this->has(point2d(row, col)));
- //FIXME: use the cache Luke.
- return this->data_->value_;
+ return this->data_->cache_(point2d(row, col));
}
template <typename T>
Index: trunk/milena/sandbox/fabien/mln/core/image/page.hh
===================================================================
--- trunk/milena/sandbox/fabien/mln/core/image/page.hh (revision 0)
+++ trunk/milena/sandbox/fabien/mln/core/image/page.hh (revision 4490)
@@ -0,0 +1,155 @@
+// Copyright (C) 2009 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 MLN_CORE_IMAGE_PAGE_HH
+# define MLN_CORE_IMAGE_PAGE_HH
+
+/// \file
+/// Definition of the basic mln::page class.
+
+# include <fstream>
+
+# include <mln/util/array.hh>
+
+
+namespace mln
+{
+
+ template <typename D, typename V>
+ class page
+ {
+ public:
+
+ // Constructor & destructor.
+ page(D domain, mln_psite(D) p, std::streampos pos, unsigned ncols, std::fstream* f);
+ ~page();
+
+ bool has(mln_psite(D) p);
+ V read(mln_psite(D) p);
+ void write(const mln_psite(D)& p, const V& value);
+ void flush();
+
+ // Debug.
+ void print_buffer();
+
+ protected:
+
+ D domain_;
+ D range_;
+ V* buffer_;
+ std::fstream* f_;
+ std::streampos offset_;
+ unsigned buffer_size_;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename D, typename V>
+ inline
+ page<D, V>::page(D domain, mln_psite(D) p, std::streampos pos, unsigned ncols, std::fstream* f)
+ {
+ // Defining layout for a line.
+ this->range_.pmin() = p;
+ this->range_.pmin().col() = domain.pmin().col();
+ this->range_.pmax() = p;
+ this->range_.pmax().col() = domain.pmax().col();
+
+ this->buffer_ = new V[ncols];
+
+ this->domain_ = domain;
+ this->f_ = f;
+ this->buffer_size_ = ncols;
+
+ this->offset_ = pos;
+ this->offset_ += (ncols * p.row()) * sizeof(V);
+ f->seekg(this->offset_);
+ f->get((char*)(buffer_), buffer_size_ * sizeof(V));
+ }
+
+ template <typename D, typename V>
+ inline
+ page<D, V>::~page()
+ {
+ this->flush();
+ delete this->buffer_;
+ }
+
+ template <typename D, typename V>
+ inline
+ bool
+ page<D, V>::has(mln_psite(D) p)
+ {
+ return p.col() >= this->range_.pmin().col() &&
+ p.col() <= this->range_.pmax().col() &&
+ p.row() >= this->range_.pmin().row() &&
+ p.row() <= this->range_.pmax().row();
+ }
+
+ template <typename D, typename V>
+ inline
+ V
+ page<D, V>::read(mln_psite(D) p)
+ {
+ return buffer_[p.col() - this->range_.pmin().col()];
+ }
+
+ template <typename D, typename V>
+ inline
+ void
+ page<D, V>::write(const mln_psite(D)& p, const V& value)
+ {
+ buffer_[p.col() - this->range_.pmin().col()] = value;
+ }
+
+ template <typename D, typename V>
+ inline
+ void
+ page<D, V>::flush()
+ {
+ this->f_->seekg(this->offset_);
+ this->f_->write((char*)(buffer_), buffer_size_ * sizeof(V));
+ }
+
+
+ // Debug.
+
+ template <typename D, typename V>
+ inline
+ void
+ page<D, V>::print_buffer()
+ {
+ for (unsigned i = 0; i < this->buffer_size_; ++i)
+ std::cout << "buffer[" << i << "] = " << this->buffer_[i] << std::endl;
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_IMAGE_PAGE_HH
1
0
* headers.mk,
* tests/unit_test/unit-tests.mk: Regen.
* estim/object_groups_v_thickness.hh,
* primitive/extract/lines_h_thick_and_single.hh,
* primitive/extract/lines_v_thick_and_single.hh: Add missing headers.
* src/text_in_photo.cc: Fix an undeclared variable.
---
scribo/ChangeLog | 13 +++++++++++++
scribo/headers.mk | 16 ++++++++++++++++
.../primitive/extract/lines_h_thick_and_single.hh | 1 -
.../primitive/extract/lines_v_thick_and_single.hh | 1 -
scribo/src/text_in_photo.cc | 3 ++-
scribo/tests/unit_test/unit-tests.mk | 16 ++++++++++++++++
6 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 82d8a53..47627e0 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,18 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ Small fixes in Scribo.
+
+ * headers.mk,
+ * tests/unit_test/unit-tests.mk: Regen.
+
+ * estim/object_groups_v_thickness.hh,
+ * primitive/extract/lines_h_thick_and_single.hh,
+ * primitive/extract/lines_v_thick_and_single.hh: Add missing headers.
+
+ * src/text_in_photo.cc: Fix an undeclared variable.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
Add new primitive extraction routines.
* primitive/extract/lines_h_thick_and_single.hh,
diff --git a/scribo/headers.mk b/scribo/headers.mk
index 8ca14cf..15d9b2a 100644
--- a/scribo/headers.mk
+++ b/scribo/headers.mk
@@ -2,6 +2,7 @@
scribodir = $(includedir)/scribo
nobase_scribo_HEADERS = \
./all.hh \
+./binarization/sauvola.hh \
./binarization/simple.hh \
./core/all.hh \
./core/central_sites.hh \
@@ -11,6 +12,7 @@ nobase_scribo_HEADERS = \
./core/object_image.hh \
./core/object_links.hh \
./debug/all.hh \
+./debug/decision_image.hh \
./debug/save_bboxes_image.hh \
./debug/save_label_image.hh \
./debug/save_linked_bboxes_image.hh \
@@ -20,9 +22,20 @@ nobase_scribo_HEADERS = \
./draw/all.hh \
./draw/bounding_box_links.hh \
./draw/bounding_boxes.hh \
+./estim/object_groups_v_thickness.hh \
./filter/all.hh \
+./filter/common/object_groups_photo.hh \
+./filter/common/object_links_photo.hh \
+./filter/common/objects_photo.hh \
./filter/object_groups_small.hh \
+./filter/object_groups_v_thickness.hh \
+./filter/object_links_bbox_h_ratio.hh \
+./filter/object_links_bbox_overlap.hh \
+./filter/object_links_bbox_ratio.hh \
+./filter/object_links_bbox_w_ratio.hh \
+./filter/object_links_bottom_aligned.hh \
./filter/object_links_non_aligned.hh \
+./filter/object_links_non_aligned_simple.hh \
./filter/object_links_non_h_aligned.hh \
./filter/object_links_non_v_aligned.hh \
./filter/objects_large.hh \
@@ -35,6 +48,7 @@ nobase_scribo_HEADERS = \
./make/influence_zone_graph.hh \
./make/text.hh \
./preprocessing/all.hh \
+./preprocessing/split_bg_fg.hh \
./preprocessing/unskew.hh \
./primitive/all.hh \
./primitive/extract/all.hh \
@@ -45,12 +59,14 @@ nobase_scribo_HEADERS = \
./primitive/extract/lines_h_pattern.hh \
./primitive/extract/lines_h_single.hh \
./primitive/extract/lines_h_thick.hh \
+./primitive/extract/lines_h_thick_and_single.hh \
./primitive/extract/lines_pattern.hh \
./primitive/extract/lines_thick.hh \
./primitive/extract/lines_v_discontinued.hh \
./primitive/extract/lines_v_pattern.hh \
./primitive/extract/lines_v_single.hh \
./primitive/extract/lines_v_thick.hh \
+./primitive/extract/lines_v_thick_and_single.hh \
./primitive/extract/objects.hh \
./primitive/group/all.hh \
./primitive/group/apply.hh \
diff --git a/scribo/primitive/extract/lines_h_thick_and_single.hh b/scribo/primitive/extract/lines_h_thick_and_single.hh
index a4803aa..969acf5 100644
--- a/scribo/primitive/extract/lines_h_thick_and_single.hh
+++ b/scribo/primitive/extract/lines_h_thick_and_single.hh
@@ -103,7 +103,6 @@ namespace scribo
mln_precondition(exact(input).is_valid());
mln_precondition(exact(nbh).is_valid());
- mln_precondition(exact(win).is_valid());
(void) nlines;
}
diff --git a/scribo/primitive/extract/lines_v_thick_and_single.hh b/scribo/primitive/extract/lines_v_thick_and_single.hh
index 8c9048c..7ddd25f 100644
--- a/scribo/primitive/extract/lines_v_thick_and_single.hh
+++ b/scribo/primitive/extract/lines_v_thick_and_single.hh
@@ -102,7 +102,6 @@ namespace scribo
mln_precondition(exact(input).is_valid());
mln_precondition(exact(nbh).is_valid());
- mln_precondition(exact(win).is_valid());
(void) nlines;
}
diff --git a/scribo/src/text_in_photo.cc b/scribo/src/text_in_photo.cc
index 152e9b2..5426dce 100644
--- a/scribo/src/text_in_photo.cc
+++ b/scribo/src/text_in_photo.cc
@@ -202,7 +202,8 @@ highlighted.");
#ifndef NOUT
- image2d<value::rgb8>
+ image2d<value::rgb8> decision_image;
+ if (argc == 4)
decision_image = scribo::debug::decision_image(input,
groups, filtered_groups);
#endif
diff --git a/scribo/tests/unit_test/unit-tests.mk b/scribo/tests/unit_test/unit-tests.mk
index 51a7da1..6b44ef9 100644
--- a/scribo/tests/unit_test/unit-tests.mk
+++ b/scribo/tests/unit_test/unit-tests.mk
@@ -21,8 +21,13 @@ scribo_debug_usage \
scribo_draw_all \
scribo_draw_bounding_box_links \
scribo_draw_bounding_boxes \
+scribo_estim_object_groups_v_thickness \
scribo_filter_all \
+scribo_filter_common_object_groups_photo \
+scribo_filter_common_object_links_photo \
+scribo_filter_common_objects_photo \
scribo_filter_object_groups_small \
+scribo_filter_object_groups_v_thickness \
scribo_filter_object_links_bbox_h_ratio \
scribo_filter_object_links_bbox_overlap \
scribo_filter_object_links_bbox_ratio \
@@ -42,6 +47,7 @@ scribo_make_debug_filename \
scribo_make_influence_zone_graph \
scribo_make_text \
scribo_preprocessing_all \
+scribo_preprocessing_split_bg_fg \
scribo_preprocessing_unskew \
scribo_primitive_all \
scribo_primitive_extract_all \
@@ -52,12 +58,14 @@ scribo_primitive_extract_lines_h_discontinued \
scribo_primitive_extract_lines_h_pattern \
scribo_primitive_extract_lines_h_single \
scribo_primitive_extract_lines_h_thick \
+scribo_primitive_extract_lines_h_thick_and_single \
scribo_primitive_extract_lines_pattern \
scribo_primitive_extract_lines_thick \
scribo_primitive_extract_lines_v_discontinued \
scribo_primitive_extract_lines_v_pattern \
scribo_primitive_extract_lines_v_single \
scribo_primitive_extract_lines_v_thick \
+scribo_primitive_extract_lines_v_thick_and_single \
scribo_primitive_extract_objects \
scribo_primitive_group_all \
scribo_primitive_group_apply \
@@ -123,8 +131,13 @@ scribo_debug_usage_SOURCES = scribo_debug_usage.cc
scribo_draw_all_SOURCES = scribo_draw_all.cc
scribo_draw_bounding_box_links_SOURCES = scribo_draw_bounding_box_links.cc
scribo_draw_bounding_boxes_SOURCES = scribo_draw_bounding_boxes.cc
+scribo_estim_object_groups_v_thickness_SOURCES = scribo_estim_object_groups_v_thickness.cc
scribo_filter_all_SOURCES = scribo_filter_all.cc
+scribo_filter_common_object_groups_photo_SOURCES = scribo_filter_common_object_groups_photo.cc
+scribo_filter_common_object_links_photo_SOURCES = scribo_filter_common_object_links_photo.cc
+scribo_filter_common_objects_photo_SOURCES = scribo_filter_common_objects_photo.cc
scribo_filter_object_groups_small_SOURCES = scribo_filter_object_groups_small.cc
+scribo_filter_object_groups_v_thickness_SOURCES = scribo_filter_object_groups_v_thickness.cc
scribo_filter_object_links_bbox_h_ratio_SOURCES = scribo_filter_object_links_bbox_h_ratio.cc
scribo_filter_object_links_bbox_overlap_SOURCES = scribo_filter_object_links_bbox_overlap.cc
scribo_filter_object_links_bbox_ratio_SOURCES = scribo_filter_object_links_bbox_ratio.cc
@@ -144,6 +157,7 @@ scribo_make_debug_filename_SOURCES = scribo_make_debug_filename.cc
scribo_make_influence_zone_graph_SOURCES = scribo_make_influence_zone_graph.cc
scribo_make_text_SOURCES = scribo_make_text.cc
scribo_preprocessing_all_SOURCES = scribo_preprocessing_all.cc
+scribo_preprocessing_split_bg_fg_SOURCES = scribo_preprocessing_split_bg_fg.cc
scribo_preprocessing_unskew_SOURCES = scribo_preprocessing_unskew.cc
scribo_primitive_all_SOURCES = scribo_primitive_all.cc
scribo_primitive_extract_all_SOURCES = scribo_primitive_extract_all.cc
@@ -154,12 +168,14 @@ scribo_primitive_extract_lines_h_discontinued_SOURCES = scribo_primitive_extract
scribo_primitive_extract_lines_h_pattern_SOURCES = scribo_primitive_extract_lines_h_pattern.cc
scribo_primitive_extract_lines_h_single_SOURCES = scribo_primitive_extract_lines_h_single.cc
scribo_primitive_extract_lines_h_thick_SOURCES = scribo_primitive_extract_lines_h_thick.cc
+scribo_primitive_extract_lines_h_thick_and_single_SOURCES = scribo_primitive_extract_lines_h_thick_and_single.cc
scribo_primitive_extract_lines_pattern_SOURCES = scribo_primitive_extract_lines_pattern.cc
scribo_primitive_extract_lines_thick_SOURCES = scribo_primitive_extract_lines_thick.cc
scribo_primitive_extract_lines_v_discontinued_SOURCES = scribo_primitive_extract_lines_v_discontinued.cc
scribo_primitive_extract_lines_v_pattern_SOURCES = scribo_primitive_extract_lines_v_pattern.cc
scribo_primitive_extract_lines_v_single_SOURCES = scribo_primitive_extract_lines_v_single.cc
scribo_primitive_extract_lines_v_thick_SOURCES = scribo_primitive_extract_lines_v_thick.cc
+scribo_primitive_extract_lines_v_thick_and_single_SOURCES = scribo_primitive_extract_lines_v_thick_and_single.cc
scribo_primitive_extract_objects_SOURCES = scribo_primitive_extract_objects.cc
scribo_primitive_group_all_SOURCES = scribo_primitive_group_all.cc
scribo_primitive_group_apply_SOURCES = scribo_primitive_group_apply.cc
--
1.5.6.5
1
0
* primitive/extract/lines_h_thick_and_single.hh,
* primitive/extract/lines_v_thick_and_single.hh: New.
---
scribo/ChangeLog | 7 +
.../primitive/extract/lines_h_thick_and_single.hh | 149 ++++++++++++++++++++
.../primitive/extract/lines_v_thick_and_single.hh | 147 +++++++++++++++++++
3 files changed, 303 insertions(+), 0 deletions(-)
create mode 100644 scribo/primitive/extract/lines_h_thick_and_single.hh
create mode 100644 scribo/primitive/extract/lines_v_thick_and_single.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 51f38a0..82d8a53 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,12 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ Add new primitive extraction routines.
+
+ * primitive/extract/lines_h_thick_and_single.hh,
+ * primitive/extract/lines_v_thick_and_single.hh: New.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
* preprocessing/split_bg_fg.hh: Add a new algorithm to split
background and foreground.
diff --git a/scribo/primitive/extract/lines_h_thick_and_single.hh b/scribo/primitive/extract/lines_h_thick_and_single.hh
new file mode 100644
index 0000000..a4803aa
--- /dev/null
+++ b/scribo/primitive/extract/lines_h_thick_and_single.hh
@@ -0,0 +1,149 @@
+// Copyright (C) 2009 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_PRIMITIVE_EXTRACT_LINES_H_THICK_AND_SINGLE_HH
+# define SCRIBO_PRIMITIVE_EXTRACT_LINES_H_THICK_AND_SINGLE_HH
+
+/// \file
+///
+/// Extract horizontal thick lines in a binary image.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/window.hh>
+# include <mln/core/concept/neighborhood.hh>
+
+# include <mln/morpho/opening/structural.hh>
+
+# include <scribo/core/object_image.hh>
+# include <scribo/core/macros.hh>
+# include <scribo/primitive/extract/objects.hh>
+
+# include <scribo/primitive/extract/lines_h_thick.hh>
+# include <scribo/primitive/extract/lines_h_single.hh>
+
+
+namespace scribo
+{
+
+ namespace primitive
+ {
+
+ namespace extract
+ {
+
+
+ using namespace mln;
+
+ /// Extract horizontal thick lines in a binary image.
+ /*!
+ * Only non discontinued lines are correctly extracted with this routine.
+ * Only lines matching the given criterions are kept in the result.
+ *
+ * \param[in] input_ A binary image.
+ * \param[in] nbh_ The neighborhood used for labeling image
+ * components.
+ * \param[in,out] nlines Type used for labeling.
+ * \param[in] line_length The minimum line length.
+ * \param[in] w_h_ratio The minimum ratio width/height object
+ * bounding boxes to consider an
+ * object as a single line.
+ *
+ * \return An image in which lines are labeled.
+ */
+ template <typename I, typename N, typename V>
+ object_image(mln_ch_value(I,V))
+ lines_h_thick_and_single(const Image<I>& input_,
+ const Neighborhood<N>& nbh_,
+ V& nlines,
+ unsigned min_line_length,
+ float h_w_ratio);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ namespace internal
+ {
+
+ template <typename I, typename N, typename V>
+ void
+ lines_h_thick_and_single_tests(const Image<I>& input,
+ const Neighborhood<N>& nbh,
+ V& nlines,
+ unsigned min_line_length,
+ float h_w_ratio)
+ {
+ mlc_equal(mln_value(I),bool)::check();
+ mlc_bool(mln_site_(I)::dim == 2)::check();
+ mlc_is_a(V, mln::value::Symbolic)::check();
+
+ mln_precondition(exact(input).is_valid());
+ mln_precondition(exact(nbh).is_valid());
+ mln_precondition(exact(win).is_valid());
+
+ (void) nlines;
+ }
+
+ } // end of namespace scribo::primitive::internal
+
+
+
+ template <typename I, typename N, typename V>
+ inline
+ object_image(mln_ch_value(I,V))
+ lines_h_thick_and_single(const Image<I>& input,
+ const Neighborhood<N>& nbh,
+ V& nlines,
+ unsigned min_line_length,
+ float h_w_ratio)
+ {
+ trace::entering("scribo::primitive::lines_h_thick_and_single");
+
+ internal::lines_h_thick_and_single_tests(input, nbh,
+ nlines,
+ min_line_length,
+ h_w_ratio);
+
+ object_image(mln_ch_value(I,V))
+ output = lines_h_thick(input, nbh, nlines, min_line_length);
+
+ output = lines_h_single(output, min_line_length, h_w_ratio);
+
+ trace::exiting("scribo::primitive::lines_h_thick_and_single");
+ return output;
+ }
+
+
+# endif // !MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::primitive::extract
+
+ } // end of namespace scribo::primitive
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_PRIMITIVE_EXTRACT_LINES_H_THICK_AND_SINGLE_HH
diff --git a/scribo/primitive/extract/lines_v_thick_and_single.hh b/scribo/primitive/extract/lines_v_thick_and_single.hh
new file mode 100644
index 0000000..8c9048c
--- /dev/null
+++ b/scribo/primitive/extract/lines_v_thick_and_single.hh
@@ -0,0 +1,147 @@
+// Copyright (C) 2009 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_PRIMITIVE_EXTRACT_LINES_V_THICK_AND_SINGLE_HH
+# define SCRIBO_PRIMITIVE_EXTRACT_LINES_V_THICK_AND_SINGLE_HH
+
+/// \file
+///
+/// Extract vertical thick lines in a binary image.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/window.hh>
+# include <mln/core/concept/neighborhood.hh>
+
+# include <mln/morpho/opening/structural.hh>
+
+# include <scribo/core/object_image.hh>
+# include <scribo/core/macros.hh>
+# include <scribo/primitive/extract/objects.hh>
+
+# include <scribo/primitive/extract/lines_v_thick.hh>
+# include <scribo/primitive/extract/lines_v_single.hh>
+
+namespace scribo
+{
+
+ namespace primitive
+ {
+
+ namespace extract
+ {
+
+
+ using namespace mln;
+
+ /// Extract vertical thick lines in a binary image.
+ /*!
+ * Only non discontinued lines are correctly extracted with this routine.
+ * Only lines matching the given criterions are kept in the result.
+ *
+ * \param[in] input_ A binary image.
+ * \param[in] nbh_ The neighborhood used for labeling image
+ * components.
+ * \param[in,out] nlines Type used for labeling.
+ * \param[in] line_length The minimum line length.
+ * \param[in] h_w_ratio The minimum ratio height/width object
+ * bounding boxes to consider an
+ * object as a single line.
+ *
+ * \return An image in which lines are labeled.
+ */
+ template <typename I, typename N, typename V>
+ object_image(mln_ch_value(I,V))
+ lines_v_thick_and_single(const Image<I>& input_,
+ const Neighborhood<N>& nbh_,
+ V& nlines,
+ unsigned min_line_length,
+ float h_w_ratio);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ namespace internal
+ {
+
+ template <typename I, typename N, typename V>
+ void
+ lines_v_thick_and_single_tests(const Image<I>& input,
+ const Neighborhood<N>& nbh,
+ V& nlines,
+ unsigned min_line_length,
+ float h_w_ratio)
+ {
+ mlc_equal(mln_value(I),bool)::check();
+ mlc_bool(mln_site_(I)::dim == 2)::check();
+ mlc_is_a(V, mln::value::Symbolic)::check();
+
+ mln_precondition(exact(input).is_valid());
+ mln_precondition(exact(nbh).is_valid());
+ mln_precondition(exact(win).is_valid());
+
+ (void) nlines;
+ }
+
+ } // end of namespace scribo::primitive::internal
+
+
+
+ template <typename I, typename N, typename V>
+ inline
+ object_image(mln_ch_value(I,V))
+ lines_v_thick_and_single(const Image<I>& input,
+ const Neighborhood<N>& nbh,
+ V& nlines,
+ unsigned min_line_length,
+ float h_w_ratio)
+ {
+ trace::entering("scribo::primitive::lines_v_thick_and_single");
+
+ internal::lines_v_thick_and_single_tests(input, nbh,
+ nlines,
+ min_line_length, h_w_ratio);
+
+ object_image(mln_ch_value(I,V))
+ output = lines_v_thick(input, nbh, nlines, min_line_length);
+
+ output = lines_v_single(output, min_line_length, h_w_ratio);
+
+ trace::exiting("scribo::primitive::lines_v_thick_and_single");
+ return output;
+ }
+
+
+# endif // !MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::primitive::extract
+
+ } // end of namespace scribo::primitive
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_PRIMITIVE_EXTRACT_LINES_V_THICK_AND_SINGLE_HH
--
1.5.6.5
1
0
4487: preprocessing/split_bg_fg.hh: Add a new algorithm to split background and foreground.
by Guillaume Lazzara 16 Sep '09
by Guillaume Lazzara 16 Sep '09
16 Sep '09
---
scribo/ChangeLog | 5 +
scribo/preprocessing/split_bg_fg.hh | 337 +++++++++++++++++++++++++++++++++++
2 files changed, 342 insertions(+), 0 deletions(-)
create mode 100644 scribo/preprocessing/split_bg_fg.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 39c0b92..51f38a0 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,10 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ * preprocessing/split_bg_fg.hh: Add a new algorithm to split
+ background and foreground.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
Improve Scribo's demo.
* demo/src/mainwindow.cc,
diff --git a/scribo/preprocessing/split_bg_fg.hh b/scribo/preprocessing/split_bg_fg.hh
new file mode 100644
index 0000000..7e05d0d
--- /dev/null
+++ b/scribo/preprocessing/split_bg_fg.hh
@@ -0,0 +1,337 @@
+// Copyright (C) 2009 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_PREPROCESSING_SPLIT_BG_FG_HH
+# define SCRIBO_PREPROCESSING_SPLIT_BG_FG_HH
+
+/// \file
+///
+/// Split the background and the foreground.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/core/routine/duplicate.hh>
+
+# include <mln/core/image/dmorph/image_if.hh>
+# include <mln/pw/all.hh>
+
+# include <mln/data/fill.hh>
+# include <mln/data/transform.hh>
+
+# include <mln/value/int_u8.hh>
+# include <mln/value/rgb8.hh>
+
+# include <mln/io/ppm/load.hh>
+# include <mln/io/ppm/save.hh>
+# include <mln/io/pgm/save.hh>
+# include <mln/io/pbm/save.hh>
+
+# include <mln/math/diff_abs.hh>
+# include <mln/math/min.hh>
+
+# include <mln/morpho/closing/area.hh>
+# include <mln/morpho/opening/area.hh>
+# include <mln/morpho/elementary/dilation.hh>
+
+# include <mln/labeling/blobs.hh>
+# include <mln/labeling/colorize.hh>
+# include <mln/labeling/compute.hh>
+# include <mln/accu/stat/mean.hh>
+
+
+
+
+namespace scribo
+{
+
+ namespace preprocessing
+ {
+
+ using namespace mln;
+
+
+ /*! \brief Split the background and the foreground.
+
+ \param[in] input A color image.
+ \param[in] lambda Lambda used for morphological closing/opening.
+ \param[in] delta Max distance between values in closing and
+ opening image.
+
+ \return A couple of color images. The first is the background
+ and the second is the foreground.
+ */
+ template <typename I>
+ util::couple<mln_concrete(I), mln_concrete(I)>
+ split_bg_fg(const Image<I>& input_, unsigned lambda, unsigned delta);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+
+ // Internal routines.
+
+ namespace internal
+ {
+
+ using value::rgb8;
+
+
+ template <unsigned n>
+ void
+ split(const image2d< value::rgb<n> >& input,
+ // out:
+ image2d< value::int_u<n> >& r,
+ image2d< value::int_u<n> >& g,
+ image2d< value::int_u<n> >& b)
+ {
+ trace::entering("scribo::preprocessing::internal::split");
+ initialize(r, input);
+ initialize(g, input);
+ initialize(b, input);
+
+ // Generic version:
+
+ // mln_piter(box2d) p(input.domain());
+ // for_all(p)
+ // {
+ // r(p) = input(p).red();
+ // g(p) = input(p).green();
+ // b(p) = input(p).blue();
+ // }
+
+ typedef image2d< value::rgb<n> > I;
+ typedef image2d< value::int_u<n> > O;
+
+ mln_pixter(const I) p_i(input);
+ mln_pixter(O) p_r(r);
+ mln_pixter(O) p_g(g);
+ mln_pixter(O) p_b(b);
+ for (p_i.start(), p_r.start(), p_g.start(), p_b.start();
+ p_i.is_valid();
+ p_i.next(), p_r.next(), p_g.next(), p_b.next())
+ {
+ const value::rgb<n>& c = p_i.val();
+ p_r.val() = c.red();
+ p_g.val() = c.green();
+ p_b.val() = c.blue();
+ }
+
+ trace::exiting("scribo::preprocessing::internal::split");
+ }
+
+
+ template <unsigned n>
+ image2d< value::rgb<n> >
+ merge(const image2d< value::int_u<n> >& r,
+ const image2d< value::int_u<n> >& g,
+ const image2d< value::int_u<n> >& b)
+ {
+ trace::entering("scribo::preprocessing::internal::merge");
+ image2d< value::rgb<n> > output(r.domain());
+
+ // mln_piter(box2d) p(output.domain());
+ // for_all(p)
+ // {
+ // value::rgb<n>& c = output(p);
+ // c.red() = r(p);
+ // c.green() = g(p);
+ // c.blue() = b(p);
+ // }
+
+ typedef image2d< value::int_u<n> > I;
+ mln_pixter(const I) p_r(r);
+ mln_pixter(const I) p_g(g);
+ mln_pixter(const I) p_b(b);
+ typedef image2d< value::rgb<n> > O;
+ mln_pixter(O) p_o(output);
+
+ for (p_o.start(), p_r.start(), p_g.start(), p_b.start();
+ p_o.is_valid();
+ p_o.next(), p_r.next(), p_g.next(), p_b.next())
+ {
+ value::rgb<n>& c = p_o.val();
+ c.red() = p_r.val();
+ c.green() = p_g.val();
+ c.blue() = p_b.val();
+ }
+
+ trace::exiting("scribo::preprocessing::internal::merge");
+ return output;
+ }
+
+
+
+ image2d< value::rgb8 >
+ diff_abs(const image2d< value::rgb8 >& input1,
+ const image2d< value::rgb8 >& input2)
+ {
+ image2d< value::rgb8 > output(input1.domain());
+ mln_piter_(box2d) p(input1.domain());
+ for_all(p)
+ {
+ value::rgb8& c = output(p);
+ c.red() = math::diff_abs(input1(p).red(), input2(p).red());
+ c.green() = math::diff_abs(input1(p).green(), input2(p).green());
+ c.blue() = math::diff_abs(input1(p).blue(), input2(p).blue());
+ }
+ return output;
+ }
+
+
+ image2d< value::rgb8 >
+ inverted_diff_abs(const image2d< value::rgb8 >& input1,
+ const image2d< value::rgb8 >& input2)
+ {
+ image2d< value::rgb8 > output(input1.domain());
+ mln_piter_(box2d) p(input1.domain());
+ for_all(p)
+ {
+ value::rgb8& c = output(p);
+// c.red() = 255 - math::diff_abs(input1(p).red(), input2(p).red());
+// c.green() = 255 - math::diff_abs(input1(p).green(), input2(p).green());
+// c.blue() = 255 - math::diff_abs(input1(p).blue(), input2(p).blue());
+
+ c.red() = 255 - math::min(2 * math::diff_abs(input1(p).red(), input2(p).red()), 255);
+ c.green() = 255 - math::min(2 * math::diff_abs(input1(p).green(), input2(p).green()), 255);
+ c.blue() = 255 - math::min(2 * math::diff_abs(input1(p).blue(), input2(p).blue()), 255);
+ }
+ return output;
+ }
+
+
+
+ unsigned dist(const rgb8& c1, const rgb8& c2)
+ {
+ unsigned d = 0;
+ d += std::abs(c1.red() - c2.red());
+ d += std::abs(c1.green() - c2.green());
+ d += std::abs(c1.blue() - c2.blue());
+ return d;
+ }
+
+
+ image2d<rgb8>
+ background_analyze(const image2d<rgb8>& input,
+ unsigned lambda, unsigned delta)
+ {
+ trace::entering("scribo::preprocessing::internal::background_analyze");
+
+ image2d<value::int_u8> r, g, b;
+ split(input, r, g, b);
+ image2d<rgb8> closed, opened;
+ closed = merge(morpho::closing::area(r, c4(), lambda),
+ morpho::closing::area(g, c4(), lambda),
+ morpho::closing::area(b, c4(), lambda));
+ opened = merge(morpho::opening::area(r, c4(), lambda),
+ morpho::opening::area(g, c4(), lambda),
+ morpho::opening::area(b, c4(), lambda));
+
+ image2d<bool> mask(input.domain());
+ mln_piter_(box2d) p(input.domain());
+ for_all(p)
+ mask(p) = (dist(closed(p), opened(p)) >= delta);
+
+ image2d<rgb8> output = duplicate(input);
+ data::fill((output | pw::value(mask)).rw(), rgb8(255,255,0));
+
+// {
+// io::ppm::save(output, "temp_output.ppm");
+// io::pbm::save(mask, "temp_mask.pbm");
+// }
+
+ unsigned nblobs;
+ image2d<unsigned> lab, con;
+ lab = labeling::blobs(mask, c4(), nblobs);
+
+// {
+// io::ppm::save(labeling::colorize(rgb8(),
+// lab,
+// nblobs),
+// "temp_blobs.ppm");
+// }
+
+ con = morpho::elementary::dilation(lab, c8());
+ data::fill((con | (pw::value(lab) != pw::cst(0u))).rw(),
+ 0u);
+
+// {
+// io::ppm::save(labeling::colorize(rgb8(),
+// con,
+// nblobs),
+// "temp_con.ppm");
+// }
+
+ typedef accu::stat::mean< rgb8, algebra::vec<3,float>, rgb8 > A;
+ util::array<rgb8> m = labeling::compute(A(), input, con, nblobs);
+
+ data::fill((output | pw::value(mask)).rw(),
+ data::transform(lab, m));
+
+ trace::exiting("scribo::preprocessing::internal::toggle");
+ return output;
+ }
+
+
+ } // end of namespace scribo::internal
+
+
+
+
+ // Facade
+
+ template <typename I>
+ util::couple<mln_concrete(I), mln_concrete(I)>
+ split_bg_fg(const Image<I>& input_, unsigned lambda, unsigned delta)
+ {
+ trace::entering("scribo::preprocessing::split_bg_fg");
+
+ using namespace mln;
+
+ const I& input = exact(input_);
+
+ mln_precondition(input.is_valid());
+ mln_precondition(lambda >= 1);
+ mln_precondition(delta >= 1);
+
+ image2d<value::rgb8>
+ bg = internal::background_analyze(input, lambda, delta);
+ image2d<value::rgb8> fg = internal::inverted_diff_abs(input, bg);
+
+ trace::exiting("scribo::preprocessing::split_bg_fg");
+ return make::couple(bg, fg);
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace scribo::preprocessing
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_PREPROCESSING_SPLIT_BG_FG_HH
--
1.5.6.5
1
0
* demo/src/mainwindow.cc,
* demo/src/mainwindow.hh: Add "text in doc" demo and improve
progress dialog output.
---
scribo/ChangeLog | 8 ++++
scribo/demo/src/mainwindow.cc | 92 ++++++++++++++++++++++++++++------------
scribo/demo/src/mainwindow.hh | 10 ++++-
3 files changed, 81 insertions(+), 29 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 7f504e6..39c0b92 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,13 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ Improve Scribo's demo.
+
+ * demo/src/mainwindow.cc,
+ * demo/src/mainwindow.hh: Add "text in doc" demo and improve
+ progress dialog output.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
* debug/decision_image.hh: Fix an invalid precondition.
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
diff --git a/scribo/demo/src/mainwindow.cc b/scribo/demo/src/mainwindow.cc
index 1bfaec9..f808d8b 100644
--- a/scribo/demo/src/mainwindow.cc
+++ b/scribo/demo/src/mainwindow.cc
@@ -34,7 +34,8 @@
const char * modes[][4] = {
- { "Text in pictures", "pics", "../src/text_in_photo", "image-x-generic.png" },
+ { "Text in pictures", "pics", "../src/text_in_photo_ppm", "image-x-generic.png" },
+ { "Text in docs", "doc", "../src/text_in_doc", "edit-find.png" },
{ (const char *)(1), 0, 0, 0}, // Separator
{ "Handwritten text lines", "hsc", "../../milena/sandbox/icdar/2009/hsc/input_to_lines", "text-x-generic.png" },
{ "Handwritten text words", "hsc", "../../milena/sandbox/icdar/2009/hsc/input_to_words", "text-x-generic.png" },
@@ -59,6 +60,7 @@ const char * modes[][4] = {
//
const char *args_list[][3] = {
{ 0, 0, 0 }, // Text in Pictures
+ { 0, 0, 0 }, // Text in Docs
{ (const char *)(1), 0, 0}, // Separator
{ "/dev/null", 0, 0 }, // Handwritten text lines
{ "/dev/null", 0, 0 }, // Handwritten text words
@@ -97,13 +99,11 @@ namespace scribo
pdialog_.setLabelText(tr("Please wait while computing..."));
pdialog_.setWindowModality(Qt::WindowModal);
+ exec_.setReadChannel(QProcess::StandardOutput);
+
qDebug() << "Cache located in " << QDir::tempPath();
connect(&pdialog_, SIGNAL(canceled()), this, SLOT(compute_canceled()));
- connect(&exec_, SIGNAL(finished(int, QProcess::ExitStatus)),
- this, SLOT(exec_finished(int, QProcess::ExitStatus)));
- connect(&exec_, SIGNAL(error(QProcess::ProcessError)),
- this, SLOT(exec_error(QProcess::ProcessError)));
connect(&context_, SIGNAL(triggered(QAction *)),
this, SLOT(context_changed(QAction *)));
@@ -118,6 +118,8 @@ namespace scribo
this, SLOT(move_horizontal_sliders(int)));
connect(&timer_, SIGNAL(timeout()), this, SLOT(timer_timeout()));
+ connect_compute_process();
+
context_.setExclusive(true);
// No status bar.
@@ -163,6 +165,7 @@ namespace scribo
action->setCheckable(true);
action->setData(i);
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0 + i));
+ action->setEnabled(QFile::exists(modes[i][2]));
if (modes[i][3] != 0)
action->setIcon(QIcon(QString(":/icons/") + modes[i][3]));
@@ -203,7 +206,8 @@ namespace scribo
void MainWindow::on_runBtn_clicked()
{
- if (useCache->isChecked() && cached_result_[mode_].contains(filepath->text()))
+ if (useCache->isChecked()
+ && cached_result_[mode_].contains(filepath->text()))
{
last_output_ = cached_result_[mode_][filepath->text()];
exec_finished(0, QProcess::NormalExit);
@@ -216,30 +220,20 @@ namespace scribo
QString input = filepath->text();
- // Loading ppm file
- if (current_mode() == "pics")
- {
- QFileInfo f(input);
- QDir dir = f.absoluteDir();
- dir.cd("../pics_pbm");
-
- QFileInfo pbm_file(dir.path() + "/" + f.completeBaseName() + ".pbm");
- if (pbm_file.exists())
- input = pbm_file.absoluteFilePath();
- }
-
args << input;
for (unsigned i = 0; args_list[mode_][i]; ++i)
args << args_list[mode_][i];
// if (!is_in_ocr_mode())
// {
- QTemporaryFile f;
- f.open();
- args << f.fileName();
- last_output_ = f.fileName();
+ QTemporaryFile f;
+ f.open();
+ args << f.fileName();
+ last_output_ = f.fileName();
// }
+// reset_progress_dialog();
+
exec_.start(exec_prefix_ + modes[mode_][2], args);
}
@@ -300,7 +294,8 @@ namespace scribo
QFileInfo finfo(name);
if (item != mainResultItem_ && current_mode() != "hsc"
&& current_mode() != "pproc"
- && (current_mode() != "pics" || finfo.suffix() == "pbm"))
+ && (current_mode() != "pics" || finfo.suffix() == "pbm")
+ && ! is_in_doc_mode())
{
QImage image(pixmap.toImage());
image.invertPixels();
@@ -338,7 +333,7 @@ namespace scribo
cached_result_[mode_][filepath->text()] = last_output_;
setEnabled(true);
- if (is_in_ocr_mode())
+ if (is_in_ocr_mode() || is_in_doc_mode())
{
QFile f(last_output_);
f.open(QIODevice::ReadOnly);
@@ -379,10 +374,12 @@ namespace scribo
void MainWindow::wait_for_result()
{
+ reset_progress_dialog();
+
pdialog_.show();
setEnabled(false);
- if (!is_in_ocr_mode())
+ if (!is_in_ocr_mode() && !is_in_ocr_mode())
update_status_message("");
}
@@ -409,7 +406,6 @@ namespace scribo
void MainWindow::exec_error(QProcess::ProcessError error)
{
- pdialog_.reset();
if (error == QProcess::FailedToStart)
exec_error(tr("This program does not exist: ")
+ exec_prefix_ + modes[mode_][2]);
@@ -423,23 +419,37 @@ namespace scribo
{
mode_ = action->data().toInt();
filepath->clear();
- tabWidget->setTabEnabled(1, is_in_ocr_mode());
+ tabWidget->setTabEnabled(1, is_in_ocr_mode() || is_in_doc_mode());
}
void MainWindow::compute_canceled()
{
setEnabled(true);
+
+ exec_.disconnect();
exec_.kill();
+ connect_compute_process();
+
update_status_message("Computation canceled.");
}
- bool MainWindow::is_in_ocr_mode()
+ bool MainWindow::is_in_ocr_mode() const
{
return current_mode() == "ocr";
}
+ bool MainWindow::is_in_pics_mode() const
+ {
+ return current_mode() == "pics";
+ }
+
+ bool MainWindow::is_in_doc_mode() const
+ {
+ return current_mode() == "doc";
+ }
+
void MainWindow::resize_pixmaps(const QRectF& rect)
{
@@ -528,6 +538,32 @@ namespace scribo
}
}
+
+ void MainWindow::update_process_status()
+ {
+ if (is_in_pics_mode() || is_in_doc_mode())
+ pdialog_.setLabelText(tr(exec_.readAllStandardOutput()));
+ }
+
+
+ void MainWindow::reset_progress_dialog()
+ {
+ pdialog_.reset();
+ pdialog_.setLabelText(tr("Please wait while computing..."));
+ }
+
+
+ void MainWindow::connect_compute_process()
+ {
+ connect(&exec_, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(exec_finished(int, QProcess::ExitStatus)));
+ connect(&exec_, SIGNAL(error(QProcess::ProcessError)),
+ this, SLOT(exec_error(QProcess::ProcessError)));
+ connect(&exec_, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(update_process_status()));
+ }
+
+
} // end of namespace scribo::demo
} // end of namespace scribo
diff --git a/scribo/demo/src/mainwindow.hh b/scribo/demo/src/mainwindow.hh
index 3641658..90ed991 100644
--- a/scribo/demo/src/mainwindow.hh
+++ b/scribo/demo/src/mainwindow.hh
@@ -76,6 +76,8 @@ namespace scribo
void move_horizontal_sliders(int value);
void timer_timeout();
+ void update_process_status();
+
private: // Members
void setup_scene();
void update_pixmap(QGraphicsView* view, const QString& name = QString());
@@ -88,7 +90,9 @@ namespace scribo
void prepare_for_run(const QString& filename);
- bool is_in_ocr_mode();
+ bool is_in_ocr_mode() const;
+ bool is_in_pics_mode() const;
+ bool is_in_doc_mode() const;
QGraphicsItem *& view_to_item(QGraphicsView *view);
@@ -99,6 +103,10 @@ namespace scribo
void update_auto_demo_dir();
+ void reset_progress_dialog();
+
+ void connect_compute_process();
+
private: // Attributes
QGraphicsItem *mainRefItem_;
QGraphicsItem *mainResultItem_;
--
1.5.6.5
1
0
16 Sep '09
---
scribo/ChangeLog | 4 ++++
scribo/debug/decision_image.hh | 2 +-
2 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 8bdadd9..7f504e6 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,9 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ * debug/decision_image.hh: Fix an invalid precondition.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
Improve and add new examples in Scribo.
* src/Makefile.am,
diff --git a/scribo/debug/decision_image.hh b/scribo/debug/decision_image.hh
index 1652f8e..447d3b0 100644
--- a/scribo/debug/decision_image.hh
+++ b/scribo/debug/decision_image.hh
@@ -136,7 +136,7 @@ namespace scribo
mln_precondition(links.is_valid());
mln_precondition(filtered_links.is_valid());
mln_precondition(links.size() == filtered_links.size());
- mln_precondition(links.objects_id() != filtered_links.objects_id());
+ mln_precondition(links.object_image_() != filtered_links.object_image_());
/// Fixme: check that objects has been computed from input.
image2d<value::rgb8>
--
1.5.6.5
1
0
* src/Makefile.am,
* src/extract/primitive/Makefile.am,
* src/text/Makefile.am: Add new targets.
* src/extract/primitive/find_thick_and_single_lines.cc,
* src/text/cleantxt.cc,
* src/text_in_photo_ppm.cc: New full examples.
* src/extract/primitive/find_thick_lines.cc: Use the lines_*_thick
routines.
* src/text_in_doc.cc,
* src/text_in_photo.cc: Improve outputs.
---
scribo/ChangeLog | 18 ++
scribo/src/Makefile.am | 2 +
scribo/src/extract/primitive/Makefile.am | 4 +-
...ick_lines.cc => find_thick_and_single_lines.cc} | 52 +---
scribo/src/extract/primitive/find_thick_lines.cc | 33 +--
scribo/src/text/Makefile.am | 28 ++
scribo/src/text/cleantxt.cc | 79 +++++
scribo/src/text_in_doc.cc | 104 ++++---
scribo/src/text_in_photo_ppm.cc | 318 ++++++++++++++++++++
9 files changed, 536 insertions(+), 102 deletions(-)
copy scribo/src/extract/primitive/{find_thick_lines.cc => find_thick_and_single_lines.cc} (70%)
create mode 100644 scribo/src/text/cleantxt.cc
create mode 100644 scribo/src/text_in_photo_ppm.cc
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index af2f788..8bdadd9 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,23 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ Improve and add new examples in Scribo.
+
+ * src/Makefile.am,
+ * src/extract/primitive/Makefile.am,
+ * src/text/Makefile.am: Add new targets.
+
+ * src/extract/primitive/find_thick_and_single_lines.cc,
+ * src/text/cleantxt.cc,
+ * src/text_in_photo_ppm.cc: New full examples.
+
+ * src/extract/primitive/find_thick_lines.cc: Use the lines_*_thick
+ routines.
+
+ * src/text_in_doc.cc,
+ * src/text_in_photo.cc: Improve outputs.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
Make text cleaning work.
* text/clean.hh: Do not use the distance map anymore.
diff --git a/scribo/src/Makefile.am b/scribo/src/Makefile.am
index 3b6a435..de051a4 100644
--- a/scribo/src/Makefile.am
+++ b/scribo/src/Makefile.am
@@ -37,6 +37,7 @@ bin_PROGRAMS = \
table_rebuild_opening \
table_rebuild_rank \
text_in_photo \
+ text_in_photo_ppm \
text_in_photo_invert \
thin_bboxes
@@ -50,6 +51,7 @@ superpose_SOURCES = superpose.cc
table_rebuild_opening_SOURCES = table_rebuild_opening.cc
table_rebuild_rank_SOURCES = table_rebuild_rank.cc
text_in_photo_SOURCES = text_in_photo.cc
+text_in_photo_ppm_SOURCES = text_in_photo_ppm.cc
text_in_photo_invert_SOURCES = text_in_photo_invert.cc
thin_bboxes_SOURCES = thin_bboxes.cc
diff --git a/scribo/src/extract/primitive/Makefile.am b/scribo/src/extract/primitive/Makefile.am
index 99be780..51850f6 100644
--- a/scribo/src/extract/primitive/Makefile.am
+++ b/scribo/src/extract/primitive/Makefile.am
@@ -28,7 +28,8 @@ bin_PROGRAMS = \
extract_thick_hlines \
find_discontinued_lines \
find_single_lines \
- find_thick_lines
+ find_thick_lines \
+ find_thick_and_single_lines
extract_discontinued_lines_SOURCES = extract_discontinued_lines.cc
extract_discontinued_vlines_SOURCES = extract_discontinued_vlines.cc
@@ -38,5 +39,6 @@ extract_thick_hlines_SOURCES = extract_thick_hlines.cc
find_discontinued_lines_SOURCES = find_discontinued_lines.cc
find_single_lines_SOURCES = find_single_lines.cc
find_thick_lines_SOURCES = find_thick_lines.cc
+find_thick_and_single_lines_SOURCES = find_thick_and_single_lines.cc
diff --git a/scribo/src/extract/primitive/find_thick_lines.cc b/scribo/src/extract/primitive/find_thick_and_single_lines.cc
similarity index 70%
copy from scribo/src/extract/primitive/find_thick_lines.cc
copy to scribo/src/extract/primitive/find_thick_and_single_lines.cc
index 993bf42..fa66e29 100644
--- a/scribo/src/extract/primitive/find_thick_lines.cc
+++ b/scribo/src/extract/primitive/find_thick_and_single_lines.cc
@@ -35,13 +35,9 @@
#include <scribo/debug/usage.hh>
#include <scribo/core/object_image.hh>
-#include <scribo/primitive/extract/lines_h_thick.hh>
-#include <scribo/primitive/extract/lines_v_thick.hh>
-#include <scribo/primitive/extract/lines_h_single.hh>
-#include <scribo/primitive/extract/lines_v_single.hh>
-
-#include <mln/util/timer.hh>
+# include <scribo/primitive/extract/lines_v_thick_and_single.hh>
+# include <scribo/primitive/extract/lines_h_thick_and_single.hh>
const char *args_desc[][2] =
{
@@ -57,13 +53,14 @@ const char *args_desc[][2] =
int main(int argc, char *argv[])
{
using namespace mln;
+ using namespace scribo;
if (argc != 7)
return scribo::debug::usage(argv,
"Extract thick horizontal and vertical lines.\
\n Common argument values: 150 10 150 10.",
"<input.pbm> <vlength> <vratio> <hlength>\
- <hration> <output.ppm>",
+ <hratio> <output.ppm>",
args_desc,
"A color image. Horizontal lines are in red\
and vertical lines in green.");
@@ -80,35 +77,20 @@ int main(int argc, char *argv[])
nhlines,
nvlines;
- util::timer t;
-
- t.start();
-
object_image(L)
- hlines = scribo::primitive::extract::lines_h_thick(input, c8(),
- nhlines, atoi(argv[2])),
- vlines = scribo::primitive::extract::lines_v_thick(input, c8(),
- nvlines, atoi(argv[2]));
- std::cout << "lines thick done" << std::endl;
- std::cout << t << std::endl;
- t.restart();
-
-
- hlines = scribo::primitive::extract::lines_h_single(hlines,
- atoi(argv[2]),
- 10);
-
- vlines = scribo::primitive::extract::lines_v_single(vlines,
- atoi(argv[2]),
- 10);
-
- std::cout << "lines single done" << std::endl;
- std::cout << t << std::endl;
-
- image2d<value::rgb8> out = debug::superpose(input, hlines, literal::red);
- out = debug::superpose(out, vlines, literal::green);
-
- io::ppm::save(out, argv[3]);
+ hlines = primitive::extract::lines_h_thick_and_single(input, c8(),
+ nhlines,
+ atoi(argv[2]),
+ atoi(argv[3])),
+ vlines = primitive::extract::lines_v_thick_and_single(input, c8(),
+ nvlines,
+ atoi(argv[4]),
+ atoi(argv[5]));
+
+ image2d<value::rgb8> out = mln::debug::superpose(input, hlines, literal::red);
+ out = mln::debug::superpose(out, vlines, literal::green);
+
+ io::ppm::save(out, argv[6]);
trace::exiting("main");
}
diff --git a/scribo/src/extract/primitive/find_thick_lines.cc b/scribo/src/extract/primitive/find_thick_lines.cc
index 993bf42..045b34d 100644
--- a/scribo/src/extract/primitive/find_thick_lines.cc
+++ b/scribo/src/extract/primitive/find_thick_lines.cc
@@ -41,15 +41,12 @@
#include <scribo/primitive/extract/lines_h_single.hh>
#include <scribo/primitive/extract/lines_v_single.hh>
-#include <mln/util/timer.hh>
const char *args_desc[][2] =
{
{ "input.pbm", "A binary image. Objects are set to True." },
{ "vlength ", "Minimum vertical line length." },
- { "vratio " "Minimum vertical ratio height/width." },
{ "hlength ", "Minimum horizontal line length." },
- { "hratio " "Minimum horizontal ratio width/height." },
{0, 0}
};
@@ -58,12 +55,11 @@ int main(int argc, char *argv[])
{
using namespace mln;
- if (argc != 7)
+ if (argc != 5)
return scribo::debug::usage(argv,
"Extract thick horizontal and vertical lines.\
-\n Common argument values: 150 10 150 10.",
- "<input.pbm> <vlength> <vratio> <hlength>\
- <hration> <output.ppm>",
+\n Common argument values: 150 150.",
+ "<input.pbm> <vlength> <hlength> <output.ppm>",
args_desc,
"A color image. Horizontal lines are in red\
and vertical lines in green.");
@@ -80,35 +76,16 @@ int main(int argc, char *argv[])
nhlines,
nvlines;
- util::timer t;
-
- t.start();
-
object_image(L)
hlines = scribo::primitive::extract::lines_h_thick(input, c8(),
nhlines, atoi(argv[2])),
vlines = scribo::primitive::extract::lines_v_thick(input, c8(),
- nvlines, atoi(argv[2]));
- std::cout << "lines thick done" << std::endl;
- std::cout << t << std::endl;
- t.restart();
-
-
- hlines = scribo::primitive::extract::lines_h_single(hlines,
- atoi(argv[2]),
- 10);
-
- vlines = scribo::primitive::extract::lines_v_single(vlines,
- atoi(argv[2]),
- 10);
-
- std::cout << "lines single done" << std::endl;
- std::cout << t << std::endl;
+ nvlines, atoi(argv[3]));
image2d<value::rgb8> out = debug::superpose(input, hlines, literal::red);
out = debug::superpose(out, vlines, literal::green);
- io::ppm::save(out, argv[3]);
+ io::ppm::save(out, argv[4]);
trace::exiting("main");
}
diff --git a/scribo/src/text/Makefile.am b/scribo/src/text/Makefile.am
index 5f5ed81..6b174ef 100644
--- a/scribo/src/text/Makefile.am
+++ b/scribo/src/text/Makefile.am
@@ -1 +1,29 @@
+# Copyright (C) 2009 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/>.
+#
+
+## Process this file through Automake to create Makefile.in.
+
+include $(top_srcdir)/scribo/scribo.mk
+
SUBDIRS = grouping
+
+
+bin_PROGRAMS = \
+ cleantxt
+
+
+cleantxt_SOURCES = cleantxt.cc
\ No newline at end of file
diff --git a/scribo/src/text/cleantxt.cc b/scribo/src/text/cleantxt.cc
new file mode 100644
index 0000000..f303448
--- /dev/null
+++ b/scribo/src/text/cleantxt.cc
@@ -0,0 +1,79 @@
+// Copyright (C) 2009 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.
+
+#include <iostream>
+
+#include <mln/core/image/image2d.hh>
+
+#include <mln/io/pbm/all.hh>
+
+#include <mln/logical/not.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/alias/w_window2d_int.hh>
+#include <mln/make/w_window2d_int.hh>
+
+
+#include <scribo/text/clean.hh>
+#include <scribo/debug/usage.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. 'True' for objects, 'False'\
+for the background." },
+ { "out.pbm", "A cleaned up binary image." },
+ {0, 0}
+};
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 3)
+ return scribo::debug::usage(argv,
+ "Cleanup text areas.",
+ "input.pbm out.pbm",
+ args_desc,
+ "");
+
+ trace::entering("main");
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ int vals[] = { 0, 9, 0, 9, 0,
+ 9, 6, 4, 6, 9,
+ 0, 4, 0, 4, 0,
+ 9, 6, 4, 6, 9,
+ 0, 9, 0, 9, 0 };
+ w_window2d_int dmap_win = mln::make::w_window2d_int(vals);
+
+ io::pbm::save(scribo::text::clean(logical::not_(input), dmap_win), argv[2]);
+
+ trace::exiting("main");
+}
diff --git a/scribo/src/text_in_doc.cc b/scribo/src/text_in_doc.cc
index 81219c4..cfca7d1 100644
--- a/scribo/src/text_in_doc.cc
+++ b/scribo/src/text_in_doc.cc
@@ -45,6 +45,8 @@
#include <mln/draw/box.hh>
+#include <mln/extension/adjust.hh>
+
#include <scribo/table/erase.hh>
#include <scribo/draw/bounding_boxes.hh>
@@ -83,12 +85,12 @@
#include <scribo/make/debug_filename.hh>
-
const char *args_desc[][2] =
{
{ "input.pbm", "A binary image. 'False' for objects, 'True'\
for the background." },
{ "out.txt", "A text file with all the recognized text" },
+ { "output_dir", "Output directory for debug image" },
{0, 0}
};
@@ -98,14 +100,15 @@ int main(int argc, char* argv[])
using namespace scribo;
using namespace mln;
- if (argc != 4)
+ if (argc != 3 && argc != 4)
return scribo::debug::usage(argv,
"Find text in a binarized photo.",
- "input.pbm out.txt output_dir",
+ "input.pbm out.txt <output_dir>",
args_desc,
"Debug outputs. The recognized text is printed in the standard output.");
- scribo::make::internal::debug_filename_prefix = argv[3];
+ if (argc == 4)
+ scribo::make::internal::debug_filename_prefix = argv[3];
trace::entering("main");
@@ -115,9 +118,11 @@ int main(int argc, char* argv[])
logical::not_inplace(input);
+
typedef image2d<value::label_16> L;
/// Extracting vertical and horizontal lines.
+ std::cout << "Extracting lines..." << std::endl;
value::label_16 nhlines, nvlines;
object_image(L)
lbl_v = primitive::extract::lines_v_discontinued(input, c8(),
@@ -125,12 +130,17 @@ int main(int argc, char* argv[])
object_image(L)
lbl_h = primitive::extract::lines_h_discontinued(input, c8(),
nhlines, 51, 6);
+
/// Reconstruct and erase tables.
+ std::cout << "Reconstructing and removing tables..." << std::endl;
image2d<bool> input_notables
= scribo::table::erase(input, lbl_h, lbl_v);
+ io::pbm::save(input_notables, "table_erased.ppm");
+
/// Finding objects.
+ std::cout << "Finding objects..." << std::endl;
value::label_16 nobjects;
object_image(L)
objects = scribo::primitive::extract::objects(input_notables,
@@ -139,11 +149,12 @@ int main(int argc, char* argv[])
/// First filtering.
+ std::cout << "Filtering objects..." << std::endl;
object_image(L) filtered_objects
= scribo::filter::objects_small(objects, 6);
filtered_objects
- = scribo::filter::objects_thin(filtered_objects, 2);
+ = scribo::filter::objects_thin(filtered_objects, 1);
// filtered_objects
// = scribo::filter::objects_thick(filtered_objects,
@@ -151,7 +162,8 @@ int main(int argc, char* argv[])
- /// Grouping potential objects
+ /// Linking potential objects
+ std::cout << "Linking objects..." << std::endl;
object_links<L> left_link
= primitive::link::with_single_left_link(filtered_objects, 30);
object_links<L> right_link
@@ -159,14 +171,17 @@ int main(int argc, char* argv[])
#ifndef NOUT
- std::cout << "BEFORE - nobjects = " << nobjects << std::endl;
- scribo::debug::save_linked_bboxes_image(input,
- filtered_objects,
- left_link, right_link,
- literal::red, literal::cyan,
- literal::yellow,
- literal::green,
- scribo::make::debug_filename("links.ppm"));
+ if (argc == 4)
+ {
+ std::cerr << "BEFORE - nobjects = " << nobjects << std::endl;
+ scribo::debug::save_linked_bboxes_image(input,
+ filtered_objects,
+ left_link, right_link,
+ literal::red, literal::cyan,
+ literal::yellow,
+ literal::green,
+ scribo::make::debug_filename("links.ppm"));
+ }
#endif
@@ -179,7 +194,8 @@ int main(int argc, char* argv[])
- // Remove links if bboxes have too different sizes.
+ // Remove links if bboxes are not aligned.
+ std::cout << "Filtering object links..." << std::endl;
object_links<L> bottom_filtered_links
= filter::object_links_bottom_aligned(filtered_objects,
merged_links,
@@ -188,13 +204,16 @@ int main(int argc, char* argv[])
#ifndef NOUT
- image2d<value::rgb8>
- bottom_decision_image = scribo::debug::decision_image(input,
- merged_links,
- bottom_filtered_links);
-
- io::ppm::save(bottom_decision_image,
- scribo::make::debug_filename("bottom_links_decision_image.ppm"));
+ if (argc == 4)
+ {
+ image2d<value::rgb8>
+ bottom_decision_image = scribo::debug::decision_image(input,
+ merged_links,
+ bottom_filtered_links);
+
+ io::ppm::save(bottom_decision_image,
+ scribo::make::debug_filename("bottom_links_decision_image.ppm"));
+ }
#endif
@@ -211,12 +230,15 @@ int main(int argc, char* argv[])
#ifndef NOUT
- image2d<value::rgb8>
- hratio_decision_image = scribo::debug::decision_image(input,
- bottom_filtered_links,
- hratio_filtered_links);
- io::ppm::save(hratio_decision_image,
- scribo::make::debug_filename("hratio_links_decision_image.ppm"));
+ if (argc == 4)
+ {
+ image2d<value::rgb8>
+ hratio_decision_image = scribo::debug::decision_image(input,
+ bottom_filtered_links,
+ hratio_filtered_links);
+ io::ppm::save(hratio_decision_image,
+ scribo::make::debug_filename("hratio_links_decision_image.ppm"));
+ }
#endif
@@ -232,12 +254,15 @@ int main(int argc, char* argv[])
#ifndef NOUT
- image2d<value::rgb8> overlap_decision_image
- = scribo::debug::decision_image(input,
- hratio_filtered_links,
- overlap_filtered_links);
- io::ppm::save(overlap_decision_image,
- scribo::make::debug_filename("overlap_links_decision_image.ppm"));
+ if (argc == 4)
+ {
+ image2d<value::rgb8> overlap_decision_image
+ = scribo::debug::decision_image(input,
+ hratio_filtered_links,
+ overlap_filtered_links);
+ io::ppm::save(overlap_decision_image,
+ scribo::make::debug_filename("overlap_links_decision_image.ppm"));
+ }
#endif
@@ -258,18 +283,21 @@ int main(int argc, char* argv[])
// groups, filtered_groups);
// #endif
+ std::cout << "Grouping objects..." << std::endl;
object_image(L)
grouped_objects = primitive::group::apply(filtered_objects, groups);
#ifndef NOUT
- io::ppm::save(mln::labeling::colorize(value::rgb8(),
- grouped_objects,
- grouped_objects.nlabels()),
- scribo::make::debug_filename("out.ppm"));
+ if (argc == 4)
+ io::ppm::save(mln::labeling::colorize(value::rgb8(),
+ grouped_objects,
+ grouped_objects.nlabels()),
+ scribo::make::debug_filename("out.ppm"));
#endif
+ std::cout << "Text recognition..." << std::endl;
text::recognition(grouped_objects, "fra", argv[2]);
trace::exiting("main");
diff --git a/scribo/src/text_in_photo_ppm.cc b/scribo/src/text_in_photo_ppm.cc
new file mode 100644
index 0000000..4cb5631
--- /dev/null
+++ b/scribo/src/text_in_photo_ppm.cc
@@ -0,0 +1,318 @@
+// Copyright (C) 2009 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.
+
+#include <libgen.h>
+#include <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/labeling/colorize.hh>
+
+#include <mln/io/pbm/all.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/math/min.hh>
+
+#include <mln/logical/not.hh>
+
+#include <mln/literal/colors.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+
+#include <mln/draw/box.hh>
+
+#include <scribo/binarization/sauvola.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+
+#include <scribo/primitive/link/merge_double_link.hh>
+#include <scribo/primitive/link/with_single_left_link.hh>
+#include <scribo/primitive/link/with_single_right_link.hh>
+
+#include <scribo/primitive/group/apply.hh>
+#include <scribo/primitive/group/from_double_link.hh>
+#include <scribo/primitive/group/from_single_link.hh>
+
+#include <scribo/filter/object_links_bbox_h_ratio.hh>
+#include <scribo/filter/object_links_bbox_overlap.hh>
+
+#include <scribo/filter/common/objects_photo.hh>
+
+#include <scribo/filter/object_groups_small.hh>
+#include <scribo/filter/object_groups_v_thickness.hh>
+
+#include <scribo/debug/decision_image.hh>
+#include <scribo/debug/save_bboxes_image.hh>
+#include <scribo/debug/save_bboxes_image.hh>
+#include <scribo/debug/save_linked_bboxes_image.hh>
+
+#include <scribo/debug/usage.hh>
+
+#include <scribo/preprocessing/split_bg_fg.hh>
+
+#include <scribo/make/debug_filename.hh>
+
+const char *args_desc[][2] =
+{
+ { "input.ppm", "A color image." },
+ { "debug_output_dir", "Directory were debug images will be saved" },
+ { "lambda", "Lambda value used for foreground extraction" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 3 && argc != 4 && argc != 5)
+ return scribo::debug::usage(argv,
+ "Find text in a photo.",
+ "input.ppm output.ppm [debug_output_dir] [lambda]",
+ args_desc,
+ "A color image where the text is highlighted.");
+
+ if (argc > 3)
+ scribo::make::internal::debug_filename_prefix = argv[3];
+
+ trace::entering("main");
+
+ image2d<value::rgb8> input_rgb;
+ io::ppm::load(input_rgb, argv[1]);
+
+
+ unsigned lambda;
+ if (argc == 5)
+ lambda = atoi(argv[4]);
+ else
+ lambda = 1.2 * (input_rgb.nrows() + input_rgb.ncols());
+
+
+ // Extract foreground
+ std::cout << "Extracting foreground..." << std::endl;
+ image2d<value::rgb8>
+ fg = preprocessing::split_bg_fg(input_rgb,
+ lambda,
+ 32).second();
+
+ // Binarize foreground to use it in the processing chain.
+ std::cout << "Binarizing foreground..." << std::endl;
+ image2d<bool> input = binarization::sauvola(fg);
+
+
+
+ typedef image2d<value::label_16> L;
+
+ /// Finding objects.
+ std::cout << "Extracting objects..." << std::endl;
+ value::label_16 nobjects;
+ object_image(L)
+ objects = scribo::primitive::extract::objects(input, c8(), nobjects);
+
+
+ /// First filtering.
+ std::cout << "Filtering objects..." << std::endl;
+ object_image(L) filtered_objects = filter::common::objects_photo(objects);
+
+
+
+ /// linking potential objects
+ std::cout << "Linking objects..." << std::endl;
+ object_links<L> left_link
+ = primitive::link::with_single_left_link(filtered_objects, 30);
+ object_links<L> right_link
+ = primitive::link::with_single_right_link(filtered_objects, 30);
+
+
+
+
+
+#ifndef NOUT
+ if (argc > 3)
+ {
+ std::cerr << "BEFORE - nobjects = " << nobjects << std::endl;
+ scribo::debug::save_linked_bboxes_image(input,
+ filtered_objects,
+ left_link, right_link,
+ literal::red, literal::cyan,
+ literal::yellow,
+ literal::green,
+ scribo::make::debug_filename("links.ppm"));
+ }
+#endif
+
+
+
+ // Validating left and right links.
+ object_links<L>
+ merged_links = primitive::link::merge_double_link(filtered_objects,
+ left_link,
+ right_link);
+ // Remove links if bboxes have too different sizes.
+ std::cout << "Filtering object links..." << std::endl;
+ object_links<L>
+ hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_objects,
+ merged_links,
+ 0.7f);
+
+
+
+
+#ifndef NOUT
+ if (argc > 3)
+ {
+ image2d<value::rgb8>
+ hratio_decision_image = scribo::debug::decision_image(input,
+ merged_links,
+ hratio_filtered_links);
+ io::ppm::save(hratio_decision_image,
+ scribo::make::debug_filename("hratio_links_decision_image.ppm"));
+ }
+#endif
+
+
+
+
+ //Remove links if bboxes overlap too much.
+ object_links<L> overlap_filtered_links
+ = filter::object_links_bbox_overlap(filtered_objects,
+ hratio_filtered_links,
+ 0.80f);
+
+
+
+
+#ifndef NOUT
+ if (argc > 3)
+ {
+ image2d<value::rgb8> overlap_decision_image
+ = scribo::debug::decision_image(input,
+ hratio_filtered_links,
+ overlap_filtered_links);
+ io::ppm::save(overlap_decision_image,
+ scribo::make::debug_filename("overlap_links_decision_image.ppm"));
+ }
+#endif
+
+
+
+ std::cout << "Grouping objects..." << std::endl;
+ object_groups<L>
+ groups = primitive::group::from_single_link(filtered_objects,
+ overlap_filtered_links);
+
+
+
+ /// Apply grouping in a temporary image (for debug purpose).
+ object_image(L)
+ raw_group_image = primitive::group::apply(filtered_objects,
+ filter::object_groups_small(groups, 2));
+
+ std::cout << "Filtering groups..." << std::endl;
+
+ // Remove objects part of groups with strictly less than 3 objects.
+ object_groups<L>
+ filtered_small_groups = filter::object_groups_small(groups, 3);
+
+
+#ifndef NOUT
+ image2d<value::rgb8> decision_image;
+ if (argc > 3)
+ {
+ decision_image = scribo::debug::decision_image(input,
+ groups,
+ filtered_small_groups);
+ io::ppm::save(decision_image,
+ scribo::make::debug_filename("small_groups_filter.ppm"));
+ }
+#endif
+
+
+
+ // Remove objects part of groups having a mean thickness lower than 8.
+ object_groups<L> filtered_thin_groups
+ = filter::object_groups_v_thickness(filtered_small_groups, 8);
+
+
+#ifndef NOUT
+ if (argc > 3)
+ {
+ decision_image = scribo::debug::decision_image(input,
+ groups,
+ filtered_thin_groups);
+
+ io::ppm::save(decision_image,
+ scribo::make::debug_filename("thin_groups_filter.ppm"));
+ }
+#endif
+
+
+
+ /// Apply grouping in the object image.
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects,
+ filtered_thin_groups);
+
+
+ /// Objects have been grouped. We try to link groups together.
+ /// This time a single link is enough since non-wanted objects have
+ /// been removed.
+ left_link
+ = primitive::link::with_single_left_link(grouped_objects, 30);
+
+ /// Grouping groups.
+ groups = primitive::group::from_single_link(grouped_objects, left_link);
+
+
+ grouped_objects = primitive::group::apply(grouped_objects, groups);
+
+
+
+
+#ifndef NOUT
+ if (argc > 3)
+ {
+ scribo::draw::bounding_boxes(decision_image, raw_group_image, literal::yellow);
+ scribo::draw::bounding_boxes(decision_image, grouped_objects, literal::blue);
+ io::ppm::save(decision_image, scribo::make::debug_filename("decision_image.ppm"));
+
+ std::cerr << "AFTER - nobjects = " << grouped_objects.nlabels() << std::endl;
+ }
+#endif
+
+
+ std::cout << "Saving result..." << std::endl;
+ io::ppm::save(mln::labeling::colorize(value::rgb8(),
+ grouped_objects,
+ grouped_objects.nlabels()),
+ argv[2]);
+
+
+ trace::exiting("main");
+}
--
1.5.6.5
1
0
* text/clean.hh: Do not use the distance map anymore.
* text/recognition.hh: Do not return an image of char anymore.
Enlarge the temporary image domain.
---
scribo/ChangeLog | 9 +++++
scribo/text/clean.hh | 73 ++++++++++++++++++++++++-------------------
scribo/text/recognition.hh | 39 ++++++++++++++---------
3 files changed, 74 insertions(+), 47 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 15ea49e..af2f788 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,14 @@
2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+ Make text cleaning work.
+
+ * text/clean.hh: Do not use the distance map anymore.
+
+ * text/recognition.hh: Do not return an image of char anymore.
+ Enlarge the temporary image domain.
+
+2009-09-15 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
Add new filters in Scribo.
* filter/common/objects_photo.hh,
diff --git a/scribo/text/clean.hh b/scribo/text/clean.hh
index 0f87139..e934241 100644
--- a/scribo/text/clean.hh
+++ b/scribo/text/clean.hh
@@ -41,7 +41,7 @@
# include <mln/logical/not.hh>
-# include <mln/world/binary_2d/enlarge.hh>
+//# include <mln/world/binary_2d/enlarge.hh>
# include <mln/debug/filename.hh>
# include <mln/io/pbm/save.hh>
@@ -58,6 +58,15 @@
#include <mln/value/int_u8.hh>
+#include <mln/fun/v2b/threshold.hh>
+#include <mln/binarization/threshold.hh>
+#include <mln/data/convert.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/io/pgm/all.hh>
+
+#include <sandbox/inim/2009/ocr/resize.hh>
+#include <sandbox/fabien/mln/upsampling/hq4x.hh>
+
namespace scribo
{
@@ -70,7 +79,8 @@ namespace scribo
/// Improve quality of an image with text.
///
- /// \param[in] input_ A binary image.
+ /// \param[in] input_ A binary image. Object are set to 'false'
+ /// and backgroud to 'true'.
/// \param[in] dmap_win_ A weighted window.
///
/// \return An image. The text have better quality.
@@ -83,8 +93,6 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY
-// static int plop = 0;
-
template <typename I, typename W>
mln_concrete(I)
clean(const Image<I>& input_, const Weighted_Window<W>& dmap_win_)
@@ -98,43 +106,44 @@ namespace scribo
mln_precondition(input.is_valid());
mln_precondition(dmap_win.is_valid());
-// I input_large = world::binary_2d::enlarge(input, 2);
-// image2d<bool> blur = linear::gaussian(input_large, 2);
-// image2d<value::int_u8> blur = linear::gaussian(level::convert(value::int_u8(), input_large), 2);
-// image2d<bool> blur = level::transform(linear::gaussian(level::convert(value::int_u8(), input_large), 2), fun::v2b::threshold<value::int_u8>(100));
+ // Resize
+ typedef image2d<value::rgb8> J;
+ J tmp = data::convert(value::rgb8(), input);
+ J clarge = mln::upsampling::hq4x(tmp);
+
+ //FIXME: not generic!
+ if (input.domain().pmax()[0] - input.domain().pmin()[0] <= 10)
+ clarge = mln::upsampling::hq4x(clarge);
-// mln_ch_value(I,unsigned)
-// dmap = transform::distance_front(logical::not_(input_large), c8(),
-// dmap_win,
-// mln_max(unsigned));
-// io::pgm::save(labeling::wrap(dmap), mln::debug::filename("dmap.pgm"));
+ I input_large = data::convert(bool(), clarge);
-// I skeleton = topo::skeleton::crest(input_large, dmap, c8());
-// I constraint = topo::skeleton::crest(input_large, dmap, c8());
-// mln_postcondition(constraint.is_valid());
+ // Blur
+ image2d<value::int_u8>
+ blur = linear::gaussian(data::convert(value::int_u8(), input_large), 2);
-// io::pgm::save(labeling::wrap(constraint), mln::debug::filename("constraint.pgm"));
+ // Skeleton constraint
+ I K = topo::skeleton::crest(input_large, blur, c8());
-// I skeleton =
-// morpho::skeleton_constrained(input_large, c8(),
-// topo::skeleton::is_simple_point<I,neighb2d>,
-// extend(constraint, false), arith::revert(dmap));
+ // Skeleton
+ I skel_on_gaussian =
+ morpho::skeleton_constrained(input_large, c8(),
+ topo::skeleton::is_simple_point<I,neighb2d>,
+ extend(K, false), arith::revert(blur));
-// win::octagon2d disk(7);
-// I output = morpho::dilation(skeleton, disk);
+ // Dilation
+ win::octagon2d oct(7);
+ I dilate_on_gaussian = morpho::dilation(skel_on_gaussian, oct);
-// if (plop > 20 && plop < 50)
- {
-// io::pbm::save(input, mln::debug::filename("input.pbm"));
-// io::pbm::save(input_large, mln::debug::filename("input_large_4x.pbm"));
-// io::pbm::save(skeleton, mln::debug::filename("skeleton.pbm"));
-// io::pbm::save(output, mln::debug::filename("dil_skel.pbm"));
- }
+// io::pgm::save(arith::revert(blur), "blur_revert.pgm");
+// io::pgm::save(blur, "gaussian.pgm");
+// io::pbm::save(input_large, mln::debug::filename("input_large_4x.pbm"));
+// io::pbm::save(K, mln::debug::filename("K.pbm"));
+// io::pbm::save(skel_on_gaussian, mln::debug::filename("skeleton_on_gaussian.pbm"));
+// io::pbm::save(dilate_on_gaussian, mln::debug::filename("dilation_on_gaussian.pbm"));
-// ++plop;
trace::exiting("scribo::text::clean");
- return input;
+ return dilate_on_gaussian;
}
# endif // ! MLN_INCLUDE_ONLY
diff --git a/scribo/text/recognition.hh b/scribo/text/recognition.hh
index 6293e28..bd9f89b 100644
--- a/scribo/text/recognition.hh
+++ b/scribo/text/recognition.hh
@@ -68,6 +68,8 @@
# include <tesseract/baseapi.h>
+#include <mln/labeling/colorize.hh>
+
namespace scribo
{
@@ -83,11 +85,9 @@ namespace scribo
/// Tesseract. (fra, en, ...)
/// \param[in] output_file If set, store the recognized text in
/// this file.
- ///
- /// \return An image of characters.
//
template <typename L>
- mln_ch_value(L,char)
+ void
recognition(const object_image(L)& objects,
const char *language,
const char *output_file);
@@ -98,7 +98,7 @@ namespace scribo
template <typename L>
- mln_ch_value(L,char)
+ void
recognition(const object_image(L)& objects,
const char *language,
const char *output_file)
@@ -110,9 +110,6 @@ namespace scribo
// Initialize Tesseract.
TessBaseAPI::InitWithLanguage(NULL, NULL, language, NULL, false, 0, NULL);
- mln_ch_value(L,char) txt(objects.domain());
- data::fill(txt, ' ');
-
typedef mln_ch_value(L,bool) I;
int vals[] = { 0, 9, 0, 9, 0,
9, 6, 4, 6, 9,
@@ -128,17 +125,31 @@ namespace scribo
/// Use text bboxes with Tesseract
for_all_ncomponents(i, objects.nlabels())
{
- I text_ima(objects.bbox(i));
- data::fill(text_ima, false);
- data::fill((text_ima | (pw::value(objects) == pw::cst(i))).rw(),
- true);
+ std::cout << "Text recognition... ("
+ << i << "/" << objects.nlabels() << ")" << std::endl;
+
+ mln_domain(I) box = objects.bbox(i);
+ // Make sure characters are isolated from the borders.
+ // Help Tesseract.
+ box.enlarge(2);
+ I text_ima(box);
+ data::fill(text_ima, true);
+
+ // Careful : background is set to 'False'
+ data::fill((text_ima | (pw::value(objects) == pw::cst(i))).rw(),
+ false);
/// Improve text quality.
/// text_ima_cleand domain is larger than text_ima's.
I text_ima_cleaned = text::clean(text_ima, dmap_win);
- border::resize(text_ima_cleaned, 0); // Make sure there is no border.
+
+ // Setting objects to 'True'
+ logical::not_inplace(text_ima_cleaned);
+
+ // Make sure there is no border.
+ border::resize(text_ima_cleaned, 0);
// Recognize characters.
char* s = TessBaseAPI::TesseractRect(
@@ -157,10 +168,9 @@ namespace scribo
- objects.bbox(i).pmin().col()) / 2;
if (s != 0)
{
- std::cout << s << std::endl;
+ std::cerr << s << std::endl;
if (output_file != 0)
file << s << std::endl;
- mln::debug::put_word(txt, p, s);
}
// The string has been allocated by Tesseract. We must free it.
@@ -171,7 +181,6 @@ namespace scribo
file.close();
trace::exiting("scribo::text::recognition");
- return txt;
}
--
1.5.6.5
1
0