URL:
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-31 Matthieu Garrigues <garrigues(a)lrde.epita.fr>
Improve Skeleton computation.
* garrigues/ocr/check_simple_point.cc: New. check the analysis of the
local configuration of a pixel.
* garrigues/ocr/enlarge.hh: Add routine for int_u8 images.
* garrigues/ocr/ocr_with_preprocess.cc: Add the use of skeleton in the
ocr preprocessing.
* garrigues/ocr/simple_point.cc: .
* garrigues/ocr/simple_point.hh: .
* garrigues/ocr/skel.cc: Remove.
* garrigues/ocr/skeleton.cc: Remove.
* garrigues/ocr/skeleton.old.cc: New.
* garrigues/ocr/skeleton.old.hh: New.
* garrigues/ocr/Makefile: .
* garrigues/ocr/check.sh: .
---
Makefile | 5
check.sh | 1
check_simple_point.cc | 61 ++++
enlarge.hh | 124 +++++++--
ocr_with_preprocess.cc | 94 +++++--
simple_point.cc | 2
simple_point.hh | 35 ++
skeleton.hh | 631 +++++++------------------------------------------
skeleton.old.cc | 30 ++
skeleton.old.hh | 611 +++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 1006 insertions(+), 588 deletions(-)
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skel.cc (deleted)
===================================================================
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc (deleted)
===================================================================
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.old.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.old.hh (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.old.hh (revision 2750)
@@ -0,0 +1,611 @@
+// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library 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 this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library 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 SKELETON_HH
+# define SKELETON_HH
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <sandbox/aroumougame/skeleton/sedt.hh>
+
+#include <mln/core/site_set/p_set.hh>
+#include <mln/math/sqrt.hh>
+
+namespace mln
+{
+
+
+template <typename P>
+ std::vector< std::pair< double, P > > remove(std::vector<
std::pair< double, P > > Q, P p)
+{
+ typename std::vector<std::pair< double, P > >::iterator it;
+
+ for(it = Q.begin(); it!=Q.end(); it++)
+ {
+ if((*it).second==p)
+ {
+ it = Q.erase(it);
+ break;
+ }
+ }
+ return Q;
+}
+template <typename N>
+ double distance(N a, N b, N c, N d)
+{
+ double dist = sqrt((a-c)*(a-c)+(b-d)*(b-d));
+ return dist;
+}
+template <typename P>
+ std::vector< std::pair< double, P > > insertDicho(std::vector<
std::pair< double, P > > Q, std::pair< double, P> p)
+{
+ int indMin, indMax, indMid;
+
+ indMin = 0;
+ indMax = Q.size();
+
+ if(indMax==0 || Q[indMax-1].first <= p.first)
+ Q.push_back(p);
+ else
+ {
+ while(indMax > indMin)
+ {
+ indMid = int(indMin + (indMax-indMin)/2);
+ if(Q[indMid].first < p.first)
+ {
+ indMin = indMid+1;
+ if(Q[indMin].first > p.first)
+ {
+ indMax = indMid;
+ }
+ }
+ else
+ {
+ indMax = indMid-1;
+ if(Q[indMax].first < p.first)
+ {
+ indMin = indMid;
+ }
+ }
+ }
+
+ typename std::vector< std::pair< double, P > >::iterator it=Q.begin();
+ it = Q.insert ( it+indMin, p);
+ }
+
+ return Q;
+}
+
+
+const neighb2d& complement_neighborhood(const Neighborhood<neighb2d>& nbh)
+{
+ if(&nbh == &c4())
+ return c8();
+ return c4();
+}
+
+template <typename N>
+ int nb_composant_connexe(p_set< mln_psite(N) > X_full,const
Neighborhood<N>& nbh_,const mln_psite(N)& p_ref, bool local)
+{
+ N nbh = exact(nbh_);
+ p_set< mln_psite(N) > X;
+ if(local)
+ {
+ mln_niter(N) n(max_neighborhood(nbh), p_ref);
+
+ for_all(n)
+ {
+ if (X_full.has(n))
+ X.insert(n);
+ }
+ }
+ else
+ {
+ X = X_full;
+ }
+
+ int T;
+ p_set< mln_psite(N) > done;
+ p_set< mln_psite(N) > neighbors;
+ p_set< mln_psite(N) > composant;
+
+ done.insert(p_ref);
+ mln_niter(N) q(nbh, p_ref);
+ for_all(q)
+ {
+ if (X.has(q)&&!done.has(q))
+ {
+ neighbors.insert(q);
+ }
+ }
+// std::cout << "nb_composant_connexe: neighbors " <<
neighbors.nsites() <<std::endl;
+ if(neighbors.nsites()<=1)
+ {
+ return neighbors.nsites();
+ }
+ else
+ T=0;
+
+ while(neighbors.nsites()!=0)
+ {
+ T++;
+ done.insert(neighbors[0]);
+ mln_niter(N) t(nbh, neighbors[0]);
+ neighbors.remove(neighbors[0]);
+ for_all(t)
+ {
+ if (X.has(t)&&!done.has(t))
+ {
+ composant.insert(t);
+ }
+ }
+
+ while(composant.nsites()!=0)
+ {
+ done.insert(composant[0]);
+ if(neighbors.has(composant[0]))
+ {
+ neighbors.remove(composant[0]);
+ if(neighbors.nsites()==0)
+ return T;
+ }
+
+ mln_niter(N) r(nbh, composant[0]);
+ composant.remove(composant[0]);
+ for_all(r)
+ {
+ if (X.has(r) && !done.has(r))
+ {
+ composant.insert(r);
+ }
+ }
+ }
+ }
+ return T;
+}
+
+template <typename N>
+ bool simple_point(p_set< mln_psite(N) > X,const Neighborhood<N>& nbh,
p_set< mln_psite(N) > X_complement, const mln_psite(N)& p_ref, bool local)
+{
+ int nX = nb_composant_connexe(X,exact(nbh),p_ref,local);
+ int nX_complement =
nb_composant_connexe(X_complement,complement_neighborhood(exact(nbh)),p_ref,local);
+
+ if((nX_complement == 1)&&(nX == 1))
+ return true;
+ return false;
+}
+
+
+ template <typename N>
+ p_set<mln_psite(N)> euclideanSkeleton(p_set<mln_psite(N)> X,
p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt,
p_set<mln_psite(N)>& Y, const Neighborhood<N>& nbh_, bool local)
+ {
+ std::vector< std::pair< double, mln::point2d> > Q;
+ std::vector< std::pair< double, mln::point2d> > R;
+ N nbh = exact(nbh_);
+
+ // fill Q
+ for (uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ std::pair<double, mln_psite(N)> p(math::sqrt(double(dt(X[i]))),X[i]);
+ Q = insertDicho(Q,p);
+ }
+ }
+
+ // fill R
+ for (uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ double min = 1023.99;
+ mln_niter(N) r(nbh, X[i]);
+ for_all(r)
+ {
+ if (Y.has(r))
+ {
+ double tmp = distance(r[0], r[1], X[i][0], X[i][1]);
+ double d =
math::sqrt(double(dt(r)))+(math::sqrt(double(dt(X[i])))-math::sqrt(double(dt(r))))/tmp;
+ min = math::min(min,d);
+ }
+ }
+ if (min!=1023.99)
+ {
+ std::pair<double, mln_psite(N)> p(min,X[i]);
+ R = insertDicho(R, p);
+ }
+ }
+ }
+
+ while (!Q.empty() || !R.empty())
+ {
+ mln_psite(N) tmp;
+ if (Q[0].first < R[0].first)
+ {
+ tmp = Q[0].second;
+ }
+ else
+ {
+ tmp = R[0].second;
+ }
+
+ Q = remove(Q, tmp);
+ R = remove(R, tmp);
+
+ if (!Y.has(tmp) && X.has(tmp))
+ {
+ if (simple_point(X, nbh, X_complement, tmp, local))
+ {
+ X.remove(tmp);
+ X_complement.insert(tmp);
+ }
+ else
+ {
+ Y.insert(tmp);
+ mln_niter(N) r(nbh, tmp);
+ for_all(r)
+ {
+ if (!Y.has(r) && X.has(r))
+ {
+ double dist = distance(r[0], r[1], tmp[0], tmp[1]);
+ double d =
math::sqrt(double(dt(tmp)))+(math::sqrt(double(dt(r)))-math::sqrt(double(dt(tmp))))/dist;
+ std::pair<double, mln_psite(N)> p(d,r);
+ R = insertDicho(R, p);
+ }
+ }
+
+ }
+ }
+
+ }
+ return X;
+ }
+
+
+ p_set<point2d> EP(image2d<value::int_u8> dt, point2d x, std::vector<
std::vector<std::pair< int, int> > > lut, const neighb2d& nbh)
+ {
+ p_set<point2d> EP;
+ p_set<point2d> tmp;
+ int w = geom::ncols(dt);
+ int h = geom::nrows(dt);
+
+
+ mln_niter_(neighb2d) r(nbh, x);
+ for_all(r)
+ {
+ if (dt(r) <= dt(x))
+ {
+ for (uint i=0; i<lut[dt(r)].size(); i++)
+ {
+ if ((r[0]+lut[dt(r)][i].first < h) && (r[1]+lut[dt(r)][i].second < w))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second));
+ }
+ if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]-lut[dt(r)][i].second >=
0))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second));
+ }
+ if ((r[0]+lut[dt(r)][i].first < h) && (r[1]-lut[dt(r)][i].second >= 0))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second));
+ }
+ if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]+lut[dt(r)][i].second < w))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second));
+ }
+ if ((r[0]+lut[dt(r)][i].second < h) && (r[1]+lut[dt(r)][i].first < w))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first));
+ }
+ if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]-lut[dt(r)][i].first >=
0))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first));
+ }
+ if ((r[0]+lut[dt(r)][i].second < h) && (r[1]-lut[dt(r)][i].first >= 0))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first));
+ }
+ if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]+lut[dt(r)][i].first < w))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first));
+ }
+ }
+ }
+ }
+
+ return EP;
+ }
+
+ std::vector< std::vector<std::pair< int, int> > > Lut2d(int N)
+ {
+ int n = int(sqrt(N))+1;
+ int i=0;
+ std::vector< std::vector<std::pair< int, int> > > lut;
+
+ for(i = 0; i <= N; i++)
+ {
+ std::vector<std::pair< int, int> > vect;
+ lut.push_back(vect);
+ }
+
+ for(int x = 0; x <= n; x++)
+ {
+ for(int y = 0; y <= x; y++)
+ {
+ i=x*x+y*y;
+ if(i<=N)
+ {
+ std::pair<int,int> p(x,y);
+ lut[i].push_back(p);
+ }
+ }
+ }
+
+ return lut;
+}
+
+ image2d<value::int_u8> DiscreteBisector(image2d<value::int_u8> dt,
p_set<point2d> Y, const neighb2d& nbh, int N)
+ {
+ int w = geom::ncols(dt);
+ int h = geom::nrows(dt);
+
+ int ux,uy,vx,vy, produit, angle, max;
+ double cos, normu, normv;
+
+ std::vector< std::vector<std::pair< int, int> > > lut;
+ lut = Lut2d(N);
+
+ p_set<point2d> proj;
+
+ image2d<value::int_u8> bisector(h, w);
+ level::fill(bisector, 0);
+
+ for (uint i=0; i<Y.nsites(); i++)
+ {
+ proj = EP(dt, Y[i], lut, nbh);
+
+ int n=proj.nsites();
+
+ if (n>1)
+ {
+ max = 0;
+ for (int y=0; y<n; y++)
+ {
+ for (int z=0; z<y; z++)
+ {
+ ux = proj[y][0]-Y[i][0];
+ uy = proj[y][1]-Y[i][1];
+ vx = proj[z][0]-Y[i][0];
+ vy = proj[z][1]-Y[i][1];
+
+ produit = ux * vx + uy * vy;
+
+ normu = sqrt(ux*ux + uy*uy);
+ normv = sqrt(vx*vx + vy*vy);
+
+ cos = produit/(normu*normv);
+ angle = int(acos(cos)*180.0/3.1415);
+
+ max = math::max(max, angle);
+ }
+ }
+ bisector(Y[i]) = max;
+ }
+
+ }
+
+ return bisector;
+
+ }
+
+
+
+const neighb2d& max_neighborhood(const Neighborhood<neighb2d>& nbh)
+{
+ return c8();
+}
+template <typename N>
+ p_set<mln_psite(N)> ultimateSkeleton(p_set<mln_psite(N)> X,
p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt,
p_set<mln_psite(N)> Y, const Neighborhood<N>& nbh_, bool local)
+{
+ std::vector< std::pair< double, mln::point2d> > Q;
+
+ N nbh = exact(nbh_);
+ // fill Q
+ for(uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ std::pair<double, mln_psite(N)> p(dt(X[i]),X[i]);
+ Q = insertDicho(Q,p);
+ }
+ }
+
+
+ while(!Q.empty())
+ {
+ mln_psite(N) tmp = Q[0].second;
+
+ Q = remove(Q, tmp);
+
+ if(simple_point(X, nbh, X_complement, tmp, local))
+ {
+ X.remove(tmp);
+ X_complement.insert(tmp);
+ mln_niter(N) r(nbh, tmp);
+ for_all(r)
+ {
+ if(!Y.has(r) && X.has(r))
+ {
+ std::pair<double, mln_psite(N)> p(dt(r),r);
+ Q = insertDicho(Q, p);
+ }
+ }
+ }
+
+ }
+ return X;
+}
+
+ image2d<value::int_u8> intImage(image2d<bool> pic)
+{
+ int w = geom::ncols(pic);
+ int h = geom::nrows(pic);
+
+ image2d<value::int_u8> out(h,w);
+ for(int i=0; i<w; i++)
+ for(int j=0; j<h; j++)
+ {
+ if(pic.at(j,i))
+ out.at(j,i) = 1;
+ else
+ out.at(j,i) = 0;
+ }
+ return out;
+}
+ image2d<bool> filteredSkeleton(image2d<bool> pic, const neighb2d& nbh,
uint r, uint alpha, bool local)
+ {
+ using value::int_u8;
+
+ typedef image2d<bool> I;
+ typedef p_set<point2d> S;
+
+ image2d<value::int_u8> pic1 = intImage(pic);
+ image2d<value::int_u8> dt = sedt(pic1);
+
+ mln::io::pgm::save(dt, "dt.pgm");
+
+ int w = geom::ncols(pic);
+ int h = geom::nrows(pic);
+ int l= math::min(w, h);
+ uint rmax = getRMax(dt);
+ uint rknown = 0;
+ p_set<point2d> X,Y,Z;
+ p_set<point2d> X_complement, Z_complement;
+
+ image2d<value::int_u8> DTg(l,l,0);
+ std::vector< std::vector<int> > Mgl;
+ std::vector< std::vector<int> > Lut;
+
+ Mgl = CompLutMask (DTg,Mgl,Lut,l,0,rmax);
+
+ rknown =rmax;
+
+ mln_fwd_piter_(image2d<bool>) p(pic.domain());
+
+ for_all(p)
+ {
+ if (pic(p)==1)
+ {
+ X.insert(p);
+ }
+ else
+ {
+ X_complement.insert(p);
+ }
+ }
+ std::cout << " medial axis " << std::endl;
+ pic = MA(pic, Mgl, dt, Lut);
+
+ mln::io::pbm::save(pic, "ma.pbm");
+
+ for_all(p)
+ {
+ if (pic(p)==1)
+ {
+ Y.insert(p);
+ }
+ }
+
+ std::cout << " euclidean skeleton " << std::endl;
+ Z = euclideanSkeleton(X, X_complement, dt, Y, nbh, local);
+
+ sub_image<I, S> es = pic | Z;
+ I es1(pic.domain());
+ level::fill(es1, false);
+
+ level::paste(es, es1);
+
+ mln::io::pbm::save(es1, "euclidean.pbm");
+
+ for_all(p)
+ {
+ if (!Z.has(p))
+ {
+ Z_complement.insert(p);
+ }
+ }
+ std::cout << " discrete bisector " << std::endl;
+ pic1 = DiscreteBisector(dt, Y, nbh, rmax);
+
+
+ mln::io::pgm::save(pic1, "bisector.pgm");
+
+ uint cpt=0;
+ while (cpt!=Y.nsites())
+ {
+ if (dt(Y[cpt])>=r && pic1(Y[cpt])>=alpha)
+ {
+ cpt++;
+ }
+ else
+ {
+ Y.remove(Y[cpt]);
+ }
+ }
+
+
+ sub_image<I, S> skel = pic | Y;
+ I test(pic.domain());
+ level::fill(test, false);
+
+ level::paste(skel, test);
+
+ mln::io::pbm::save(test, "Y.pbm");
+
+ std::cout << " ultimate skeleton " << std::endl;
+ Z = ultimateSkeleton(Z, Z_complement, dt, Y, nbh, local);
+
+
+
+ sub_image<I, S> skeleton = pic | Z;
+ I output(pic.domain());
+ level::fill(output, false);
+
+ level::paste(skeleton, output);
+
+ return output;
+ }
+
+} // End of namespace mln
+#endif // ! SKELETON_HH
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/simple_point.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/simple_point.hh (revision 2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/simple_point.hh (revision 2750)
@@ -139,7 +139,7 @@
for_all(n)
{
res = (res << 1);
- if (ima(n) == object)
+ if (ima.domain().has(n) && ima(n) == object)
res = res | 1;
}
@@ -152,18 +152,43 @@
}
}
- bool is_curve_extremum(const image2d<bool>& ima, unsigned nbh, const
point2d& p)
+ bool is_curve_extremum(const image2d<bool>& ima, unsigned nbh_i, const
point2d& p_, unsigned deep)
{
+// return false;
unsigned cpt = 0;
- mln_bkd_niter_(neighb2d) n(c8() , p);
+ mln_site_(image2d<bool>) next = p_;
+ mln_site_(image2d<bool>) p = next;
+ mln_niter_(neighb2d) n(int_to_neighb(nbh_i) , p);
+ p = next;
for_all(n)
{
- if (ima(n) == true)
+ if (ima.domain().has(n) && ima(n) == true)
+ {
+ next = n;
cpt++;
}
+ }
+ if (cpt != 1)
+ return false;
+
+ for (unsigned i = 0; i < deep - 1; i++)
+ {
+ cpt = 0;
+ p = next;
+ for_all(n)
+ {
+ if (ima.domain().has(n) && ima(n) == true)
+ {
+ next = n;
+ cpt++;
+ }
+ }
+ if (cpt != 2)
+ return false;
+ }
- return cpt == 1;
+ return true;
}
bool is_simple_point2d(const image2d<bool>& ima, unsigned nbh, const
point2d& p)
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh (revision 2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh (revision 2750)
@@ -24,588 +24,159 @@
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef SKELETON_HH
-# define SKELETON_HH
-#include <mln/core/image/image2d.hh>
-#include <mln/core/alias/neighb2d.hh>
-#include <sandbox/aroumougame/skeleton/sedt.hh>
-
-#include <mln/core/site_set/p_set.hh>
-#include <mln/math/sqrt.hh>
-
-namespace mln
-{
-
-
-template <typename P>
- std::vector< std::pair< double, P > > remove(std::vector<
std::pair< double, P > > Q, P p)
-{
- typename std::vector<std::pair< double, P > >::iterator it;
-
- for(it = Q.begin(); it!=Q.end(); it++)
- {
- if((*it).second==p)
- {
- it = Q.erase(it);
- break;
- }
- }
- return Q;
-}
-template <typename N>
- double distance(N a, N b, N c, N d)
-{
- double dist = sqrt((a-c)*(a-c)+(b-d)*(b-d));
- return dist;
-}
-template <typename P>
- std::vector< std::pair< double, P > > insertDicho(std::vector<
std::pair< double, P > > Q, std::pair< double, P> p)
-{
- int indMin, indMax, indMid;
-
- indMin = 0;
- indMax = Q.size();
-
- if(indMax==0 || Q[indMax-1].first <= p.first)
- Q.push_back(p);
- else
- {
- while(indMax > indMin)
- {
- indMid = int(indMin + (indMax-indMin)/2);
- if(Q[indMid].first < p.first)
- {
- indMin = indMid+1;
- if(Q[indMin].first > p.first)
- {
- indMax = indMid;
- }
- }
- else
- {
- indMax = indMid-1;
- if(Q[indMax].first < p.first)
- {
- indMin = indMid;
- }
- }
- }
-
- typename std::vector< std::pair< double, P > >::iterator it=Q.begin();
- it = Q.insert ( it+indMin, p);
- }
-
- return Q;
-}
-
-
-const neighb2d& complement_neighborhood(const Neighborhood<neighb2d>& nbh)
-{
- if(&nbh == &c4())
- return c8();
- return c4();
-}
-
-template <typename N>
- int nb_composant_connexe(p_set< mln_psite(N) > X_full,const
Neighborhood<N>& nbh_,const mln_psite(N)& p_ref, bool local)
-{
- N nbh = exact(nbh_);
- p_set< mln_psite(N) > X;
- if(local)
- {
- mln_niter(N) n(max_neighborhood(nbh), p_ref);
-
- for_all(n)
- {
- if (X_full.has(n))
- X.insert(n);
- }
- }
- else
- {
- X = X_full;
- }
-
- int T;
- p_set< mln_psite(N) > done;
- p_set< mln_psite(N) > neighbors;
- p_set< mln_psite(N) > composant;
-
- done.insert(p_ref);
- mln_niter(N) q(nbh, p_ref);
- for_all(q)
- {
- if (X.has(q)&&!done.has(q))
- {
- neighbors.insert(q);
- }
- }
-// std::cout << "nb_composant_connexe: neighbors " <<
neighbors.nsites() <<std::endl;
- if(neighbors.nsites()<=1)
- {
- return neighbors.nsites();
- }
- else
- T=0;
-
- while(neighbors.nsites()!=0)
- {
- T++;
- done.insert(neighbors[0]);
- mln_niter(N) t(nbh, neighbors[0]);
- neighbors.remove(neighbors[0]);
- for_all(t)
- {
- if (X.has(t)&&!done.has(t))
- {
- composant.insert(t);
- }
- }
+#ifndef MLN_SKELETON_HH
+# define MLN_SKELETON_HH
- while(composant.nsites()!=0)
- {
- done.insert(composant[0]);
- if(neighbors.has(composant[0]))
- {
- neighbors.remove(composant[0]);
- if(neighbors.nsites()==0)
- return T;
- }
+# include <iomanip>
+# include <iostream>
+# include <sstream>
- mln_niter(N) r(nbh, composant[0]);
- composant.remove(composant[0]);
- for_all(r)
- {
- if (X.has(r) && !done.has(r))
- {
- composant.insert(r);
- }
- }
- }
- }
- return T;
-}
-
-template <typename N>
- bool simple_point(p_set< mln_psite(N) > X,const Neighborhood<N>& nbh,
p_set< mln_psite(N) > X_complement, const mln_psite(N)& p_ref, bool local)
-{
- int nX = nb_composant_connexe(X,exact(nbh),p_ref,local);
- int nX_complement =
nb_composant_connexe(X_complement,complement_neighborhood(exact(nbh)),p_ref,local);
-
- if((nX_complement == 1)&&(nX == 1))
- return true;
- return false;
-}
-
-
- template <typename N>
- p_set<mln_psite(N)> euclideanSkeleton(p_set<mln_psite(N)> X,
p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt,
p_set<mln_psite(N)>& Y, const Neighborhood<N>& nbh_, bool local)
- {
- std::vector< std::pair< double, mln::point2d> > Q;
- std::vector< std::pair< double, mln::point2d> > R;
- N nbh = exact(nbh_);
-
- // fill Q
- for (uint i = 0; i < X.nsites(); i++)
- {
- if (!Y.has(X[i]))
- {
- std::pair<double, mln_psite(N)> p(math::sqrt(double(dt(X[i]))),X[i]);
- Q = insertDicho(Q,p);
- }
- }
-
- // fill R
- for (uint i = 0; i < X.nsites(); i++)
- {
- if (!Y.has(X[i]))
- {
- double min = 1023.99;
- mln_niter(N) r(nbh, X[i]);
- for_all(r)
- {
- if (Y.has(r))
- {
- double tmp = distance(r[0], r[1], X[i][0], X[i][1]);
- double d =
math::sqrt(double(dt(r)))+(math::sqrt(double(dt(X[i])))-math::sqrt(double(dt(r))))/tmp;
- min = math::min(min,d);
- }
- }
- if (min!=1023.99)
- {
- std::pair<double, mln_psite(N)> p(min,X[i]);
- R = insertDicho(R, p);
- }
- }
- }
-
- while (!Q.empty() || !R.empty())
- {
- mln_psite(N) tmp;
- if (Q[0].first < R[0].first)
- {
- tmp = Q[0].second;
- }
- else
- {
- tmp = R[0].second;
- }
-
- Q = remove(Q, tmp);
- R = remove(R, tmp);
-
- if (!Y.has(tmp) && X.has(tmp))
- {
- if (simple_point(X, nbh, X_complement, tmp, local))
- {
- X.remove(tmp);
- X_complement.insert(tmp);
- }
- else
- {
- Y.insert(tmp);
- mln_niter(N) r(nbh, tmp);
- for_all(r)
- {
- if (!Y.has(r) && X.has(r))
- {
- double dist = distance(r[0], r[1], tmp[0], tmp[1]);
- double d =
math::sqrt(double(dt(tmp)))+(math::sqrt(double(dt(r)))-math::sqrt(double(dt(tmp))))/dist;
- std::pair<double, mln_psite(N)> p(d,r);
- R = insertDicho(R, p);
- }
- }
-
- }
- }
+# include <mln/core/var.hh>
- }
- return X;
- }
-
-
- p_set<point2d> EP(image2d<value::int_u8> dt, point2d x, std::vector<
std::vector<std::pair< int, int> > > lut, const neighb2d& nbh)
- {
- p_set<point2d> EP;
- p_set<point2d> tmp;
- int w = geom::ncols(dt);
- int h = geom::nrows(dt);
-
-
- mln_niter_(neighb2d) r(nbh, x);
- for_all(r)
- {
- if (dt(r) <= dt(x))
- {
- for (uint i=0; i<lut[dt(r)].size(); i++)
- {
- if ((r[0]+lut[dt(r)][i].first < h) && (r[1]+lut[dt(r)][i].second < w))
- {
- if (!dt(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second)))
- EP.insert(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second));
- }
- if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]-lut[dt(r)][i].second >=
0))
- {
- if (!dt(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second)))
- EP.insert(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second));
- }
- if ((r[0]+lut[dt(r)][i].first < h) && (r[1]-lut[dt(r)][i].second >= 0))
- {
- if (!dt(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second)))
- EP.insert(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second));
- }
- if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]+lut[dt(r)][i].second < w))
- {
- if (!dt(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second)))
- EP.insert(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second));
- }
- if ((r[0]+lut[dt(r)][i].second < h) && (r[1]+lut[dt(r)][i].first < w))
- {
- if (!dt(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first)))
- EP.insert(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first));
- }
- if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]-lut[dt(r)][i].first >=
0))
- {
- if (!dt(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first)))
- EP.insert(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first));
- }
- if ((r[0]+lut[dt(r)][i].second < h) && (r[1]-lut[dt(r)][i].first >= 0))
- {
- if (!dt(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first)))
- EP.insert(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first));
- }
- if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]+lut[dt(r)][i].first < w))
- {
- if (!dt(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first)))
- EP.insert(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first));
- }
- }
- }
- }
-
- return EP;
- }
-
- std::vector< std::vector<std::pair< int, int> > > Lut2d(int N)
- {
- int n = int(sqrt(N))+1;
- int i=0;
- std::vector< std::vector<std::pair< int, int> > > lut;
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/cast_image.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/core/site_set/p_queue_fast.hh>
+# include <mln/core/site_set/p_priority.hh>
- for(i = 0; i <= N; i++)
- {
- std::vector<std::pair< int, int> > vect;
- lut.push_back(vect);
- }
+# include <mln/value/int_u8.hh>
+# include <mln/arith/revert.hh>
+# include <mln/transform/distance.hh>
- for(int x = 0; x <= n; x++)
- {
- for(int y = 0; y <= x; y++)
- {
- i=x*x+y*y;
- if(i<=N)
- {
- std::pair<int,int> p(x,y);
- lut[i].push_back(p);
- }
- }
- }
+# include <mln/make/w_window2d_int.hh>
- return lut;
-}
+# include <mln/level/fill.hh>
- image2d<value::int_u8> DiscreteBisector(image2d<value::int_u8> dt,
p_set<point2d> Y, const neighb2d& nbh, int N)
- {
- int w = geom::ncols(dt);
- int h = geom::nrows(dt);
+# include <mln/debug/println.hh>
- int ux,uy,vx,vy, produit, angle, max;
- double cos, normu, normv;
+# include <mln/logical/not.hh>
- std::vector< std::vector<std::pair< int, int> > > lut;
- lut = Lut2d(N);
+# include "simple_point.hh"
- p_set<point2d> proj;
+#include <mln/make/w_window2d_int.hh>
- image2d<value::int_u8> bisector(h, w);
- level::fill(bisector, 0);
+# include <mln/io/pgm/save.hh>
+# include <mln/io/pbm/save.hh>
- for (uint i=0; i<Y.nsites(); i++)
+namespace mln
{
- proj = EP(dt, Y[i], lut, nbh);
-
- int n=proj.nsites();
- if (n>1)
+ template <typename V>
+ void save_state(const image2d<V>& ima)
{
- max = 0;
- for (int y=0; y<n; y++)
- {
- for (int z=0; z<y; z++)
- {
- ux = proj[y][0]-Y[i][0];
- uy = proj[y][1]-Y[i][1];
- vx = proj[z][0]-Y[i][0];
- vy = proj[z][1]-Y[i][1];
-
- produit = ux * vx + uy * vy;
+ static int id = 0;
+ std::stringstream filename;
- normu = sqrt(ux*ux + uy*uy);
- normv = sqrt(vx*vx + vy*vy);
+ std::cout << id << std::endl;
+ filename << "skel_trace_" << std::setw(5) <<
std::setfill('0')
+ << std::right << id++ << ".ppm";
- cos = produit/(normu*normv);
- angle = int(acos(cos)*180.0/3.1415);
-
- max = math::max(max, angle);
- }
- }
- bisector(Y[i]) = max;
+ io::pbm::save(ima, filename.str());
}
- }
-
- return bisector;
-
- }
-
-
-
-const neighb2d& max_neighborhood(const Neighborhood<neighb2d>& nbh)
-{
- return c8();
-}
-template <typename N>
- p_set<mln_psite(N)> ultimateSkeleton(p_set<mln_psite(N)> X,
p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt,
p_set<mln_psite(N)> Y, const Neighborhood<N>& nbh_, bool local)
-{
- std::vector< std::pair< double, mln::point2d> > Q;
-
- N nbh = exact(nbh_);
- // fill Q
- for(uint i = 0; i < X.nsites(); i++)
+ image2d<bool> crest(const image2d<bool>& input,
+ const image2d<value::int_u8>& dist_map,
+ const neighb2d& nbh)
{
- if (!Y.has(X[i]))
- {
- std::pair<double, mln_psite(N)> p(dt(X[i]),X[i]);
- Q = insertDicho(Q,p);
- }
- }
-
+ image2d<bool> is_crest;
+ initialize(is_crest, input);
+ level::fill(is_crest, false);
- while(!Q.empty())
+ mln_piter_(image2d<value::int_u8>) p(dist_map.domain());
+ mln_niter_(neighb2d) n(nbh, p);
+ for_all(p)
{
- mln_psite(N) tmp = Q[0].second;
-
- Q = remove(Q, tmp);
+ if (!input(p) || dist_map(p) < 20)
+ continue;
- if(simple_point(X, nbh, X_complement, tmp, local))
- {
- X.remove(tmp);
- X_complement.insert(tmp);
- mln_niter(N) r(nbh, tmp);
- for_all(r)
- {
- if(!Y.has(r) && X.has(r))
+ unsigned nb_eq = 0;
+ unsigned nb_gt = 0;
+ for_all(n)
+ if (input.domain().has(n))
{
- std::pair<double, mln_psite(N)> p(dt(r),r);
- Q = insertDicho(Q, p);
- }
- }
+ if (dist_map(n) == dist_map(p))
+ nb_eq++;
+ else if (dist_map(n) > dist_map(p))
+ nb_gt++;
}
+ if ((nb_gt == 1 && nb_eq == 0) ||
+ (nb_gt == 0))
+ is_crest(p) = true;
}
- return X;
+ return is_crest;
}
- image2d<value::int_u8> intImage(image2d<bool> pic)
-{
- int w = geom::ncols(pic);
- int h = geom::nrows(pic);
-
- image2d<value::int_u8> out(h,w);
- for(int i=0; i<w; i++)
- for(int j=0; j<h; j++)
- {
- if(pic.at(j,i))
- out.at(j,i) = 1;
- else
- out.at(j,i) = 0;
- }
- return out;
-}
- image2d<bool> filteredSkeleton(image2d<bool> pic, const neighb2d& nbh,
uint r, uint alpha, bool local)
+ image2d<bool>
+ skeleton(const image2d<bool>& input, unsigned nbh_i)
{
- using value::int_u8;
+ mln_assertion(nbh_i == 4 || nbh_i == 8);
- typedef image2d<bool> I;
- typedef p_set<point2d> S;
+ neighb2d nbh = int_to_neighb(nbh_i);
+ image2d<bool> output;
+ initialize(output, input);
- image2d<value::int_u8> pic1 = intImage(pic);
- image2d<value::int_u8> dt = sedt(pic1);
- mln::io::pgm::save(dt, "dt.pgm");
+ int vals[] = { 0, 9, 0, 9, 0,
+ 9, 6, 4, 6, 9,
+ 0, 4, 0, 4, 0, // Values of distaces.
+ 9, 6, 4, 6, 9,
+ 0, 9, 0, 9, 0 };
- int w = geom::ncols(pic);
- int h = geom::nrows(pic);
- int l= math::min(w, h);
- uint rmax = getRMax(dt);
- uint rknown = 0;
- p_set<point2d> X,Y,Z;
- p_set<point2d> X_complement, Z_complement;
+ image2d<value::int_u8> dist_map_n = transform::distance(value::int_u8(),
logical::not_(input), nbh, make::w_window2d_int(vals));
+ image2d<value::int_u8> dist_map = arith::revert(dist_map_n);
- image2d<value::int_u8> DTg(l,l,0);
- std::vector< std::vector<int> > Mgl;
- std::vector< std::vector<int> > Lut;
+ io::pgm::save(dist_map, "distance.pgm");
+ io::pgm::save(dist_map_n, "distance_n.pgm");
- Mgl = CompLutMask (DTg,Mgl,Lut,l,0,rmax);
+ // Make K
+ image2d<bool> K = crest(input, dist_map_n, nbh);
- rknown =rmax;
+ io::pbm::save(K, "K.pbm");
- mln_fwd_piter_(image2d<bool>) p(pic.domain());
+ typedef mln_site_(image2d<bool>) P;
+ p_priority<value::int_u8, p_queue_fast<P> > q;
- for_all(p)
- {
- if (pic(p)==1)
+ // Initialization.
{
- X.insert(p);
- }
- else
- {
- X_complement.insert(p);
- }
- }
- std::cout << " medial axis " << std::endl;
- pic = MA(pic, Mgl, dt, Lut);
-
- mln::io::pbm::save(pic, "ma.pbm");
+ p_priority<value::int_u8, p_queue_fast<P> > q_tmp;
+ level::fill(output, input);
+ mln_piter_(image2d<bool>) p(input.domain());
for_all(p)
- {
- if (pic(p)==1)
- {
- Y.insert(p);
+ if (!input(p) &&
+ is_simple_point2d(input, nbh_i, p)) // p is a simple point of background
+ q.push(dist_map(p), p);
}
- }
-
- std::cout << " euclidean skeleton " << std::endl;
- Z = euclideanSkeleton(X, X_complement, dt, Y, nbh, local);
-
- sub_image<I, S> es = pic | Z;
- I es1(pic.domain());
- level::fill(es1, false);
- level::paste(es, es1);
-
- mln::io::pbm::save(es1, "euclidean.pbm");
-
- for_all(p)
+ // Propagation.
{
- if (!Z.has(p))
+ P p;
+ mln_niter_(neighb2d) n(nbh, p);
+ while (! q.is_empty())
{
- Z_complement.insert(p);
- }
- }
- std::cout << " discrete bisector " << std::endl;
- pic1 = DiscreteBisector(dt, Y, nbh, rmax);
-
-
- mln::io::pgm::save(pic1, "bisector.pgm");
+ p = q.pop_front();
- uint cpt=0;
- while (cpt!=Y.nsites())
- {
- if (dt(Y[cpt])>=r && pic1(Y[cpt])>=alpha)
- {
- cpt++;
+ for_all(n)
+ if (output.domain().has(n) &&
+ output(n) &&
+ K(n) == false &&
+ is_simple_point2d(output, nbh_i, n)
+ // && // n is simple
+ // !is_curve_extremum(output, nbh_i, n, 1)
+ )
+ {
+ output(n) = false; // Remove n from object
+ // save_state(output);
+ q.push(dist_map(n), n);
}
- else
- {
- Y.remove(Y[cpt]);
}
}
-
- sub_image<I, S> skel = pic | Y;
- I test(pic.domain());
- level::fill(test, false);
-
- level::paste(skel, test);
-
- mln::io::pbm::save(test, "Y.pbm");
-
- std::cout << " ultimate skeleton " << std::endl;
- Z = ultimateSkeleton(Z, Z_complement, dt, Y, nbh, local);
-
-
-
- sub_image<I, S> skeleton = pic | Z;
- I output(pic.domain());
- level::fill(output, false);
-
- level::paste(skeleton, output);
-
return output;
}
-} // End of namespace mln
-#endif // ! SKELETON_HH
+} // end of namespace mln
+
+#endif
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/check_simple_point.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/check_simple_point.cc (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/check_simple_point.cc (revision
2750)
@@ -0,0 +1,61 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/labeling/blobs.hh>
+#include <mln/level/fill.hh>
+#include <mln/debug/println.hh>
+#include "simple_point.hh"
+
+
+int main()
+{
+ using namespace mln;
+ using namespace mln::value;
+
+ typedef image2d<bool> I;
+ image2d<bool> ima(3,3);
+ point2d p(1,1);
+
+ std::cout << "----- Object in C8 ------" << std::endl;
+
+ for (unsigned i = 0; i < 256; i++)
+ {
+ level::fill(ima, false);
+ int_u8 tmp = i;
+
+ mln_niter_(neighb2d) n(c8() , p);
+ for_all(n)
+ {
+ if (tmp % 2)
+ ima(n) = true;
+ tmp = tmp >> 1;
+ }
+
+ unsigned x;
+ labeling::blobs(ima, c8(), x);
+
+ mln_assertion(nb_connexity2d(ima, 8, p, true) == x);
+ }
+
+ std::cout << "----- Object in C4 ------" << std::endl;
+
+ for (unsigned i = 0; i < 256; i++)
+ {
+ level::fill(ima, false);
+ int_u8 tmp = i;
+
+ mln_niter_(neighb2d) n(c8() , p);
+ for_all(n)
+ {
+ if (tmp % 2)
+ ima(n) = true;
+ tmp = tmp >> 1;
+ }
+
+
+ unsigned x;
+ labeling::blobs(ima, c4(), x);
+
+ mln_assertion(nb_connexity2d(ima, 4, p, true) == x);
+ }
+}
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.old.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.old.cc (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.old.cc (revision 2750)
@@ -0,0 +1,30 @@
+
+#include <mln/core/alias/point2d.hh>
+#include "skeleton.hh"
+#include <mln/level/paste.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/sub_image.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/io/pbm/load.hh>
+
+
+int main(int argc, char* argv[])
+{
+ if(argc!=5)
+ {
+ std::cout << "arguments: filename voisinage R alpha" <<
std::endl;
+ exit(1);
+ }
+ image2d<bool> output;
+ std::string filename = argv[1];
+ int r = atoi(argv[3]);
+ int alpha = atoi(argv[4]);
+
+ image2d<bool> pic = io::pbm::load(filename);
+ if(atoi(argv[2])==4)
+ output = filteredSkeleton( pic, c4(), r, alpha, true);
+ else
+ output = filteredSkeleton( pic, c8(), r, alpha, true);
+ mln::io::pbm::save(output,
"FS-"+std::string(argv[2])+"_"+std::string(argv[3])+"_"+std::string(argv[4])+"_"+filename);
+}
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/check.sh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/check.sh (revision 2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/check.sh (revision 2750)
@@ -22,7 +22,6 @@
d_without=`diff ./tmp/without tmp/ref | diffstat | grep insert | sed -r 's/.*,
([0-9]+) insertion.*/\1/g'`
echo "$(($d_without * 100 / $total))% missmatch without preprocessing"
- ./ocr_with_preprocess $i tmp/`basename $i` | sed -e 's/\(.\)/\1\n/g' >
tmp/with
d_with=`diff ./tmp/with tmp/ref | diffstat | grep insert | sed -r 's/.*,
([0-9]+) insertion.*/\1/g'`
echo "$(($d_with * 100 / $total))% missmatch with preprocessing"
echo ""
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/simple_point.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/simple_point.cc (revision 2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/simple_point.cc (revision 2750)
@@ -32,7 +32,7 @@
mln_piter_(I) p(input.domain());
for_all(p)
- if (input(p) && simple_point2d(input, 8, p))
+ if (input(p) && simple_point2d(input, 4, p))
output(p) = true;
io::pbm::save(output, argv[2]);
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr_with_preprocess.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr_with_preprocess.cc (revision
2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr_with_preprocess.cc (revision
2750)
@@ -38,23 +38,28 @@
#include "resize.hh"
#include "enlarge.hh"
#include "skeleton.hh"
+
#include <mln/linear/gaussian.hh>
#include <mln/trace/all.hh>
-#include <mln/io/pgm/load.hh>
-#include <mln/io/pgm/save.hh>
-#include <mln/io/pbm/load.hh>
-#include <mln/io/pbm/save.hh>
-#include <mln/core/alias/w_window2d_float.hh>
+
+#include <mln/fun/p2v/ternary.hh>
+#include <mln/pw/image.hh>
#include <mln/debug/println.hh>
-#include <mln/geom/chamfer.hh>
-#include <mln/make/win_chamfer.hh>
#include <mln/labeling/regional_maxima.hh>
#include <mln/morpho/dilation.hh>
+#include <mln/win/octagon2d.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/logical/not.hh>
#include <tesseract/baseapi.h>
+
// _COMPILATION_
// g++ -DNDEBUG -O3 -I../../.. ocr.cc -L/usr/lib -ltesseract_full -lpthread
@@ -93,38 +98,69 @@
io::pbm::load(input, argv[1]);
// Resize
- image2d<int_u8> output = enlarge(input, 1);
+ std::cerr << "Enlarge the image" << std::endl;
+ image2d<int_u8> enlarged = enlarge(logical::not_(input), 2);
+ //image2d<bool> enlarged = geom::resize(logical::not_(input), 4);
+ io::pgm::save(enlarged, "1_enlage.pgm");
- // TODO CLEANUP
-#if 1
// Blur.
- output = linear::gaussian(output, 1);
-#endif
+ std::cerr << "Blur the enlarged image" << std::endl;
+// image2d<int_u8> blur = linear::gaussian(fun::p2v::ternary(pw::value(enlarged),
pw::cst(int_u8(255)), pw::cst(int_u8(0))) | enlarged.domain(),
+// 4);
+ image2d<int_u8> blur = linear::gaussian(enlarged, 1);
+
+ io::pgm::save(blur, "2_gaussian.pgm");
+
+ // Crest.
+// image2d<bool> c = crest(enlarged, blur, c4());
+// io::pbm::save(c, "3_crest.pbm");
+
+
-#if 1
// Threshold
- mln_piter_(image2d<unsigned>) p(output.domain());
- for_all(p)
+ image2d<bool> binary;
{
- output(p) = output(p) > 150 ? 255 : 0;
- }
-#endif
+ std::cerr << "Threshold the blur image" << std::endl;
+
+// // Compute the histogram.
+// histo::data<int_u8> h = histo::compute(blur);
+// image1d<std::size_t> h_ima = convert::to_image(h);
-#if 0
- // Compute chamfer distance map.
- const w_window2d_int& w_win = make::mk_chamfer_3x3_int<8, 0> ();
- image2d<unsigned> out = geom::chamfer(output, w_win, 255);
+// // Blur the histogram.
+// h_ima = linear::gaussian(h_ima, 4);
+// // Get the maxima.
+// unsigned n;
+// image1d<std::size_t> maxs = regional_maxima(h_ima, c2(), n);
+// mln_piter()
+
+
+ initialize(binary, blur);
+ mln_piter_(image2d<int_u8>) p(blur.domain());
for_all(p)
- {
- out(p) = out(p) > 10 ? 255 : 0;
- }
-#endif
+ binary(p) = blur(p) > 100;
- io::pgm::save(cast_image<int_u8>(output), argv[2]);
+ io::pbm::save(binary, "3_threshold.pbm");
+ }
- std::cout << "> with preprocessing." << std::endl;
- char* s = tesseract("fra", output);
+ // Skeleton
+ std::cerr << "Compute the skeleton" << std::endl;
+ image2d<bool> skel = skeleton(binary, 4);
+ io::pbm::save(skel, "4_skeleton.pbm");
+
+ // Dilation
+ std::cerr << "Dilate the skeleton" << std::endl;
+ win::octagon2d oct(7);
+ for (unsigned i = 0; i < 1; i++)
+ skel = morpho::dilation(skel, oct);
+
+ io::pbm::save(skel, "5_dilation.pbm");
+
+ io::pbm::save(skel, argv[2]);
+
+ std::cerr << "Text recognition" << std::endl;
+ char* s = tesseract("fra", clone(logical::not_(skel)));
+ std::cerr << "Tesseract result:"<< std::endl;
std::cout << s;
free(s);
}
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh (revision 2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh (revision 2750)
@@ -1,10 +1,16 @@
-#ifndef ENLARGE_HH
-# define ENLARGE_HH
-
# include <iostream>
# include <mln/core/image/image2d.hh>
+# include <mln/core/routine/initialize.hh>
+
# include <mln/value/int_u8.hh>
+# include <mln/fun/p2v/ternary.hh>
+
+# include <mln/pw/image.hh>
+# include <mln/pw/cst.hh>
+# include <mln/pw/value.hh>
+
+# include <mln/core/routine/clone.hh>
float val(bool b) { return b ? 1 : 0; }
@@ -14,11 +20,12 @@
return 255.f * value;
}
+namespace mln
+{
-mln::image2d<mln::value::int_u8>
-enlargex2(mln::image2d<bool> input)
+ image2d<value::int_u8>
+ enlargex2(const image2d<bool>& input)
{
- using namespace mln;
using value::int_u8;
unsigned nrows, ncols;
@@ -91,31 +98,104 @@
}
-// enlarge 2^n times
-mln::image2d<mln::value::int_u8>
-enlarge(mln::image2d<bool> input, unsigned int n)
+
+ image2d<value::int_u8>
+ enlargex2(const image2d<value::int_u8>& input)
{
- using namespace mln;
using value::int_u8;
- image2d<int_u8> output;
+ unsigned nrows, ncols;
+
+ nrows = input.nrows();
+ ncols = input.ncols();
+
+ image2d<int_u8> output(2 * nrows, 2 * ncols);
+ unsigned value;
+
+ // row 0
+
+ output.at(0, 0) = (input.at(0, 0));
+
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = (input.at(0, col / 2));
+ value += (input.at(0, col / 2 - 1));
+ output.at(0, col) = (value / 2);
+ }
+
+ for (int col = 1; col < output.ncols(); col += 2)
+ output.at(0, col) = (input.at(0, col / 2));
+
+ // col 0
+
+ for (int row = 2; row < output.nrows(); row += 2)
+ {
+ value = (input.at(row / 2, 0));
+ value += (input.at(row / 2 - 1, 0));
+ output.at(row, 0) = (value / 2);
+ }
+
+ for (int row = 1; row < output.nrows(); row += 2)
+ output.at(row, 0) = (input.at(row / 2, 0));
+
+ // others
- do
+ for (int row = 2; row < output.nrows(); row += 2)
+ {
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = (input.at(row / 2, col / 2));
+ value += (input.at(row / 2 - 1, col / 2));
+ value += (input.at(row / 2, col / 2 - 1));
+ value += (input.at(row / 2 - 1, col / 2 - 1));
+ output.at(row, col) = ((unsigned(value)+2) / 4);
+ }
+ for (int col = 1; col < output.ncols(); col += 2)
{
- output = enlargex2(input);
+ value = (input.at(row / 2, col / 2));
+ value += (input.at(row / 2 - 1, col / 2));
+ output.at(row, col) = (value / 2);
+ }
+ }
- if (--n > 0)
+ for (int row = 1; row < output.nrows(); row += 2)
{
- initialize(input, output);
- mln_piter_(image2d<bool>) p(input.domain());
- for_all(p)
- input(p) = output(p) > 0;
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = (input.at(row / 2, col / 2));
+ value += (input.at(row / 2, col / 2 - 1));
+ output.at(row, col) = (value / 2);
+ }
+ for (int col = 1; col < output.ncols(); col += 2)
+ output.at(row, col) = (input.at(row / 2, col / 2));
}
- else
- break;
+
+ return output;
}
- while (1);
+
+
+
+
+
+
+ // enlarge 2^n times
+ image2d<value::int_u8>
+ enlarge(const image2d<bool>& input, unsigned int n)
+ {
+ using value::int_u8;
+
+ if (n == 0)
+ return clone(fun::p2v::ternary(pw::value(input),
+ pw::cst(int_u8(255)),
+ pw::cst(int_u8(0)))
+ | input.domain());
+
+ image2d<int_u8> output = enlargex2(input);
+
+ while (--n)
+ output = enlargex2(output);
+
return output;
}
-#endif // ! ENLARGE_HH
+} // mln
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/Makefile
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/Makefile (revision 2749)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/Makefile (revision 2750)
@@ -19,3 +19,8 @@
check: logs tmp ocr_without_preprocess ocr_with_preprocess
./check.sh
+
+skeleton: skeleton.cc
+ g++ -DNDEBUG -W -Wall -Wextra ${CXXFLAGS} $< -o $@
+
+.PHONY: skeleton