中华农历论坛知识讨论区历法知识 → 校准你的万年历


  共有33041人关注过本帖树形打印

主题:校准你的万年历

帅哥哟,离线,有人找我吗?
xjw01
  11楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:蝙蝠侠 帖子:866 积分:3804 威望:3 精华:20 注册:2008/3/20 22:14:00
  发帖心情 Post By:2008/12/30 20:00:00

那个是针对《三千五百年历日天象》专用的,而且对bmp图片大小有严格要求,对大家没有用处的。

算法原理如下:

用window做一个《三千五百年历日天象》的标准字形库,字形取自《三千五百年历日天象》,含用30几个汉字(农历用的那些汉字),再读取《三千五百年历日天象》bmp文件,取出每个汉字,并与字形库比对,找出它与字库中相似度最高的汉字,如果相似度不达标则打上一个“?”。

 

以下是其中一个比较简单的版本:


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部
帅哥哟,离线,有人找我吗?
xjw01
  12楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:蝙蝠侠 帖子:866 积分:3804 威望:3 精华:20 注册:2008/3/20 22:14:00
  发帖心情 Post By:2008/12/30 20:03:00

//---------------------------------------------------------------------------

#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="完成";
}
//---------------------------------------------------------------------------

 


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部
帅哥哟,离线,有人找我吗?
知鹿苑
  13楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:新手上路 帖子:3 积分:234 威望:0 精华:0 注册:2008/12/29 14:42:00
  发帖心情 Post By:2009/1/2 17:45:00

辛苦了!


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部
帅哥哟,离线,有人找我吗?
YS0290
  14楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:新手上路 帖子:2 积分:192 威望:0 精华:0 注册:2011/10/17 11:13:00
  发帖心情 Post By:2011/10/17 12:48:00

有没有用于php的代码哦……

支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部
帅哥哟,离线,有人找我吗?
战庄
  15楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:新手上路 帖子:2 积分:202 威望:0 精华:0 注册:2011/11/18 0:50:00
  发帖心情 Post By:2011/11/18 21:44:00

好好学习了------

支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部
总数 15 上一页 1 2

返回版面帖子列表

校准你的万年历








签名