r2750: Improve Skeleton computation

URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox ChangeLog: 2008-10-31 Matthieu Garrigues <garrigues@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
participants (1)
-
Matthieu Garrigues