-- 作者:xjw01
--
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; char colorA(int c){//颜色判断 int r,g,b; r=c&255; g=(c>>8)&255; b=(c>>16)&255; int f=r; if(f<g) f=g; if(f<b) f=b; if (f*3-r-g-b<100){ if(r+g+b<150*3) return 1; return 0; } //黑白判断 if(r>190&&g<30&&b<30) return 2; //红 if(r<30&&g>190&&b<30) return 3; //绿 if(r<30&&g<30&&b>190) return 4; //蓝 return 0; } void imgDxDy(char *b,char *r,int dx,int dy){ //文字图像微移 int i,j,k,x2,y2; for(i=0;i<18;i++) for(j=0;j<18;j++){ k=i*18+j; x2=j+dx; y2=i+dy; if(y2<0||y2>=18||x2<0||x2>=18) {r[k]=0; continue;} r[k]=b[y2*18+x2]; } } int imgIs1(char *p,int k){ //图片p中的k位附近是否为黑 int m, x=k%18,y=k/18, x2,y2, dx,dy; for(m=0;m<9;m++){ dx=m/3; if(dx>1) dx-=3; dy=m%3; if(dy>1) dy-=3; x2=x+dx; y2=y+dy; if(y2<0||y2>=18||x2<0||x2>=18) continue; if(p[y2*18+x2]==1) return 1; } return 0; } int imgX(char *b,char *z,int sz=0){ //相似度计算,数字或字母应置sz=1; int i,m,c,dx,dy; int v1,v2,v3,v1n,v2n,v3n; int M=0,C; char h[324]; for(m=0;m<25;m++){ dx=m/5; if(dx>2) dx-=4; dy=m%5; if(dy>2) dy-=4; imgDxDy(z,h,dx,dy); v1=v2=v3=v1n=v2n=v3n=0; for(i=0;i<324;i++){ if(sz&&i%18>11) continue; if(h[i]==1){ v1n++; if(b[i]==1) v1++; } //黑色部分的相似计算 if(h[i]==2){ v2n++; if(b[i]==0) v2++; } //白色部分的相似计算 if(h[i]==3){ if(b[i]==0) v1-=4; } //必须为黑的部分处理 if(h[i]==4){ if(b[i]==1) v2-=4; } //必须为白的部分处理 if(b[i]==1){ v3n++; if(imgIs1(h,i)==1) v3++; } //字形相似计算 } if(!v1n) v1n=1; if(!v2n) v2n=1; if(!v3n) v3n=1; C=100.0*v1/v1n+100.0*v2/v2n+100.0*v3/v3n+0.5; if(C>M) M=C; if(C>290&&!sz) break; } return M; } char Z[30][324],Z_isload=0; AnsiString strZ0="01234567891"; AnsiString strZ1="甲乙丙丁戊己庚辛壬癸正"; void loadZ(){ //截入标准文字库 if(Z_isload) return; Z_isload=1; TImage *im=new TImage(NULL); im->Picture->LoadFromFile("moB.bmp"); int w=im->Picture->Width; w=w/19.0+0.5; if(w>30) w=30; int i,j,k,c; for(k=0;k<w;k++) for(i=0;i<324;i++){ c=im->Canvas->Pixels[i%18+k*19][i/18]; Z[k][i]=colorA(c); } delete im; } AnsiString imgToA(char *buf,int retOne=0){ //图片转为文字 loadZ(); int i,v,vr,Max=0,k=-1,sz=1; //判断是否为数字 for(i=0,v=0,vr=0;i<324;i++){ if(!buf[i]) continue; if(i%18>11) sz=0; if(i%18>8) vr++; v++; } if(vr>15) sz=0; if(v<6) return "空"; if(retOne) return "有"; //图像比对 if(sz){ for(i=0;i<11;i++){ v=imgX(buf,Z[i],1); if(v>Max) Max=v,k=i; } }else{ for(i=11;i<22;i++){ v=imgX(buf,Z[i],0); if(v>Max) Max=v,k=i; if(v>290) break; } } //转为字串 AnsiString c=""; if(k<=10) c=strZ0.SubString(k+1,1); else c=strZ1.SubString((k-11)*2+1,2); if(Max<270||sz&&Max<290) c="?"+c; return c; } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
} //--------------------------------------------------------------------------- class lunImg{ public: int x0,y0; //文字起始坐标 double sx,sy; //图片的歪斜角 double Dx,Dy; //字宽,字高 TImage *im; lunImg(){ im=new TImage(NULL); } ~lunImg() { delete im;} void getRedXY(int x1,int y1,int x2,int y2,int *rx,int *ry){ //取红点的位置 int i,j,c; for(i=x1;i<x2;i++) for(j=y1;j<y2;j++){ c=im->Canvas->Pixels[i][j]; if( colorA(c)==2 ) {*rx=i,*ry=j;return;} } *rx=*ry=0; } void load(AnsiString fname){//载入图片 im->Picture->LoadFromFile(fname); const w0=1068,h0=1593; //右下点的理想坐标 int i,c,w2,h2; int x1,y1,x2,y2; getRedXY(0,0,50,50,&x0,&y0); if(!x0){ShowMessage("未找到左上标"); return;} getRedXY(x0+1066,y0-15,x0+1086,y0+15,&x1,&y1); if(!x1){ShowMessage("未找到右上标"); return;} getRedXY(x0+1060,y0+1420,x0+1100,y0+1570,&x2,&y2); if(!x2){ShowMessage("未找到右下标"); return;} sx = 1.0*(x2-x1-3)/(y2-y1); //水平线的斜率 sy = 1.0*(y1-y0)/(x1-x0); //竖直线的斜率 Dx=(x1-x0-3)/53.0; //字宽 c=(y2-y1-58)/28.4+0.5; Dy=1.0*(y2-y1-58)/int((y2-y1-58)/28.4+0.5); //行高 } void TZxy(int &x,int &y){//调整x,y int i,j,d; for(i=0;i<5;i++){ d=i; if(i>2) d=2-i; for(j=0;j<18;j++) if( colorA(im->Canvas->Pixels[x+j][y+d])==1 ) break; if(j==18){ y+=d; break; } } for(i=0;i<5;i++){ d=i; if(i>2) d=2-i; for(j=0;j<18;j++) if( colorA(im->Canvas->Pixels[x+d][y+j])==1 ) break; if(j==18){ x+=d; break; } } } AnsiString getA(double row,double col,int wn=-1,int retOne=0){ //取图片中的文字,wn为字宽(最大为60) //取指定的文字 int hz=0; //hz=1读汉字 if(wn==-1) wn=20,hz=1; //确定x,y char buf[28*60]={0},b[324]; double w,h; int i,j,x,y,c; w = col*Dx + 0.5 -3; h = row*Dy + 60.5 -3; x = x0+w + sx*h; y = y0+h + sy*w; if(y>im->Picture->Height-28) return "err"; TZxy(x,y);//调整x,y //到图片 for(i=0;i<28;i++) for(j=0;j<wn;j++){ c=im->Canvas->Pixels[x+j][y+i]; buf[i*wn+j]=colorA(c); } //去除上方及左边的空白区 int bx,by; for(i=0;i<14*wn;i++) if(buf[i]) break; by=i/wn; for(i=0;i<28*wn;i++) if(buf[i%28*wn+i/28]) break; bx=i/28; for(i=0;i<28*wn;i++){ int y=i/wn,x=i%wn; int x2=x+bx,y2=y+by; if(x2>=wn||y2>=28) buf[i]=0; else buf[i]=buf[y2*wn+x2]; } //转换中文 if(hz){ for(i=0;i<324;i++) b[i]=buf[i/18*wn+i%18]; return imgToA(b,retOne); } int g[8]={0},gn=1; //g为各字的开始与结束所在列 for(i=1;i<wn;i++){ for(j=0;j<18;j++) if(buf[j*wn+i]) break; if(gn%2==1&&(j==18||i-g[gn-1]==11)) g[gn++]=i; if(gn%2==0&&j!=18) g[gn++]=i; if(gn>=8) break; } AnsiString r; if(gn%2==1) g[gn++]=wn; for(i=0;i<gn-1;i++){ int offs=g[i],w=g[i+1]-offs,k; if(i%2==1){ if(w>5&&gn<=6) r+="_"; continue; } //数据间距较大时视为空格 for(j=0;j<324;j++) b[j]=0; for(j=0;j<18;j++) for(k=0;k<w;k++) b[j*18+k]=buf[j*wn+k+offs]; r+=imgToA(b); } return r; } /*void show(char *b){ int i,c; for(i=0;i<324;i++){ if(b[i]) c=1; else c=0xFFFFFF; Form1->im2->Canvas->Pixels[i%18][i/18]=c; } }*/ }R; AnsiString bmpToTxt(AnsiString fname){ if(!FileExists(fname+".bmp")){ ShowMessage(fname+".bmp 找不到"); return ""; } R.load(fname+".bmp"); int i,k,rrn,rn; AnsiString s,c,c2,c3,c4,c5; for(k=0;k<19*3;k+=19) for(i=0,rrn=0,rn=0;i<56;i++){ c2=c3=""; c=R.getA(i,0+k,-1,1); if(c=="err") break; if(c=="空"){ c2=R.getA(i,12+k); if(c2=="空") { //新的一年开始或到了页底 if(rrn) break; else { rrn++,rn=0,i++; } } else s+=" "+c2; continue; } if(!rn) s+="\r\n年份"+R.getA(i-1,12.5+k,50); //节气 c=" "+R.getA(i,12+k); c2=R.getA(++i,12+k); if(c2!="空") c+=" "+c2; s+="\r\n"+c; rn++; } int fp = FileCreate("B"+fname+".txt"); FileWrite(fp,s.c_str(),s.Length()); FileClose(fp); return s; } void __fastcall TForm1::Button1Click(TObject *Sender) { int n=StrToInt(Edit2->Text); if(n<1||n>800) { ShowMessage("个数不要超过800或小于1"); return; } AnsiString c; for(int i=0;i<n;i++){ c=StrToInt(Edit1->Text)+1000+i; c=c.SubString(2,3); StatusBar1->SimpleText="正在转换"+c+".bmp"; Memo1->Text=bmpToTxt(c); } StatusBar1->SimpleText="完成"; } //---------------------------------------------------------------------------
|