/* Copyright (C) 2002 Giulio Lunati This is free software; you can redistribute it and/or modify it under the terms of the version 2 of the GNU General Public License as published by the Free Software Foundation. This software 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 software; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* preproc.c: Deskewing, balancing, thresholding routines. */ #define STAT 0 #include #include #include #include #include "common.h" #include "gui.h" #define MSG(args...) fprintf(stderr, ## args) #define CKP(M) fprintf(stderr,"[CKP %d OK!]\n",M) #define DIV(a,b) (((a)+abs(b)/((a)>0?2:-2))/(b)) #define MIN(A,B) ((A)<(B)?(A):(B)) #define MAX(A,B) ((A)>(B)?(A):(B)) #define TRIM(X,A,B) MIN(MAX((X),(A)),(B)) /* interpolation */ #define ITP(A,B,R) (1-R)*(A)+(R)*(float)(B) #define MAXVAL 255 /****************************** PIXMAP STUFF ******************************/ #define PIX(x,y) (pixmap+(x)+(y)*XRES) #define NPIX(p) ++(p) /* return interpolated pixel x,y: coordinates map: pointer to graymap X: x-width of map Y: y-width of map */ inline int PIXFI(float x, int y, unsigned char *map, int X, int Y) { int ix; unsigned char *p; x=TRIM(x,0,X-1); y=TRIM(y,0,Y-1); x-=(ix=floor(x)); p=map+ix+y*X; ix=rintf(ITP(*p,*(NPIX(p)),x)); return(ix); } /****************************** HISTOGRAM STUFF ******************************/ float h0[MAXVAL+1],h1[MAXVAL+1]; float H_dark,H_light,H_thr; float h_cnt,h_mean,h_var,h_dens; char *graf(float i, float min, float max, int wid) { static char c[200]; char *p; float f; f=(i-min)*wid/(max-min); for (p=c; f>0; f--, p++) *p='*'; *p = 0; return(c); } void h_print(float *h, int width) { int l,M; for (l=1,M=h[0]; l<=MAXVAL; l++) if (h[l]>M) M=h[l]; for (l=0; l<=MAXVAL; l++) if (h0[(int)l]!=0) printf("%4d %6.0f %s\n",(int)l,h0[(int)l],graf(h0[(int)l],0,M,70)); } /* smooth h0[] with radius d and contrast correction f; use h1[] aux buffer */ void h_smooth(int d, float f) { int i; float s; for (s=0,i=0; i<=d; i++) s+=h0[i]; for (i=0; i<=MAXVAL; i++) { h1[i]=s/(2*d+1); s+=(i+d+1<=MAXVAL? h0[i+d+1] : 0); s-=(i-d>=0? h0[i-d] :0); } for (i=0; i<=MAXVAL; i++) h0[i]=h1[i]; /* contrast correction for (i=0; i-d<0; i++) h0[i]=h1[i]-f*(2*h1[i]-h1[0]-h1[i+d+1]); for (; i+d+1<=MAXVAL; i++) h0[i]=h1[i]-f*(2*h1[i]-h1[i-d]-h1[i+d+1]); for (; i<=MAXVAL; i++) h0[i]=h1[i]-f*(2*h1[i]-h1[i-d]-h1[MAXVAL]); */ } int h_thr_stat() { int i,I; float m0,m1,m2,M0,M1,M2,s,S; for(i=0; i<=MAXVAL; i++) { h1[i]=log(1+h0[i]); } for(i=M0=M1=M2=0; i<=MAXVAL; i++) { M0+=h1[i]; M1+=h1[i]*i; M2+=h1[i]*i*i; } S =(M2-M1*M1/M0); for(i=I=m0=m1=m2=0; i<=MAXVAL; i++) { m0+=h1[i]; m1+=h1[i]*i; m2+=h1[i]*i*i; s =(m2-m1*m1/m0); s+=((M2-m2)-(M1-m1)*(M1-m1)/(M0-m0)); if (s0; i--) { if (h0[i]>1 && h0[i]>h0[i-1]) break; } H_light=i; for (i=0; i+1<=MAXVAL; i++) { if (h0[i]>1 && h0[i]>h0[i+1]) break; } H_dark=i; for (I=i=H_dark, M=h0[i]; i<=H_light; i++) { if (h0[i]=n*Delta) && dy >=1; dy*=0.618 ) { l= (N>0? s/N : -1); for (x=3*w/2; x+3*w/2(t=*PIX( (int)(x+c),(int)(y+p[i]) ))) m=t; for (i=c=0; c(t=*PIX( (int)(x-c),(int)(y-p[i]) ))) m=t; s += m; N++; } #define R 0.5 delta*=R; delta+=fabs(s/N-l); n*=R; n++; if (Delta <0 && l>=0) break; } return s/N; exit(0); #undef NP #undef R } float skew_calc(float Eps) { #define MaxSkew 0.2 #define R 0.618034 float x0,x1,y1,y0,D; D=0; x1=MaxSkew, x0=-x1; for ( x1=(x1-x0)*R+x0, y1=skew_score(x1,D), x0=(x1-x0)*R+x0, y0=skew_score(x0,D); fabs(x1-x0)>Eps; D=(pp_deskew_accurate? 0 : fabs(y1-y0)/30) ) { if (y0y1) x1=x0/R-x1*R, y1=skew_score(x1,D); else break; } return (x0+x1)/2; exit(0); #undef MaxSkew #undef R } void pp_shear_y(float f) { int D,x,y,s,x0,x1; float *m1,m0; unsigned char *p; int *d; s=abs((int)(f*(XRES-1))); if (s==0) return; s=s++/2; p= alloca(YRES); d= alloca(XRES*sizeof(d)); m1= alloca(XRES*sizeof(*m1)); D=XRES/2; for (x=0; x0) x0=XRES/2+1, x1=XRES; else x0=0, x1=XRES/2; for (y=0; y+s=s; y--) { for (x=x0; x=0; y--) for (x=x0; x, now rotating",f); st = 3; } else if (st == 3) { if (fabs(f)<0.1 && !pp_deskew_accurate) { /* fast: quasi-rotation */ a=0; b=f; c=-f; } else { /* exact rotation */ c=a = -(hypot(1,f)-1)/f; b = -2*a/(a*a+1); } pp_shear_x(a); pp_shear_y(b); pp_shear_x(c); show_hint(2,"DESKEW: finished"); st = 0; r = 0; } return(r); } /****************************** AUTOTHRESHOLD STUFF ******************************/ int pp_thresh() { int x,y; static int st; { if (pm_t != 8) return 128; show_hint(2,"computing threshold..."); st = 2; for (x=0; x<=MAXVAL; x++) h0[x]=0; for (y=0; y\n", H_dark, H_thr, H_light); */ return(H_thr); } } /****************************** BALANCE STUFF ******************************/ /* light icon */ int Dx,Dy,Iw,Ih,Rx,Ry; float M,Q,c; unsigned char *Icon; /* balance: convert the pixmap to b/n, based on local darkness */ void pre_balance() { /* counters */ int x,y,x0,x1,y0,y1,i,j,dx,dy; /* for linear regression */ float sn,st,sl,stt,sll,stl; /* for balancing */ float t,l; unsigned char *p; /* init linear regression */ sn=sl=st=sll=stt=stl=0; /* init icon */ /* steps for icon */ Ry=(LS+LH)*DENSITY/25.4; Rx=(LW*2)*DENSITY/25.4; /* initial corner for icon */ Dx=((XRES-1)%Rx)/2; Dy=((YRES-1)%Ry)/2; /* width and height of threshold map */ Iw=(XRES-1)/Rx+1; Ih=(YRES-1)/Ry+1; dx=Rx/40+1; dy=Ry/40+1; /* temp buffer for icon */ Icon=malloc(Iw*Ih); /* calculate icon */ for (y=0; y=XRES ? XRES : Dx+x*Rx+Rx); y1=(Dy+y*Ry+Ry>=YRES ? YRES : Dy+y*Ry+Ry); for (i=0; i<=MAXVAL; i++) h0[i]=0; for(j=y0; j<=y1; j+=dy) for(i=x0,p=PIX(x0,j); i<=x1; i+=dy,p+=2) h0[*p]++; h_split(); #if 0 if (x==0 && y==0) for (i=0;i=0) { t=MIN(0,dyy/2+dxx); v=MIN(MAXVAL,v-C*t); } } *q=v; } } return; } void test() { pp_thresh(); avoid_links(100); hqbin(); redraw_dw=1; } /* re-write pixmap in 1-bit format, double resolution (with intepolation) */ void hqbin() { int i,j,m,bpl; unsigned char *p1, *r1, *p2, *r2, *p3, *r3, /* for input on 3 rows */ *q1, *q2; /* for output on 2 rows*/ float d; q1=q2 = pixmap; r1=alloca(XRES+2); r2=alloca(XRES+2); r3=alloca(XRES+2); bpl = (XRES/4) + ((XRES%4) != 0); /* byte per line */ MC(r2,pixmap); MC(r3,pixmap); for (j=0; j>=1; d=(*p2*3+*(p2+1)+*p1)*3+*(p1+1); if (d< thresh_val*16) *q1 |= m; d=(*p2*3+*(p2+1)+*p3)*3+*(p3+1); if (d< thresh_val*16) *q2 |= m; if ((m>>=1) == 0) { m = 128; ++q1; ++q2; } } } pm_t=1; XRES*=2; YRES*=2; DENSITY *= 2; /* WARNING: should realloc the pixmap */ } #undef MC /************************ ANTI - DISTORSION STUFF ********************/ void adist(int x0, int x1) { int i,y; unsigned char *p; float A; A=(float)(x0-x1)/x0/x0; for (y=0; y=1? 30*log(h0[i]): 0); for (i=I=M=0; i<=MAXVAL; i++) if (h0[i]+i>M && h0[i]>0) I=i, M=h0[i]+i; H_light=I; for (i=I=0,M=-MAXVAL; i<=MAXVAL; i++) if (h0[i]-i>M && h0[i]>0) I=i, M=h0[i]-i; H_dark=I; #else for (i=I=M=0; i<=MAXVAL; i++) if (h0[i]>M) I=i, M=h0[i]; L=I; for (M=0,I=i=-L/2; L+i+i<=L; i++) if ((m=h0[L+i+i]-h0[L+i]) > M) M=m, I=i; I=L+I; if(I=0; i--) if (h0[i]>M) I=i, M=h0[i]; H_light=L; H_dark=I; } else { for (i=I, M=h0[i]; i<=MAXVAL; i++) if (h0[i]>M) I=i, M=h0[i]; H_light=I; H_dark=L; } #endif for (i=H_dark, M=h0[i]; im) m++; #endif #if STAT for (i=0; i<=MAXVAL; i++){ for (j=0; j<=MAXVAL; j++) s[i][j]=rintf(25*log(s[i][j])); } printf("P2\n256 256 %d\n",(int)rintf(25*log(m))); for (i=0; i<=MAXVAL; i++){ for (j=0; j<=MAXVAL; j++) printf("%d ",s[i][j]); printf("\n"); } #endif /******* END TRASHED ******/ #endif