X-Git-Url: http://git.asbjorn.it/?a=blobdiff_plain;f=lib%2Fgocr%2Focr0n.c;fp=lib%2Fgocr%2Focr0n.c;h=c833c5886db71d1ff68a16de64881e24c00c9c82;hb=8154e11e1c06aefe18c16b33f2b12d6de21273a4;hp=0000000000000000000000000000000000000000;hpb=e8fe2f290123fc66181709a8a5263ad9e91c6939;p=swftools.git diff --git a/lib/gocr/ocr0n.c b/lib/gocr/ocr0n.c new file mode 100644 index 0000000..c833c58 --- /dev/null +++ b/lib/gocr/ocr0n.c @@ -0,0 +1,1254 @@ +/* ocr-engine numbers only */ +/* +This is a Optical-Character-Recognition program +Copyright (C) 2000-2007 Joerg Schulenburg + +This program 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; either version 2 +of the License, or (at your option) any later version. + +This program 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 program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + see README for EMAIL-address + + OCR engine (c) Joerg Schulenburg + first engine: rule based --- numbers 0..9 + +*/ + +#include +#include +/* #include "pgm2asc.h" */ +#include "ocr0.h" +#include "ocr1.h" +#include "gocr.h" + +/* only for debugging and development */ +#define IFV if(JOB->cfg.verbose&4) +#define MM {IFV fprintf(stderr,"\nDBG %c L%04d (%d,%d): ",(char)c_ask,__LINE__,box1->x0,box1->y0);} + +/* the old debug mode (0.40) was only for a special char, for another char + * code must be recompiled with C_ASK='char' + * new debug mode (0.41) explains why char is declined or accepted as ABC... + * the output can be filtered by external scripts + * ToDo: we could reduce output to filter string + */ +#ifndef DO_DEBUG /* can be defined outside */ +#define DO_DEBUG 0 /* 0 is the default */ +#endif + +/* this macro is for debugging output: "if char is declined, why?" */ +#if DO_DEBUG /* 0=Work mode, 1=debugging mode */ +// Setac: output, that char is choosen with a probability +// Break: output, why the char is not choosen +// MSG: debugging functions for char C_ASK, mostly messages +// DBG: definitions usefull only for debugging +#define Setac(box1,ac,ad) { MM;IFV fprintf(stderr,"setac %d",ad);setac(box1,ac,ad); } +#define Break { MM;IFV fprintf(stderr,"break"); break; } +#define MSG(x) { MM;IFV x } +#define DBG(x) x +#else +#define Setac(box1,ac,ad) setac(box1,ac,ad) +#define Break break +#define MSG(x) +#define DBG(x) +#endif + +/* extern "C"{ */ + +// OCR engine ;) +wchar_t ocr0n(ocr0_shared_t *sdata){ + struct box *box1=sdata->box1; + pix *bp=sdata->bp; + int d,x,y,x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1; + int dx=x1-x0+1,dy=y1-y0+1,cs=sdata->cs; // size + int xa,xb,ya,yb, /* tmp-vars */ + i1,i2,i3,i4,i,j; + int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */ + wchar_t bc=UNKNOWN; // best char + int ad=0; // propability 0..100 + int hchar=sdata->hchar; // char is higher than 'e' + int gchar=sdata->gchar; // char has ink lower than m3 + int dots=box1->dots; + // --- test 5 near S --------------------------------------------------- + for(ad=d=100;dx>2 && dy>4;){ // min 3x4 + DBG( char c_ask='5'; ) + if (sdata->holes.num > 1) Break; /* be tolerant */ + if( num_cross( dx/2, dx/2,0,dy-1,bp,cs)!=3 + && num_cross(5*dx/8,3*dx/8,0,dy-1,bp,cs)!=3 ) Break; + + i1=loop(bp,dx-1,dy-1,dx,cs,0,LE); + i2=loop(bp,dx-1,dy-2,dx,cs,0,LE); + if (i2-i1 >= dx/4) Break; // ~{ 5x7font + + // get the upper and lower hole koords, y around dy/4 ??? + x=5*dx/8; + y =loop(bp,x,0,dy,cs,0,DO); if(y>dy/8) Break; + y +=loop(bp,x,y,dy,cs,1,DO); if(y>dy/4) Break; + i1 =loop(bp,x,y,dy,cs,0,DO)+y; if(i1>5*dy/8) Break; + i3=y=(y+i1)/2; // upper end can be shifted to the right for italic + x =loop(bp,0,y,dx,cs,0,RI); if(x>4*dx/8) Break; + x +=loop(bp,x,y,dx,cs,1,RI); if(x>5*dx/8) Break; + i1 =loop(bp,x,y,dx,cs,0,RI); i1=(i1+2*x)/2; // upper center (i1,i3) + y=11*dy/16; + x =loop(bp,dx-1 ,y,dx,cs,0,LE); if(x>dx/4) Break; + x +=loop(bp,dx-1-x,y,dx,cs,1,LE); if(x>dx/2) Break; + i2 =loop(bp,dx-1-x,y,dx,cs,0,LE); i2=dx-1-(i2+2*x)/2; // lower center x + + MSG( fprintf(stderr,"i1,i3=%d,%d i2=%d (upper+lower center)",i1,i3,i2);) + + y =loop(bp,i1,0,dy,cs,0,DO); + y +=loop(bp,i1,y,dy,cs,1,DO); + y =(3*y+i3)/4; + if( num_cross( i1, dx-1, y, y,bp,cs)>0 ){ /* S or serif5 ? */ + y =loop(bp,i1 ,i3,dy,cs,0,DO); + i =loop(bp,i1-1,i3,dy,cs,0,DO); + if (y>i ) ad=99*ad/100; /* looks like S */ + y =loop(bp,i1 ,i3,dy,cs,0,UP); + i =loop(bp,i1+1,i3,dy,cs,0,UP); + if (ii ) ad=99*ad/100; /* looks like S */ + if( num_cross( 0, dx/2, dy-1, dy-1,bp,cs)>1 + && num_cross( dx/2,dx-1, 0, 0,bp,cs)>1 ) ad=98*ad/100; /* serifs */ + if (loop(bp,0,dy-1,dx,cs,0,RI)==0) ad=98*ad/100; /* S or 7segment */ + ad=99*ad/100; + } + + for(y=dy/5;y<3*dy/4;y++) // right gap? + if( num_cross(i1,dx-1,y,y,bp,cs)==0 ) break; + if( y==3*dy/4 ) Break; + + for(y=dy/4;y<=11*dy/16;y++) // left gap? + if( num_cross(0,i2,y,y,bp,cs)==0 ) break; + if( y>11*dy/16 ) Break; + + // if( num_hole( x0, x1, y0, y1, box1->p,cs,NULL) > 0 ) break; + if (sdata->holes.num>0) Break; + + // sS5 \sl z left upper v-bow ? + for(x=dx,i=y=dy/4;yi2 ) i2=i; + i3=loop(bp,0, y ,dx,cs,0,RI); + i =loop(bp,0, y-1,dx,cs,0,RI); if( i=20 && dx<16 ) /* tall S */ + if( loop(bp,0, dy/5 ,dx,cs,0,RI) + ==loop(bp,0, dy/4 ,dx,cs,0,RI) + && + loop(bp,0, dy/10 ,dx,cs,0,RI) + >loop(bp,0, dy/4 ,dx,cs,0,RI) + && + loop(bp,0, 1 ,dx,cs,0,RI) + >loop(bp,0, dy/4 ,dx,cs,0,RI)+1 + && + loop(bp,dx-1, 0 ,dx,cs,0,LE) + >loop(bp,dx-1, 1 ,dx,cs,0,LE) ) Break; + + if( dy>=30 && dx>15 ) /* large S */ + if( loop(bp,dx/4,3*dy/10,dy,cs,1,DO)>0 ) // check start + if( loop(bp,dx-2,3*dy/4 ,dy,cs,1,UP)>0 ) // check end + if( num_cross(dx/4,dx-2,3*dy/10,3*dy/4,bp,cs)==1 ) Break; // connected? + + if( dy>17 && dx>9 ) /* S */ + if( loop(bp, 0,dy/2 ,dx,cs,0,RI)0 ) // check start + if( loop(bp,dx-2,2*dy/3 ,dy,cs,1,UP)>0 ) // check end + if( loop(bp, 0, dy/16,dx,cs,0,RI) + >= loop(bp,dx-1, dy-1-dy/16,dx,cs,0,LE) ) ad=ad*98/100; + if( loop(bp,dx-1, dy/16,dx,cs,0,LE) + >= loop(bp, 0, dy-1-dy/16,dx,cs,0,RI) + && loop(bp,dx-1, dy/16,dx,cs,0,LE) + >= loop(bp, 0, dy-1,dx,cs,0,RI) ) ad=ad*98/100; + + if ( gchar) ad=99*ad/100; + if (!hchar) ad=99*ad/100; + Setac(box1,(wchar_t)'5',ad); + if (ad==100) return '5'; + break; + + } + // --- test 1 --------------------------------------------------- + for(ad=d=100;dy>4 && dy>dx && 2*dy>box1->m3-box1->m2;){ // min 3x4 + DBG( char c_ask='1'; ) + if( dots==1 ) Break; + if (sdata->holes.num > 1) Break; /* be tolerant */ + + if( num_cross(0, dx-1, 0 , 0 ,bp,cs) != 1 + && num_cross(0, dx-1, 1 , 1 ,bp,cs) != 1 ) Break; + if( num_cross(0, dx-1,dy/2,dy/2,bp,cs) != 1 ) Break; + if( num_cross(0, dx-1,dy-1,dy-1,bp,cs) != 1 + && num_cross(0, dx-1,dy-2,dy-2,bp,cs) != 1 ) Break; + /* 5x7 micr + + ooo + .$. ooo + $@. oo + .$. oo + .@. ooooo + .$. ooooo + $@$ ooooo + + */ + + i4=0; // human font + if( num_cross(0, dx-1,3*dy/4,3*dy/4,bp,cs) != 2 ) { // except ocr-a + for( y=1; y=dy/2) ad=98*ad/100; + for( i=dy/8,y=7*dy/16;y8 && !i ) Break; + } else { // ocr-a-1 + /* @@@.. + ..@.. + ..@.. + ..@.. + ..@.@ + ..@.@ + @@@@@ */ + i= loop(bp,dx/2,0,dy,cs,0,DO); + if (loop(bp,dx/2,i,dy,cs,1,DO) 1 + && num_cross(0, dx-1, 1 , 1 ,bp,cs) > 1 ) Break; // ~/it_7 + + // calculate upper and lower mass center (without lower serif) + + x =loop(bp,0,7*dy/8-1,dx,cs,0,RI); i2=x; + x+=loop(bp,x,7*dy/8-1,dx,cs,1,RI)-1; i2=(i2+x)/2; + + i1=loop(bp,dx-1 ,1+0* dy/4,dx,cs,0,LE); i1=dx-1-i1-(x-i2)/2; + + x =(i1-i2+4)/8; i1+=x; i2-=x; + + if( get_line2(i1,0,i2,dy-1,bp,cs,100)<95 ) { // dont work for ocr-a-1 + i1=loop(bp,dx-1 ,1+0* dy/4,dx,cs,0,LE); i1=dx-1-i1; + if( get_line2(i1,0,i2,dy-1,bp,cs,100)<95 ) Break; + } + // upper and lower width + x =loop(bp,(i1+i2)/2,dy/2,dx,cs,1,RI); i=x; i3=0; + for(y=0;y<7*dy/8;y++) + if( loop(bp,i1+y*(i2-i1)/dy, y,dx,cs,1,RI)-i > 1+dx/8 ) break; + if(y<7*dy/8) ad=98*ad/100; // serif or ocr-a-1 ? + if(y<6*dy/8) ad=99*ad/100; /* MICR E-13B font Jan07 */ + if(y<4*dy/8) Break; +// out_x(box1); printf(" i12=%d %d\n",i1,i2); + x =loop(bp,i2,dy-1,dx,cs,1,LE); j=x; + x =loop(bp,i2,dy-2,dx,cs,1,LE); if(x>j)j=x; i=j; + x =loop(bp,i2,dy-1,dx,cs,1,RI); j=x; + x =loop(bp,i2,dy-2,dx,cs,1,RI); if(x>j)j=x; + if(abs(i-j)>1+dx/8) i3|=1; + if(i3) Break; +// out_x(box1);printf(" 11 i=%d j=%d i2=%d dx=%d\n",i,j,i1,dx); + // get most left upper point (i,j) + for(i=dx,j=y=0;y<7*dy/16;y++){ + x =loop(bp,0,y,dx,cs,0,RI); if(x 7*dx/16 MICR E-13B font + if ( i1-i<4*dx/16 ) Break; + x =loop(bp,0,dy/2,dx,cs,0,RI); // right distance + j =loop(bp,x,dy/2,dx,cs,1,RI); // thickness + if( j>x+(dy+16)/32 ) ad=98*ad/100; // ~l but MICR E-13B font + x =loop(bp,0,0,dx,cs,0,RI); // straight line ??? + j =loop(bp,0,1,dx,cs,0,RI); if( j>x ) Break; // ~l + if( x==j ) j =loop(bp,0,dy/8,dx,cs,0,RI); if( j>x && !i4) Break; + if( x==j ) if(loop(bp,0,dy/4,dx,cs,0,RI)>x) { // ~l + // check micr-1 first before taken as 'l' + if (loop(bp,dx-1,dy/8,dx,cs,0,LE)<=dx/4 + && loop(bp,0,3*dy/4,dx,cs,1,RI)=x ) Break; x=j; // ~l +// j =loop(bp,0, 0,dx,cs,0,DO); if( !j ) Break; // ~7 + if( !hchar ) // ~ right part of n + if( loop(bp,dx-1, 1,dx,cs,0,LE)-dy/6 + > loop(bp,dx-1,dy/4,dx,cs,0,LE) + || get_bw(x1+1,x1+2,y0,y0+dy/8,box1->p,cs,1)==1 ) Break; // Mai00 + if( loop(bp,dx-1,3*dy/4,dx,cs,0,LE) > dx/2 + && get_bw(x1-dx/4,x1,y1-1,y1,box1->p,cs,1)==1 ) Break; // ~z Jun00 + + i=loop(bp, dx/8,0,dy,cs,0,DO); + for (y=dy,x=dx/2;x<3*dx/4;x++){ /* get upper end */ + j=loop(bp,x,0,dy,cs,0,DO); if (j=i) ad=97*ad/100; // ~\tt l ??? ocr-a_1 + + if( loop(bp, 0, dy/8,dx,cs,0,RI) + -(dx-loop(bp,dx-1,7*dy/8,dx,cs,0,LE)) > dx/4 ) Break; // ~/ + + i= loop(bp, 0, 0,dy,cs,0,DO); // horizontal line? + if(dy>=12 && i>dy/8 && iloop(bp,dx-1, i,dx,cs,0,LE) + || loop(bp,dx-1,3*dy/16,dx,cs,0,LE)-dx/8 + >loop(bp,dx-1, i+1,dx,cs,0,LE) ) Break; // ~t,~f + i= loop(bp, 0,dy-1-dy/32,dx,cs,0,RI); + x= loop(bp, 0,dy-2-dy/32,dx,cs,0,RI); if (idx/8 + && loop(bp,dx-1, 3*dy/4,dx,cs,0,LE)-dx/8 + >loop(bp,dx-1,dy-1-dy/32,dx,cs,0,LE) ) Break; // ~t + if( loop(bp, 0,i-1,dx,cs,0,RI)>1 && dx<6) { + ad=99*ad/100; + if ( loop(bp,dx-1,i-1,dx,cs,0,LE)>1 ) Break; // ~t + } + } + + if (dx>8){ + if (loop(bp,0,3*dy/4,dx,cs,0,RI)- + loop(bp,0,dy/2-1,dx,cs,0,RI)>dx/4) ad=95*ad/100; // ~3 + if (loop(bp,dx-1,dy/2-1,dx,cs,0,LE)- + loop(bp,dx-1,3*dy/4,dx,cs,0,LE)>dx/8) ad=95*ad/100; // ~3 + if (loop(bp,dx-1, dy/16,dx,cs,0,LE)- + loop(bp,dx-1, dy/4,dx,cs,0,LE)>dx/8) ad=95*ad/100; // ~23 + } + /* font 5x9 "2" recognized as "1" */ + i=loop(bp,dx-1-dx/8,dy-1,dy,cs,0,UP); + if (i<=dy/4) { + i+=loop(bp,dx-1-dx/8,dy-1-i,dy,cs,1,UP); + if (i<=dy/4) { + i=loop(bp,dx-1-dx/8,dy-1-i,dy,cs,0,LE); + if (2*i>=dx && loop(bp,dx/4,0,dy,cs,0,DO)i+dx/8) { break; } + } if (y>=dy/2) ad=95*ad/100; // Feb07 care plates, right black border + + if (sdata->holes.num > 0) Break; // mini holes should be filtered + if (!box1->m3 && ad>98) ad=98; else { + if (!hchar) ad=99*ad/100; + if (box1->y0>box1->m2) ad=98*ad/100; + if (box1->y1<(1*box1->m2+3*box1->m3)/4) ad=98*ad/100; + if (box1->y1-box1->y0<(box1->m3-box1->m1)/2) ad=98*ad/100; + if ( gchar) ad=99*ad/100; + } + + Setac(box1,(wchar_t)'1',ad); + break; + } + // --- test 2 old pixelbased - remove! ----------------------------- +#ifdef Old_pixel_based + for(ad=d=100;dx>2 && dy>4;){ // min 3x4 + DBG( char c_ask='2'; ) + if (sdata->holes.num > 1) Break; /* be tolerant */ + if( get_bw(x0+dx/2, x0+dx/2 , y1-dy/5, y1 ,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/2, x0+dx/2 , y0 , y0+dy/5,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/8, x1-dx/3 , y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break; + + if( get_bw(x1-dx/3, x1 , y0+dy/3 , y0+dy/3,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0 , x0+dx/ 8, y1-dy/16, y1 ,box1->p,cs,1) != 1 ) Break; + if( num_cross(x0, x1-dx/8, y0+dy/2, y0+dy/2,box1->p,cs) != 1 ) Break; + if( get_bw(x0, x0+dx/9 , y0 , y0 ,box1->p,cs,1) == 1 + && get_bw(x0, x0+dx/2 ,y0+3*dy/16,y0+3*dy/16,box1->p,cs,1) == 1 ) Break; + if( get_bw(x0, x0+dx/9 , y0 , y0 ,box1->p,cs,1) + != get_bw(x1-dx/9, x1 , y0 , y0 ,box1->p,cs,1) ) + { if (dx<6 && dy<9) ad=99*ad/100; else Break; } + // out_x(box1); + + for( x=x0+dx/4;xp,cs) == 2 ) break; + if( x>=x1-dx/6 ) Break; + + for( x=x0+dx/4;xp,cs) == 2 ) break; + if( x>=x1-dx/6 ) Break; + + for(i=1,y=y0;yp,cs) == 2 ) i=0; + if( i ) ad=99*ad/100; // ToDo: ocr-a-2 should have 100% + + for(i=1,y=y0+dy/5;yp,cs,1) == 0 ) i=0; + if( i ) Break; + + x=x1-dx/3,y=y1; /* center bottom */ + turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( yp,&x,&y,x0,x1,y0,y1,cs,ST,UP); if( yp,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( yp,&x,&y,x0,x1,y0,y1,cs,RI,ST); + if( xp,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( yp,&x,&y,x0,x1,y0,y1,cs,RI,ST); + if( xp,x1,y0+y,dx,cs,0,LE); // use p (not b) for broken chars + if( ix ) x=i; + } + if (y>dy/3 ) Break; // z + + // hole is only allowed in beauty fonts + // if( num_hole( x0, x1, y0, y1,box1->p,cs,NULL) > 0 ) // there is no hole + // if( num_hole( x0, x0+dx/2, y0, y0+dy/2,box1->p,cs,NULL) == 0 ) // except in some beauty fonts + if (sdata->holes.num>0) + if (sdata->holes.hole[0].x1 >= dx/2 || sdata->holes.hole[0].y1 >= dy/2) + Break; + + i1=loop(bp,dx-1-dx/16,0,dy,cs,0,DO); // Jul00 + i2=loop(bp, dx/ 2,0,dy,cs,0,DO); if( i2+dy/32>=i1 ) Break; // ~z + i1=loop(bp,dx-1,dy-3*dy/16,dx,cs,0,LE); + i2=loop(bp, 0,dy-3*dy/16,dx,cs,0,RI); if( i2>i1 ) ad=98*ad/100; // ~i + if (dots) ad=98*ad/100; // i + if (loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)>dx/4) ad=96*ad/100; // \it i + + if ((!hchar) && box1->m4!=0) ad=80*ad/100; + Setac(box1,(wchar_t)'2',ad); + if (ad==100) return '2'; + break; + } +#endif + // --- test 2 new edge based v0.44 -------------------------------------- + for(ad=d=100;dx>2 && dy>4;){ // min 3x4 + // rewritten for vectors 0.42 + int ld, i1, i2, i3, i4, i5, i6, i7; // line derivation + corners + DBG( wchar_t c_ask='2'; ) + if (sdata->holes.num > 0) Break; /* no hole */ + /* half distance to the center */ + d=2*sq(128/4); + /* now we check for the lower ends, must be near to the corner */ + if (aa[1][2]>d/4) Break; /* [2] = distance, ~7... */ + if (aa[2][2]>d/2) Break; /* [2] = distance, ~r... */ + if (aa[0][2]>d/1) Break; /* [2] = distance, ~d... */ + if (aa[3][2]>d/1) Break; /* [2] = distance, ~bhk... */ + /* searching for 4 notches between neighbouring ends */ + +/* + type A B + + 1OOO OO + 2 1 2 <- 6 + 7-> OOOO O + O O <- 5 + 3OO4 3OO4 +*/ + + /* get a point on the inner low left side of the J */ + i =box1->num_frame_vectors[0] - 1; + /* rightmost point on upper left side */ + i2=nearest_frame_vector(box1, aa[0][3], aa[1][3], x1+dx, y0+dy/4); + /* upper leftmost vector */ + i1=nearest_frame_vector(box1, aa[0][3], i2, x0-dx, (y0+y1)/2); + i3=aa[1][3]; + /* low leftmost vector */ + i5=nearest_frame_vector(box1, aa[2][3], aa[3][3], x0, y1); + /* low mostright vector */ + i4=nearest_frame_vector(box1, aa[1][3], i5, x1+dx, y1); + /* next local max_x-point after i5 */ + i6=i5; + for (i=i5;i!=aa[0][3];i=(i+1)%box1->num_frame_vectors[0]) { + if (box1->frame_vector[ i][0] + >box1->frame_vector[i6][0]) i6=i; // get next maximum + if (box1->frame_vector[ i][0]frame_vector[ i][1]frame_vector[i6][0]>x0+dx/2) break; // 5 + } + /* which type? ToDo: have a more sure algorithm */ + i7=nearest_frame_vector(box1, i2, i3, x0-dx/8, (y0+y1)/2); + if (box1->frame_vector[i7][0]<=x0+ dx/4 + && box1->frame_vector[i7][1]<=y0+2*dy/3) { + MSG(fprintf(stderr,"7-segment-type");) + } else { /* regular-book-type */ + if (aa[3][0]>=x1-dx/8 + && aa[3][1]<=y0+dy/8) ad=99*ad/100; + if (aa[0][0]<=x0+dx/8 + && aa[0][1]<=y0+dy/8) ad=99*ad/100; + if (aa[3][2]<=aa[1][2]) ad=97*ad/100; + } + // ToDo: output no=(x,y) + MSG(fprintf(stderr,"i1-7 %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7);) + if (i5==i6) Break; // ~+ + + if (box1->frame_vector[i5][1] + -box1->frame_vector[i6][1]frame_vector[i1][1]>y0+dy/2) Break; // not to low + if (box1->frame_vector[i1][0]>x0+dx/8) Break; + if (box1->frame_vector[i2][1]>(y0+ y1)/2) Break; + if (box1->frame_vector[i2][1]>(5*y0+3*y1)/8) ad=99*ad/100; + if (box1->frame_vector[i2][0]<(x0+x1+1)/2) Break; // fat tiny fonts? + if (box1->frame_vector[i2][0]<(x0+2*x1)/3) ad=99*ad/100; + if (box1->frame_vector[i3][0]>(3*x0+x1)/4) Break; + if (box1->frame_vector[i3][0]>(7*x0+x1)/8) ad=99*ad/100; + if (box1->frame_vector[i3][1]<(y0+3*y1)/4) Break; + if (box1->frame_vector[i3][1]>(y0+7*y1)/8) ad=99*ad/100; + /* check lower leftmost point from right side */ + if (box1->frame_vector[i5][0]>(x0+2*x1)/3) Break; + if (box1->frame_vector[i5][0]>(x0+ x1)/2) ad=98*ad/100; + if (box1->frame_vector[i5][0]>(2*x0+x1)/3) ad=99*ad/100; + if (box1->frame_vector[i5][1]<(3*y0+5*y1)/8) Break; + if (box1->frame_vector[i5][1]<(y0+3*y1)/4) ad=99*ad/100; + if (box1->frame_vector[i6][1]>(y0+2*y1)/3) Break; + if (box1->frame_vector[i6][1]>(y0+ y1)/2) ad=99*ad/100; + if (box1->frame_vector[i6][0]<(x0+3*x1)/4) Break; + if (box1->frame_vector[i6][0]<(x0+7*x1)/8) ad=99*ad/100; + + /* check for zZ */ + + /* check if lower left and right points are joined directly */ + ld=line_deviation(box1, i3, i4); + MSG(fprintf(stderr," i1-i2 %d %d dist= %d/%d",i1,i2,ld,2*sq(1024/4));) + if (ld >2*sq(1024/4)) Break; + if (ld > sq(1024/4)) ad=99*ad/100; + + if (box1->m3) { + if(!hchar){ ad=99*ad/100; } + if( gchar){ ad=99*ad/100; } + } else { if (ad==100) ad=99; } /* not 100% sure */ + Setac(box1,'2',ad); + if (ad==100) return '2'; + break; + } + // --- test 3 ------- + for(ad=d=100;dx>3 && dy>4;){ // dy<=dx nicht perfekt! besser mittleres + // min-suchen fuer m + DBG( char c_ask='3'; ) + if (sdata->holes.num > 1) Break; /* be tolerant */ + // if( get_bw(x0+dx/2,x0+dx/2,y0,y0+dy/4,box1->p,cs,1) == 0 ) Break; // ~4 + // if( get_bw(x0+dx/2,x0+dx/2,y1-dy/8,y1,box1->p,cs,1) == 0 ) Break; // ~4 + // if( num_cross(x0+dx/2,x0+dx/2,y0 ,y1,box1->p,cs) < 2 ) Break; + // if( num_cross(x0+dx/4,x0+dx/4,y1-dy/2,y1,box1->p,cs) == 0 ) Break; + if( get_bw(dx/2,dx/2, 0,dy/6,bp,cs,1) == 0 ) Break; // ~4 + if( get_bw(dx/2,dx-1, dy/6,dy/6,bp,cs,1) == 0 ) Break; // ~j + if( get_bw(dx/2,dx/2,dy-1-dy/8,dy-1,bp,cs,1) == 0 ) Break; // ~4 + if( num_cross(dx/2,dx/2,0 ,dy-1,bp,cs) < 2 // normal + && num_cross(dx/3,dx/3,0 ,dy-1,bp,cs) < 2 ) Break; // fat LCD + if( num_cross(dx/4,dx/4,dy-1-dy/2,dy-1,bp,cs) == 0 ) Break; + if( loop(bp,dx/2, 0 ,dy,cs,0,DO)>dy/4 ) Break; + if( loop(bp,dx/2, dy-1,dy,cs,0,UP)>dy/4 ) Break; + if( loop(bp,dx-1, dy/3,dy,cs,0,LE)>dy/4 /* 3 with upper bow */ + && loop(bp,dx-1, dy/8,dy,cs,0,LE)>dy/4 /* 3 with horizontal line */ + && loop(bp,dx/4, dy/8,dy,cs,1,RI)dy/4 ) Break; + if( loop(bp,dx-1,3*dy/4,dy,cs,0,LE)>dy/2 ) Break; // ~2 Feb06 + if( loop(bp,dx-1,7*dy/8,dy,cs,0,LE)>dy/2 ) Break; // ~2 Feb06 + // search upper right half circle + for( i3=x=0,i1=y=dy/5;yx) { i3=x=i; i1=y; } + } i3--; if (i31+dx/8) ad=ad*99/100; // ~1 with a pixel + // search lower right half circle + for( i4=x=0,i2=y=dy-1-dy/8;y>=dy/2;y-- ){ + i=loop(bp,0,y,dx,cs,0,RI); + if( i>x ) { i4=x=i;i2=y; } + } i4--; if(i41+dx/8) ad=ad*99/100; // ~1 with a pixel + + for( x=xa=0,ya=y=dy/4;y<3*dy/4;y++ ){ // right gap, not on LCD-font + i=loop(bp,dx-1,y,dx,cs,0,LE); + if (i>=xa) { xa=i;ya=y;x=xa+loop(bp,dx-1-xa,y,dx,cs,1,LE); } + } if (dy>3*dx) if (xa<2 && x-xa1+dx/8 // noLCD + && xa<=loop(bp,dx-1,i2,dx,cs,0,LE)) ad=ad*99/100; // ~1 with a pixel + if (xa>1+dx/8 // noLCD + && xa<=loop(bp,dx-1,i1,dx,cs,0,LE)) ad=ad*99/100; // ~1 with a pixel + + + if( get_bw(i3,i3,i1,i2 ,bp,cs,1) != 1 ) Break; + if( get_bw(i4,i4,i1,i2 ,bp,cs,1) != 1 ) Break; + if( get_bw(i3,i3,0 ,i1 ,bp,cs,1) != 1 ) Break; + if( get_bw(i4,i4,i1,dy-1,bp,cs,1) != 1 ) Break; // m like + // hole is only allowed in beauty fonts + // if( num_hole( x0, x1, y0, y1,box1->p,cs,NULL) > 0 ) // there is no hole + // if( num_hole( x0, x0+dx/2, y0, y0+dy/2,box1->p,cs,NULL) == 0 ) // except in some beauty fonts + if (sdata->holes.num>0) + if (sdata->holes.hole[0].x1 >= dx/2 || sdata->holes.hole[0].y1 >= dy/2) + Break; + Setac(box1,(wchar_t)'3',ad); + if (ad==100) return '3'; + break; + } + // --- test 4 --------------------------------------------------- 25Nov06 + for(ad=d=100;dy>3 && dx>2;){ // min 3x4 ~holes.num > 1) Break; /* no or one hole */ + /* half distance to the center */ + d=2*sq(128/4); + /* now we check for the lower left end, must be far away */ + if (aa[1][2]num_frame_vectors[0] - 1; + /* leftmost upper point */ + i1=nearest_frame_vector(box1, 0, i, x0, y0-dy); + /* lowest from leftmost vector can be very low (20/23) */ + i2=nearest_frame_vector(box1, 0, i, x0-2*dx, (y0+7*y1)/8); + /* lowest vector */ + i4=nearest_frame_vector(box1, 0, i, (x0+2*x1)/3, y1+dy); + /* right center crossing point */ + i3=nearest_frame_vector(box1, i2, i4, x1, (3*y0+y1)/4); + /* get a point on the outer right side below top serif */ + /* next local max_y-point after i4 */ + i5=i4; + for (i=i4;i!=i2;i=(i+1)%box1->num_frame_vectors[0]) { + if (box1->frame_vector[ i][1] + frame_vector[i5][1]) i5=i; // get next maximum + if (box1->frame_vector[ i][1] + >box1->frame_vector[i5][1]+1) break; // break after maximum + if (box1->frame_vector[ i][0]num_frames>1) { // type C D + i = box1->num_frame_vectors[0] - 1; // end outer loop + j = box1->num_frame_vectors[1] - 1; // end inner loop + i6=nearest_frame_vector(box1, i+1, j, x1, y1); + i7=nearest_frame_vector(box1, i+1, j, x0, y1); + if (box1->frame_vector[i1][0] + -box1->frame_vector[i2][0]frame_vector[i ][0]-x0frame_vector[i ][1]-y07) ad=97*ad/100; // q + + } else { // type A B + i6=nearest_frame_vector(box1, i5, i1, (x0+3*x1)/4, y1-dy/8); + i7=nearest_frame_vector(box1, i5, i1, x0 , y1-dy/8); + MSG(fprintf(stderr,"open type");) + } + // ToDo: output no=(x,y) + MSG(fprintf(stderr,"i1-7 %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7);) + if (i5==i6) Break; // ~+ + + if (box1->frame_vector[i1][1]>y0+dy/8) Break; // not to low + if (box1->frame_vector[i2][1] + -box1->frame_vector[i1][1]frame_vector[i3][0] + -box1->frame_vector[i2][0]frame_vector[i3][1] + -box1->frame_vector[i2][1])>dy/4) Break; + if (box1->frame_vector[i2][0]>x0+dx/8) Break; + if (box1->frame_vector[i2][1]>y1-dy/8) Break; + if (box1->frame_vector[i4][1] + -box1->frame_vector[i2][1]frame_vector[i4][1] + -box1->frame_vector[i2][1]frame_vector[i4][1] + -box1->frame_vector[i3][1]<1+dy/16) Break; + if (box1->frame_vector[i4][1] + -box1->frame_vector[i3][1]frame_vector[i4][1] + -box1->frame_vector[i3][1]frame_vector[i4][1]frame_vector[i3][0]frame_vector[i3][0]frame_vector[i3][1]>y1-1) Break; + if (box1->frame_vector[i3][1]>y1-dy/16) Break; + if (box1->frame_vector[i3][1]>=y1) Break; // ~5x5# + if (box1->frame_vector[i5][0]frame_vector[i5][1]>y0+2*dy/3) Break; + if (box1->frame_vector[i6][1] + -box1->frame_vector[i5][1]<1+dy/16) Break; + if (box1->frame_vector[i6][0]frame_vector[i7][0]>x0+dx/2) Break; + if (box1->frame_vector[i7][0]>x0+dx/3) ad=ad*99/100; + if (box1->frame_vector[i6][1]frame_vector[i6][0]frame_vector[i6][0]=y1-1-dy/8) ad=96*ad/100; // ~ 42 + if (box1->frame_vector[i7][1]frame_vector[i3][1] + -box1->frame_vector[i2][1])>dy/4) Break; + + /* check if upper left and lower left points are joined directly */ + ld=line_deviation(box1, i1, i2); + MSG(fprintf(stderr," i1-i2 %d %d dist= %d/%d",i1,i2,ld,2*sq(1024/4));) + if (ld >2*sq(1024/4)) Break; + /* check if lower right and upper right points are joined directly */ + ld=line_deviation(box1, i2, i3); + MSG(fprintf(stderr," i2-i3 %d %d dist= %d/%d",i2,i3,ld,2*sq(1024/4));) + if (ld > sq(1024/4)) Break; + /* check if lower right and upper right points are joined directly */ + ld=line_deviation(box1, i3, i4); + MSG(fprintf(stderr," i3-i4 %d %d dist= %d/%d",i3,i4,ld,2*sq(1024/4));) + if (ld > sq(1024/4)) Break; + /* check if lower right and upper right points are joined directly */ + ld=line_deviation(box1, i6, i7); + MSG(fprintf(stderr," i6-i7 %d %d dist= %d/%d",i6,i7,ld,2*sq(1024/4));) + if (ld >2*sq(1024/4)) Break; + + // 4 exists as gchar and ~gchar + if(!hchar){ ad=99*ad/100; } + Setac(box1,'4',ad); + break; + } +#ifdef Old_pixel_based + // --- old test 4 pixelbased ------- remove! + for(ad=d=100;dx>3 && dy>5;){ // dy>dx, min 4x6 font + DBG( char c_ask='4'; ) + if (sdata->holes.num > 2) Break; /* be tolerant */ + if (sdata->holes.num > 1) ad=97*ad/100; + // upper raising or vertical line + if( loop(bp,0 ,3*dy/16,dx,cs,0,RI) + < loop(bp,0 ,2*dy/4 ,dx,cs,0,RI)-dx/8 ) Break; + // search for a vertical line on lower end + for (y=0;y= dx/2 ) break; + if (y>=dy/4) Break; + if( loop(bp,0 ,dy-1-dy/8,dx,cs,0,RI) < dx/4 ) Break; + // --- follow line from (1,0) to (0,.7) + y=0; x=loop(bp,0,0,dx,cs,0,RI); + if (x<=dx/4) { // ocr-a-4 + i=loop(bp,0,dy/4,dx,cs,0,RI); if (i>dx/4) Break; + i=loop(bp,i,dy/4,dx,cs,1,RI); if (i>dx/2) Break; + j=loop(bp,i,dy/4,dy,cs,0,DO)+dy/4; if (j>7*dy/8) Break; + } + turmite(bp,&x,&y,0,dx-1,0,dy-1,cs,DO,LE); if( x>=0 ) Break; + + y=loop(bp,0,0,dy,cs,0,DO); + if( (y+loop(bp,0,y,dy,cs,1,DO)) < dy/2 ) Break; + if( get_bw(x0 , x0+3*dx/8, y1-dy/7, y1-dy/7,box1->p,cs,1) == 1 ) Break; + if( get_bw(x0+dx/2, x1 , y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/2, x0+dx/2, y0+dy/3, y1-dy/5,box1->p,cs,1) != 1 ) Break; + i=loop(bp,bp->x-1, bp->y/4,dx,cs,0,LE); + if( i > loop(bp,bp->x-1,2*bp->y/4,dx,cs,0,LE)+1 + && i > loop(bp,bp->x-1,3*bp->y/8,dx,cs,0,LE)+1 ) Break; + if (loop(bp,0,0,dx,cs,0,RI)>dx/4) { + for(i=dx/8+1,x=0;x15 && i ) Break; + for(i=dy/10+1,y=dy-1-dy/4;yp,cs,NULL); + // ToDo: + // - get start and endpoint of left edge of left vert. line + // and check if that is an streight line + // - check the right edge of the inner hole (if there) too + i4 = sdata->holes.num; + if (sdata->holes.num >0) { // ~q + i = loop(bp,0,dy/16,dx,cs,0,RI); + if (i < dx/3) Break; + if (i < dx/2) ad=98*ad/100; // hole? + if ( loop(bp, 0,dy-1,dy,cs,0,UP) + -loop(bp,dx/8+1,dy-1,dy,cs,0,UP)>dy/16) ad=97*ad/100; + } + // thickness of left vertical line + for (j=y=0;yj) j=i; + } + if (j>=dx/2) ad=98*ad/100; // ~q handwritten a (or very thinn 4) + // ToDo: check y of masscenter of the hole q4 + + if( i4 ) if( dx > 15 ) + if( loop(bp, dx/2, 0,dy,cs,0,DO)3*dx/4 + && i-loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE)>dx/4 ) Break; + + i =loop(bp,dx-1-dx/4,dy-1,dx,cs,0,UP); + if (i> dy/2) ad=97*ad/100; + if (i>3*dy/4) ad=97*ad/100; /* handwritten n */ + + if( num_cross(0 ,dx-1,dy/16 ,dy/16 , bp,cs) == 2 // ~9 + && loop(bp,dx-1,dy/16 ,dx,cs,0,LE)> + loop(bp,dx-1,dy/16+1+dy/32,dx,cs,0,LE) ) Break; + if ( !hchar) ad=99*ad/100; + if (gchar && !hchar) ad=98*ad/100; // ~q + Setac(box1,(wchar_t)'4',ad); + if (ad>99) bc='4'; + break; + } +#endif + // --- test 6 ------- ocr-a-6 looks like a b :( + for(ad=d=100;dx>3 && dy>4;){ // dy>dx + DBG( char c_ask='6'; ) + if (sdata->holes.num > 2) Break; /* be tolerant */ + if( loop(bp, 0, dy/4,dx,cs,0,RI)>dx/2 // ocr-a=6 + && loop(bp,dx-1, 0,dy,cs,0,DO)>dy/4 ) Break; // italic-6 + if( loop(bp, 0, dy/2,dx,cs,0,RI)>dx/4 ) Break; + if( loop(bp, 0,3*dy/4,dx,cs,0,RI)>dx/4 ) Break; + if( loop(bp,dx-1,3*dy/4,dx,cs,0,LE)>dx/2 ) Break; + if( num_cross(x0+ dx/2,x0+ dx/2,y0 ,y1 ,box1->p,cs) != 3 + && num_cross(x0+5*dx/8,x0+5*dx/8,y0 ,y1 ,box1->p,cs) != 3 ) { + if( num_cross(x0+ dx/2,x0+ dx/2,y0+dy/4,y1 ,box1->p,cs) != 2 + && num_cross(x0+5*dx/8,x0+5*dx/8,y0+dy/4,y1 ,box1->p,cs) != 2 ) Break; + // here we have the problem to decide between ocr-a-6 and b + if ( loop(box1->p,(x0+x1)/2,y0,dy,cs,0,DO)p,x0+dx/2,y0,dx,cs,0,DO)>dy/8 + && loop(box1->p,x1-dx/4,y0,dx,cs,0,DO)>dy/8 ) Break; + } + if( num_cross(x0 ,x1 ,y1-dy/4,y1-dy/4,box1->p,cs) != 2 ) Break; + for( y=y0+dy/6;yp,x1 ,y ,dx,cs,0,LE); if( x>dx/2 ) break; + x+=loop(box1->p,x1-x+1,y-1,dx,cs,0,LE); if( x>dx/2 ) break; + } if( y>=y0+dy/2 ) Break; + if (loop(box1->p,x0,y1-dy/3,dx,cs,0,RI)>dx/4 ) Break; + if (loop(box1->p,x1,y1-dy/3,dx,cs,0,LE)>dx/4 ) Break; + + if (sdata->holes.num != 1) Break; + if (sdata->holes.hole[0].y1 < dy/2) ad=95*ad/100; // whats good for? + if (sdata->holes.hole[0].y0 < dy/4) Break; +// if( num_hole ( x0, x1, y0, y0+dy/2,box1->p,cs,NULL) > 0 ) ad=95*ad/100; +// if( num_hole ( x0, x1, y0+dy/4, y1,box1->p,cs,NULL) != 1 ) Break; +// if( num_hole ( x0, x1, y0 , y1,box1->p,cs,NULL) != 1 ) Break; +// out_x(box1); printf(" x0 y0 %d %d\n",x0,y0); + /* check left vertical bow */ + i1=loop(bp,0,dy/8 ,dx,cs,0,RI); + i3=loop(bp,0,dy-1-dy/8,dx,cs,0,RI); + i2=loop(bp,0,dy/2 ,dx,cs,0,RI); + if(i1+i3-2*i2<-2-dx/16 && i1+i2+i3>0) Break; // convex from left + if(i1+i3-2*i2<1 && i1+i2+i3>0) ad=99*ad/100; // 7-segment-font + for( x=dx,y=0;ydx/2 && i2>dx/4) break; /* its a 6 (example: 7-segment) */ + if (i1x) break; /* may be serifen b */ + } if (y 1 ) i++; if( i>dy/8 ) break; + } if( ydots ) ad=98*ad/100; + Setac(box1,(wchar_t)'6',ad); + bc='6'; + break; + } + // --- test 7 --------------------------------------------------- + for(ad=d=100;dx>2 && dy>4;){ // dx>1 dy>2*dx + DBG( char c_ask='7'; ) + if (sdata->holes.num > 1) Break; /* be tolerant */ + if( loop(bp,dx/2,0,dy,cs,0,DO)>dy/8 ) Break; + if( num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs) != 1 ) Break; // preselect + for( yb=xb=y=0;y0 && j>dx/4) break; // gap after h-line + j=loop(bp,j,y,dx,cs,1,RI);if(j>xb){ xb=j;yb=y; } // h-line + } if( xbx ) x=j-1; + } if( yj) Break; + j=loop(bp, 0,j,dx,cs,0,RI); + if(j>dx/4 && j<=i+dx/16) Break; // tall T + } + + MSG( fprintf(stderr,"7: ad= %d",ad); ) + if( loop(bp, 0,3*dy/8,dx,cs,0,RI) + <=loop(bp,dx-1,3*dy/8,dx,cs,0,LE)+dx/8 ) ad=ad*98/100; // l + MSG( fprintf(stderr,"7: ad= %d",ad); ) + if( num_cross(0,dx-1,dy/4,dy/4,bp,cs) == 1 + && loop(bp,0,dy/4,dx,cs,0,RI) < dx/2 ) ad=ad*96/100; // J + MSG( fprintf(stderr,"7: ad= %d",ad); ) + + if (box1->m3 && dym3-box1->m2) ad=99*ad/100; // too small + if (box1->m3 && 2*dym3-box1->m2) ad=96*ad/100; // too small + if (dy>3*dx) ad=99*ad/100; // ) + if ( gchar) ad=99*ad/100; // J + if (!hchar) ad=99*ad/100; + Setac(box1,(wchar_t)'7',ad); + break; + } + // --- test 8 --------------------------------------------------- + // last change: May15th,2000 JS + for(ad=d=100;dx>2 && dy>4;){ // or we need large height + DBG( char c_ask='8'; ) + if (sdata->holes.num != 2) Break; + if( num_cross(x0,x1,y0 +dy/4,y0 +dy/4,box1->p,cs) != 2 ) Break; // ~gr (glued) + if( num_cross(x0,x1,y1 -dy/4,y1 -dy/4,box1->p,cs) != 2 + && num_cross(x0,x1,y1-3*dy/8,y1-3*dy/8,box1->p,cs) != 2 ) Break; + if( get_bw(x0,x0+dx/4,y1-dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break; // ~9 + if( get_bw(x0,x0+dx/2,y0+dy/4,y0+dy/4,box1->p,cs,1) == 0 ) Break; + if( get_bw(x0+dx/2,x0+dx/2,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break; // ~0 +// MSG( printf(" x0 y0 %d %d\n",x0,y0); ) + for( i2=i1=x=0,i=y=y0+dy/3;y<=y1-dy/3;y++){ // check left middle nick + j=loop(box1->p,x0,y,dx,cs,0,RI); + if (j>x || (abs(j-x)<=dx/8 /* care about MICR E-13B font */ + && (i1=loop(box1->p,x0+j,y,dx,cs,1,RI))>dx/2)) { + if (j>x) x=j; i=y; if (i1>i2) i2=i1; } + } if(i>=y1-dy/3 || (xdx/2) Break; // no gB + if (x< dx/4) ad=99*ad/100; // no B + if (x<=dx/8) ad=98*ad/100; // no B + j = loop(box1->p,x1,y1- dy/4,dx,cs,0,LE); + if( j>loop(box1->p,x1,y1- dy/5,dx,cs,0,LE) + && j>loop(box1->p,x1,y1-2*dy/5,dx,cs,0,LE) ) Break; // & + // check for upper hole + for (j=0;jholes.num;j++) { + if (sdata->holes.hole[j].y1 < i-y0+1 ) break; + if (sdata->holes.hole[j].y1 < i-y0+dy/8) break; + } if (j==sdata->holes.num) Break; // not found + // if( num_hole(x0,x1,y0,i+1 ,box1->p,cs,NULL)!=1 ) + // if( num_hole(x0,x1,y0,i+dy/8,box1->p,cs,NULL)!=1 ) Break; // upper hole + // check for lower hole + for (j=0;jholes.num;j++) { + if (sdata->holes.hole[j].y0 > i-y0-1 ) break; + } if (j==sdata->holes.num) Break; // not found + // if( num_hole(x0,x1,i-1,y1,box1->p,cs,NULL)!=1 ) Break; + i1=i; // left middle nick + /* find the middle right nick */ + for( x=0,i2=i=y=y0+dy/3;y<=y1-dy/3;y++){ + j=loop(box1->p,x1,y,dx,cs,0,LE); if( j>=x ) i2=y; + /* we care also for 7-segment and unusual fonts */ + if (j>x || (abs(j-x)<=(dx+4)/8 + && loop(box1->p,x1-j,y,dx,cs,1,LE)>dx/2)){ + if (j>x) x=j; i=y; } + // MSG(fprintf(stderr," yjix %d %d %d %d %d %d",y-y0,j,i-y0,x,loop(box1->p,x1-j,y,dx,cs,1,LE),dx/2);) + } + if( i>y0+dy/2+dy/10 ) Break; + // if( xdx/2 ) Break; + MSG(fprintf(stderr,"center bar at y= %d %d x=%d+%d i1=%d",i-y0,i2-y0,x,j,i1);) + if( num_cross(x0,x1, i , i ,box1->p,cs) != 1 + && num_cross(x0,x1, i+1 , i+1 ,box1->p,cs) != 1 + && num_cross(x0,x1,(i+i2)/2,(i+i2)/2,box1->p,cs) != 1 ) Break; // no g + if(abs(i1-i)>(dy+5)/10) ad=99*ad/100; // y-distance right-left-nick + if(abs(i1-i)>(dy+4)/8) ad=99*ad/100; // y-distance right-left-nick + if(abs(i1-i)>(dy+2)/4) Break; + // ~B ff + for(i=dx,y=0;yi+dx/16 ) break; + } if( yi+dx/16 ) break; + } if( y16 && num_cross(0,dx-1,dy-1,dy-1,bp,cs) > 1 + && loop(bp,0,dy-1,dx,cs,0,RI) 2 ) i++; if( i>dy/8 ) break; + } if( y 1) ad=98*ad/100; // & + if (num_cross(dx-1,dx-1,dy/2,dy-1,bp,cs) > 1) ad=98*ad/100; // & + if (num_cross( 0,dx-1, 0, 0,bp,cs) > 1) ad=98*ad/100; + if (dy>15) + if (num_cross( 0,dx-1, 1, 1,bp,cs) > 1) ad=98*ad/100; + /* if m1..4 is unsure ignore hchar and gchar ~ga */ + if (!hchar) { + if ((box1->m2-box1->y0)*8>=dy) ad=98*ad/100; + else ad=99*ad/100; + } + if ( gchar + && (box1->y1-box1->m3)*8>=dy) ad=99*ad/100; + Setac(box1,(wchar_t)'8',ad); + break; + } + // --- test 9 \it g --------------------------------------------------- + /* + * lcd micr + * ooo ooo + * o o o o + * ooo ooo + * o o + * ooo o + */ + for(ad=d=100;dx>2 && dy>4;){ // dx>1 dy>2*dx + DBG( char c_ask='9'; ) + if (sdata->holes.num > 1) Break; + if( num_cross(x0+ dx/2,x0+ dx/2,y0,y1-dy/4,box1->p,cs) != 2 // pre select + && num_cross(x0+ dx/2,x0+ dx/2,y0, y1,box1->p,cs) != 3 // pre select + && num_cross(x0+3*dx/8,x0+3*dx/8,y0,y1,box1->p,cs) != 3 + && num_cross(x0+ dx/4,x1 -dx/4,y0,y1,box1->p,cs) != 3 ) Break; + if( num_cross(x0+ dx/2,x0 +dx/2,y0,y0+dy/4,box1->p,cs) < 1 ) Break; + if( num_cross(x0+ dx/2,x1, y0+dy/2 ,y0+dy/2,box1->p,cs) < 1 ) Break; + if( num_cross(x0,x1, y0+ dy/4 ,y0+ dy/4,box1->p,cs) != 2 + && num_cross(x0,x1, y0+3*dy/8 ,y0+3*dy/8,box1->p,cs) != 2 ) Break; + if( num_cross(x1-dx/8,x1,y0+dy/4,y0+dy/4,box1->p,cs) == 0) ad=ad*97/100; // ~4 + for( x=0,i=y=y0+dy/2;y<=y1-dy/4;y++){ // find notch (suche kerbe) + j=loop(box1->p,x0,y,dx,cs,0,RI); + if( j>x ) { x=j; i=y; } + } if (x<1 || xp,x0+x-1,y,dy/8+1,cs,0,DO)/2; y=i=y+j; + j=loop(box1->p,x0+x-1,y,dx/2 ,cs,0,RI); x+=j; + if (x5) + if( num_cross(x0+dx/2,x1,i,y1 ,box1->p,cs) != 1 /* fails on 5x8 */ + && num_cross(x0+dx/2,x1,i,y1-dy/8,box1->p,cs) != 1 ) Break; + if( num_cross(x0+dx/2,x0+dx/2,i,y1,box1->p,cs) > 1 ) Break; + if( num_cross(x0+dx/2,x1 ,i, i,box1->p,cs) != 1 ) Break; + + if (sdata->holes.num < 1) { /* happens for 5x7 font */ + if (dx<8) ad=98*ad/100; else Break; } + else { + if (sdata->holes.hole[0].y1 >= i+1) Break; + if (sdata->holes.hole[0].y0 > i-1) Break; + if (sdata->holes.num > 1) + if (sdata->holes.hole[1].y0 > i-1) Break; + // if( num_hole(x0,x1,y0,i+1,box1->p,cs,NULL)!=1 ) Break; + // if( num_hole(x0,x1,i-1,y1,box1->p,cs,NULL)!=0 ) Break; + } + if( loop(box1->p,x0,y1 ,dy,cs,0,RI)>dx/3 && + loop(box1->p,x0,y1-1,dy,cs,0,RI)>dx/3 + && (box1->m3==0 || (box1->m3!=0 && (!hchar || gchar)))) ad=98*ad/100; // no q OR ocr-a-9 + for( x=0,i=y=y0+dy/3;y<=y1-dy/3;y++){ // suche kerbe + j=loop(box1->p,x1,y,dx,cs,0,LE); + if( j>x ) { x=j; i=y; } + } if( x>dx/2 ) Break; // no g + i1=loop(bp,dx-1,dy/8 ,dx,cs,0,LE); if(i1>dx/2) Break; + i3=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE); + i2=loop(bp,dx-1,dy/2 ,dx,cs,0,LE); if(i1+i3-2*i2<-1-dx/16) Break; // konvex + i1=loop(bp,dx-1,dy/4 ,dx,cs,0,LE); if(i1>dx/2) Break; + i3=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE); + for(y=dy/4;y0){ + x--; // robust + y=loop(bp,dx-x-1, dy-1,dy,cs,0,UP); + if(ym3) { + if( gchar) ad=99*ad/100; /* unsure */ + if(!hchar) ad=99*ad/100; /* unsure */ + } else { if (ad==100) ad=99; } /* not 100% sure */ + Setac(box1,(wchar_t)'9',ad); + break; + } + // 0 is same as O !? + // --- test 0 (with one big hole in it ) ----------------------------- + for(d=ad=100;dx>2 && dy>3;){ // min 3x4 + DBG( char c_ask='0'; ) + if (sdata->holes.num > 1) Break; /* be tolerant */ + if( get_bw(x0 , x0+dx/3,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break; + if( get_bw(x1-dx/3 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break; + /* could be an O, unless we find a dot in the center */ + if( get_bw(x0 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 3 ) ad=99; + if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/3 , y1,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/3,box1->p,cs,1) != 1 ) Break; + /* accept 0 with dot in center, accept \/0 too ... */ + if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/3 , y1-dy/3,box1->p,cs,1) != 0 ) Break; + + if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) != 2 ) Break; + if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND + if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break; + if( num_cross(x0+dx/3,x1-dx/3,y1 , y1 ,box1->p,cs) != 1 ) // against "rauschen" + if( num_cross(x0+dx/3,x1-dx/3,y1-1 , y1-1 ,box1->p,cs) != 1 ) Break; + if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) + if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break; + if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) + if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break; + // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 1 ) Break; + if (sdata->holes.num != 1) Break; + + i= loop(bp,0 ,0 ,x1-x0,cs,0,RI)- + loop(bp,0 ,2 ,x1-x0,cs,0,RI); + if (i<0) Break; + if (i==0) { + if (loop(bp,dx-1,0 ,x1-x0,cs,0,LE)> + loop(bp,dx-1,2 ,x1-x0,cs,0,LE) ) ad=98*ad/100; + ad=99*ad/100; /* LCD-type? */ + } + + x=loop(bp,dx-1,dy-1-dy/3,x1-x0,cs,0,LE); // should be minimum + for (y=dy-1-dy/3;yx) x=i; + } + if( ydx/8 ) + if( loop(bp,0 , dy/16,dx,cs,0,RI)dx/8 ) + if( loop(bp,0 ,dy-1-dy/16,dx,cs,0,RI)p,cs,1) == 0 + && get_bw(x1-dx/32,x1,y1-dy/32,y1,box1->p,cs,1) == 0 + && ( get_bw(x0,x0+dx/32,y0,y0+dy/32,box1->p,cs,1) == 1 + || get_bw(x0,x0+dx/32,y1-dy/32,y1,box1->p,cs,1) == 1 ) ) { + if (dx<32) ad=ad*99/100; else Break; // ~D + } + + // search lowest inner white point + for(y=dy,j=x=0;x 1 ) ad=99*ad/100; // ~a \it a + + if (loop(bp, 0, 0,x1-x0,cs,0,RI)>=dx/8) { // round, notLCD + if (loop(bp,dx-1,dy-1,x1-x0,cs,0,LE)dy/8 + || num_cross(0,dx-1, 0, 0,bp,cs) > 1 + || num_cross(0,dx-1,dy-1,dy-1,bp,cs) > 1 + ) ad=98*ad/100; // ~bq + + if (box1->m3) { + if (!hchar) ad=98*ad/100; else // ~o + if ( gchar) ad=99*ad/100; // wrong line detection? + } else { if (ad==100) ad=99; } /* not 100% sure */ + if (ad>99) ad=99; /* we can never be sure having a O, + let context correction decide, see below! */ + Setac(box1,(wchar_t)'0',ad); + break; + } + // --- test 0 with a straight line in it ------------------- + for(ad=100;dx>4 && dy>5;){ /* v0.3.1+ */ + DBG( char c_ask='0'; ) + if (sdata->holes.num > 3) Break; /* be tolerant */ + if (sdata->holes.num < 1) Break; + if (sdata->holes.num != 2) ad=95*ad/100; + if( get_bw(x0 , x0+dx/2,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break; + if( get_bw(x1-dx/2 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/2 , y1,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break; + if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/3 , y1-dy/3,box1->p,cs,1) != 1 ) Break; + // out_x(box1); printf(" x0 y0 %d %d\n",x0,y0); + if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) != 3 ) Break; + if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND + if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break; + if( num_cross(x0+dx/3,x1-dx/3,y1 , y1 ,box1->p,cs) != 1 ) // against "rauschen" + if( num_cross(x0+dx/3,x1-dx/3,y1-1 , y1-1 ,box1->p,cs) != 1 ) Break; + if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) + if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break; + if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) + if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break; + // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 2 ) Break; + if (sdata->holes.num != 2) ad=85*ad/100; + + if( loop(bp,0 , 0,x1-x0,cs,0,RI)<= + loop(bp,0 , 2+dy/32,x1-x0,cs,0,RI) ) Break; + x= loop(bp,0 ,dy/2 ,x1-x0,cs,0,RI); + i= loop(bp,0 ,dy/2-1,x1-x0,cs,0,RI); if (i>x) x=i; + i= loop(bp,0 ,dy/2-2,x1-x0,cs,0,RI); if (i>x && dy>8) x=i; + if( loop(bp,0 , dy/4,x1-x0,cs,0,RI)x) x=i; + i= loop(bp,dx-1,dy/2-1,x1-x0,cs,0,LE); if(i>x && dy>8) x=i; + if( loop(bp,dx-1,3*dy/4,x1-x0,cs,0,LE)x) x=i; + } + if( ydy/4) Break; + y+=loop(bp,dx/2,dy-1-y,y1-y0,cs,1,UP); if(y>dy/3) Break; if (y>dy/4) ad=ad*99/100; + y+=loop(bp,dx/2,dy-1-y,y1-y0,cs,0,UP); if(3*y>2*dy) Break; + x =loop(bp,dx/2,dy-y,dx/2,cs,0,RI); if(x==0) Break; + // MM; fprintf(stderr," y=%d x=%d\n",y-1,x); + if( loop(bp,dx/2+x-1-dx/16,dy-y,y1-y0,cs,0,UP)==0 ) Break; + // $ + for(i=0,y=dy/4;y dx/4 + || loop(bp,dx-1,y,dx-1,cs,0,LE) > dx/4 ) break; + if( ydx/8 ) + if( loop(bp,0 , dy/16,dx,cs,0,RI)dx/8 ) + if( loop(bp,0 ,dy-1-dy/16,dx,cs,0,RI)p,cs,1) == 0 + && get_bw(x1-dx/32,x1,y1-dy/32,y1,box1->p,cs,1) == 0 + && ( get_bw(x0,x0+dx/32,y0,y0+dy/32,box1->p,cs,1) == 1 + || get_bw(x0,x0+dx/32,y1-dy/32,y1,box1->p,cs,1) == 1 ) ) Break; // ~D + + /* 5x9 font "9" is like "0" */ + if (dx<16) + if ( num_cross(x0,x0,y0,y1,box1->p,cs) != 1 ) ad=98*ad/100; + + // italic a + for(i=0,y=6*dy/8;y 2 ) i++; else i--; + if(i>0) ad=ad*98/100; // ~'a' \it a + if( !hchar ) ad=90*ad/100; + Setac(box1,(wchar_t)'0',ad); + break; + } + return box1->c; +}