验证码识别

/*

**********************************
  验证码识别 v2.0   By:feiyue
**********************************

为了解决:http://www.123shipin.com/register.php

使用说明:先按F1选择验证码范围,然后F4识别,先自动生成字库

*/


#NoEnv
#SingleInstance Force
SetBatchLines, -1
CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetTitleMatchMode, 2
SetWorkingDir, %A_ScriptDir%
IniRead, wt, a.ini, 0, wt, %A_Space%
IniRead, pos, a.ini, 0, pos, %A_Space%

okzhi:=10      ;//阀值设置非常关键,学习取10,使用取25

Return


Esc::      ;//Esc为重启脚本热键
IfWinExist, %A_ScriptName% ahk_class Notepad
{
  PostMessage, 0x111, 3
  Sleep, 500
}
Reload
Return


Pause::Pause      ;//暂停脚本热键,用于调试


F2::Run, Notepad.exe %A_ScriptName%      ;//编辑脚本热键


F1::      ;//选择验证码的范围的启动热键,用鼠标选择
Gui,9: Destroy
Gui,9: +LastFound +AlwaysOnTop
WinSet, Transparent, 10
Gui,9: -Caption +ToolWindow +E0x08000000
Gui,9: Show, NA x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%
;-----------------------------
Gui,8: Destroy
Gui,8: +LastFound +AlwaysOnTop
WinSet, Transparent, 100
Gui,8: -Caption +ToolWindow +E0x08000000
Gui,8: Color, Red
down=0
Loop {
  Sleep, 50
  MouseGetPos, x, y
  if (down=0)
  {
    ToolTip, 按住鼠标左键选择范围!`n取消请按【Ctrl】键
    if GetKeyState("LButton","P")
      down:=1, x1:=x, y1:=y
    if GetKeyState("Ctrl","P")
      Break
  }
  else
  {
    ToolTip, 松开鼠标左键确定范围!
    w:=Abs(x-x1), h:=Abs(y-y1)
    x:=x1nW-1 or top>nH-1 or rightnW-1)
    right:=nW-1
  if (topnH-1)
    end:=nH-1
  width:=right-left+1, height:=end-top+1

  if !DllCall("GetModuleHandle", "str", "gdiplus")
    DllCall("LoadLibrary", "str", "gdiplus")
  VarSetCapacity(si, 16, 0), si := Chr(1)
  DllCall("gdiplusGdiplusStartup", "uintP", pToken, "uint", &si, "uint", 0)

  mDC := DllCall("CreateCompatibleDC", "uint", 0)
  NumPut(VarSetCapacity(bi, 40, 0), bi)
  NumPut(nW, bi, 4)
  NumPut(nH, bi, 8)
  NumPut(32, NumPut(1, bi, 12, "UShort"), 0, "Ushort")
  NumPut(0,  bi,16)
  hBuffer := DllCall("gdi32CreateDIBSection", "uint", mDC
  , "uint", &bi, "uint", 0, "uintP", pBits, "uint", 0, "uint", 0)

  oldObject := DllCall("SelectObject", "uint", mDC, "uint", hBuffer)
  screenDC := DllCall("GetDC", "uint", 0)
  DllCall("gdi32BitBlt", "uint", mDC, "int", 0, "int", 0, "int", nW
  , "int", nH, "uint", screenDC, "int", 0, "int", 0, "uint", 0x00CC0020)
  DllCall("ReleaseDC", "uint", 0, "uint", screenDC)

  DllCall("gdiplusGdipCreateBitmapFromHBITMAP"
  , "uint", hBuffer, "uint", 0, "uintP", pBitmap)

  DllCall("SelectObject", "uint", mDC, "uint", oldObject)
  DllCall("DeleteObject", "uint", hBuffer)
  DllCall("DeleteDC", "uint", screenDC)
  DllCall("DeleteDC", "uint", mDC)

  VarSetCapacity(Rect, 16)
  NumPut(0, Rect, 0, "uint")
  NumPut(0, Rect, 4, "uint")
  NumPut(nW, Rect, 8, "uint")
  NumPut(nH, Rect, 12, "uint")

  VarSetCapacity(BitmapData, 21, 0)
  DllCall("GdiplusGdipBitmapLockBits", "uint", pBitmap
  , "uint", &Rect, "uint", 3, "int", 0x26200a, "uint", &BitmapData)
  Stride:=NumGet(BitmapData, 8)
  Scan0:=NumGet(BitmapData, 16)

  ;//生成图像的灰度数组
  arr:=[]
  Loop, %width%
    arr[A_Index]:=[]
  j:=stride-width*4
  i:=top*stride+left*4-4-j
  Loop, %height% {
    y:=A_Index, i+=j
    Loop, %width%
      c:=NumGet(Scan0+0,i+=4)
      , arr[A_Index][y]:=((c>>16&0xFF)*299
        +(c>>8&0xFF)*587+(c&0xFF)*114)//1000
  }

  DllCall("gdiplusGdipBitmapUnlockBits", "uint", pBitmap, "uint", &BitmapData)
  DllCall("gdiplusGdipDisposeImage", "uint", pBitmap)

  DllCall("gdiplusGdiplusShutdown", "uint", pToken)
  if (hModule:=DllCall("GetModuleHandle", "str", "gdiplus"))
    DllCall("FreeLibrary", "uint", hModule)
  Return, arr    ;//返回数组
}


YanZhengMa(x1,y1,x2,y2,okzhi=10000,zishu=4)
{
  cc:=getc(x1,y1,x2,y2,nW,nH)  ;//首先得到图像的灰度数组

;//准备好GUI窗口用于查看归一化效果
k:=(zishu+1)//2
IfWinExist, 查看归一化效果
  Gui, Show, NA
else
{
  Gui, +LastFoundExist
  IfWinExist
    Gui, Destroy
  Gui, +AlwaysOnTop
  Loop, % k*2 {
    j:=Mod(A_Index,k)=1 ? "xm":"x+15"
    Gui, Add, Edit, %j% w150 r17
  }
  x:=A_ScreenWidth-(150+15)*k-15+3
  Gui, Show, NA y0 x%x%, 查看归一化效果
}

;;【第一步】,采用Ostu法二值化,并初步过滤椒盐噪点

;//生成灰度统计直方图,趁机过滤椒盐噪点(与周围八点都有色差)
pp:=[], SeCha:=50    ;//色差阀值越小过滤越多
Loop, 256
  pp[A_Index-1]:=0
Loop, %nH% {
  j:=A_Index
  Loop, %nW% {
    i:=A_Index, c:=cc[i][j]
    Loop {
      if (i=1 or j=1 or i=nW or j=nH)
        Break
      if Abs(c-cc[i-1][j])fmax)
    fmax:=sb, ek:=k
}
;//利用阀值将图像数组二值化为黑白图像
Loop, %nH% {
  j:=A_Index
  Loop, %nW%    ;//如果是黑底白字,这改为0:1进行反色
    cc[A_Index][j]:=cc[A_Index][j]aa[i][j-1])
      a:=aa[i][j-1]
    else
    {
      if (cc[i-1][j-1]=1 and a>aa[i-1][j-1])
        a:=aa[i-1][j-1]
      if (cc[i+1][j-1]=1 and a>aa[i+1][j-1])
        a:=aa[i+1][j-1]
    }
    if (cc[i+1][j]=1)
    {
      aa[i][j]:=a
      Continue
    }
    ;//达到一条线段的最右边,就开始向左生成连通等价关系表
    Loop, %i% {
      if (cc[i][j]=0)
        Break
      ;//用不含等号记录新连通域的一个起始标记
      if !RegExMatch(ks,"[-=]" a "[-=]")
        ks.=a "-"
      aa[i][j]:=a, a2:=aa[i][j-1]
      if (cc[i][j-1]=1 and aa2)
       and !InStr(ks,"-" a "=" a2 "-")
        ks.=a "=" a2 "-"
      else
      {
        a1:=aa[i-1][j-1], a3:=aa[i+1][j-1]
        if (cc[i-1][j-1]=1 and aa1)
         and !InStr(ks,"-" a "=" a1 "-")
          ks.=a "=" a1 "-"
        if (cc[i+1][j-1]=1 and aa3)
         and !InStr(ks,"-" a "=" a3 "-")
        ks.=a "=" a3 "-"
      }
      i--
    }
  }
}
;//整理连通等价关系表
zs:="-", num:=0, Stack:=[]  ;//用数组模拟堆栈
Loop, Parse, ks, -
{
  v:=A_LoopField
  if (v="") or InStr(v,"=") or InStr(zs,"-" v ">")
    Continue
  ;//初始的 v 代表新连通域的一个起始标记
  s:="-" v "-", ds:=ks, num++    ;//连通域总共找到了num个
  Loop {
    re1=-(d+)=%v%-
    re2=-%v%=(d+)-
    if RegExMatch(ds,re1,r) or RegExMatch(ds,re2,r)
    {
      if !InStr(s,"-" r1 "-")
        s.=r1 "-", Stack.Insert(r1)
      StringReplace, ds, ds, %r%, -, All
    }
    else if Stack.MaxIndex()
      v:=Stack.Remove()
    else Break     ;//循环直到堆栈为空,s可防止重复入栈
  }
  Sort, s, U D-
  s:=Trim(s,"-")
  Loop, Parse, s, -
    zs.=A_LoopField ">" num "-"
}
;//整理连通域标记,并统计连通域的点数直方图
pN:=[]
Loop, %num%
  pN[A_Index]:=0
Loop, %nH% {
  j:=A_Index
  Loop, %nW% {
    i:=A_Index
    if RegExMatch(zs,"-" aa[i][j] ">(d+)-",r)
      aa[i][j]:=r1, pN[r1]++
    else aa[i][j]:=0
  }
}
zs:="-"
Loop, %num%
  if (pN[A_Index]>=3)  ;//连通域分析可以过滤部分噪点
    zs.=A_Index "-"


;;【第四步】,两种方法自适应分割数字

ss:=wenzi:="", liantongmode:=0, wz_index:=ii:=0
Loop {
  if (++ii>nW)
  {
    ;//竖直分割的份数小于参数zishu时自动换到连通域分割
    if (wz_index=20)
  {
    wz_index++   ;//已处理文字数加一
    wz_%wz_index%:=ss    ;//保存每个字的字符串数据
    wz_%wz_index%_w:=zW  ;//保存每个字的宽度作为合并的依据
  }
  ;//如果是连通域分割,清理当前的连通域
  if (liantongmode=1)
  {
    StringReplace, zs, zs, -%wenzi%-, -
    wenzi:="", ii:=0
  }
  ss=    ;//清空为下一个字做准备
}

;//竖直分割的份数大于参数zishu时,考虑合并被切为两半的数字
if (wz_index>zishu and liantongmode=0)
{
  w:=0
  Loop, %wz_index%
    w+=wz_%A_index%_w  ;//得到所有宽度之和
  w:=Round(w/zishu)        ;//得到字的平均宽度
  Loop, %wz_index% {
    k:=A_Index, i:=k-1, j:=k+1
    if (wz_%k%_wzW)
{
  ;//使宽度和高度相等,缩放图像不致变形
  k1:=(zH-zW)//2, k2:=zH-zW-k1, zW:=zH
  t1:=t2:=""
  Loop, %k1%
    t1.="0"
  Loop, %k2%
    t2.="0"
  s:=SubStr(ts,1,-1), ts:=""
  Loop, Parse, s, `n
    ts.=t1 . A_LoopField . t2 . "`n"
}
s:=RegExReplace(ts,"n")
gc:=[], fx:=zW/16, fy:=zH/16
Loop, 16 {
  i:=A_Index, gc[i]:=[]
  Loop, 16 {
    j:=A_Index, x:=i*fx, y:=j*fy
    m:=x-Floor(x), n:=y-Floor(y)
    x:=Floor(x), y:=Floor(y)
    ;// l:左;u:上;r:右;d:下
    lu:=(x=0 or y=0) ? 0:SubStr(s,(y-1)*zW+x,1)
    ld:=(x=0 or y=zH) ? 0:SubStr(s,y*zW+x,1)
    ru:=(x=zW or y=0) ? 0:SubStr(s,(y-1)*zW+x+1,1)
    rd:=(x=zW or y=zH) ? 0:SubStr(s,y*zW+x+1,1)
    pix:=(1-m)*(1-n)*lu+(1-m)*n*ld+m*(1-n)*ru+m*n*rd
    gc[i][j]:=( pix>0.33 ) ? 1:0    ;//这个阀值也可取0.5
  }
}

;//生成16*16=256长度的加权特征数组
mb:=[], k:=0
Loop, 16 {
  j:=A_Index
  Loop, 16 {
    i:=A_Index, m:=0
    m+=gc[i-1][j-1]
    m+=gc[i][j-1]
    m+=gc[i+1][j-1]
    m+=gc[i-1][j]
    m+=gc[i][j]
    m+=gc[i+1][j]
    m+=gc[i-1][j+1]
    m+=gc[i][j+1]
    m+=gc[i+1][j+1]
    mb[++k]:=m
  }
}

;;//与字库中的模板比较,得到差距最小的
small:=1000000, wz:=""
Loop, read, 字库.txt
{
  v:=A_LoopReadLine
  IfNotInString, v, =, Continue
  StringSplit, r, v, =
  n1:=n2:=n3:=0    ;//允许每个模板左右平移一次来匹配
  Loop, Parse, r2
  {
    i:=A_Index, k:=A_LoopField
    n1+=Abs(k-mb[i])1        ;//模板左移一位
      n2+=Abs(k-mb[i-1])0        ;//模板右移一位
      n3+=Abs(k-mb[i+1])small and n2>small and n3>small)
      Break
  }
  n1:=n1"")
      cs.=v "`n`n"
  }
  cs.=k
  FileDelete, 字库.txt
  FileAppend, %cs%, 字库.txt
}
  Return, result
}


;//程序结束

验证码识别

/*

**********************************
  验证码识别 v2.0   By:feiyue
**********************************

为了解决:http://www.123shipin.com/register.php

使用说明:先按F1选择验证码范围,然后F4识别,先自动生成字库

*/


#NoEnv
#SingleInstance Force
SetBatchLines, -1
CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetTitleMatchMode, 2
SetWorkingDir, %A_ScriptDir%
IniRead, wt, a.ini, 0, wt, %A_Space%
IniRead, pos, a.ini, 0, pos, %A_Space%

okzhi:=10      ;//阀值设置非常关键,学习取10,使用取25

Return


Esc::      ;//Esc为重启脚本热键
IfWinExist, %A_ScriptName% ahk_class Notepad
{
  PostMessage, 0x111, 3
  Sleep, 500
}
Reload
Return


Pause::Pause      ;//暂停脚本热键,用于调试


F2::Run, Notepad.exe %A_ScriptName%      ;//编辑脚本热键


F1::      ;//选择验证码的范围的启动热键,用鼠标选择
Gui,9: Destroy
Gui,9: +LastFound +AlwaysOnTop
WinSet, Transparent, 10
Gui,9: -Caption +ToolWindow +E0x08000000
Gui,9: Show, NA x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%
;-----------------------------
Gui,8: Destroy
Gui,8: +LastFound +AlwaysOnTop
WinSet, Transparent, 100
Gui,8: -Caption +ToolWindow +E0x08000000
Gui,8: Color, Red
down=0
Loop {
  Sleep, 50
  MouseGetPos, x, y
  if (down=0)
  {
    ToolTip, 按住鼠标左键选择范围!`n取消请按【Ctrl】键
    if GetKeyState("LButton","P")
      down:=1, x1:=x, y1:=y
    if GetKeyState("Ctrl","P")
      Break
  }
  else
  {
    ToolTip, 松开鼠标左键确定范围!
    w:=Abs(x-x1), h:=Abs(y-y1)
    x:=x1nW-1 or top>nH-1 or rightnW-1)
    right:=nW-1
  if (topnH-1)
    end:=nH-1
  width:=right-left+1, height:=end-top+1

  if !DllCall("GetModuleHandle", "str", "gdiplus")
    DllCall("LoadLibrary", "str", "gdiplus")
  VarSetCapacity(si, 16, 0), si := Chr(1)
  DllCall("gdiplusGdiplusStartup", "uintP", pToken, "uint", &si, "uint", 0)

  mDC := DllCall("CreateCompatibleDC", "uint", 0)
  NumPut(VarSetCapacity(bi, 40, 0), bi)
  NumPut(nW, bi, 4)
  NumPut(nH, bi, 8)
  NumPut(32, NumPut(1, bi, 12, "UShort"), 0, "Ushort")
  NumPut(0,  bi,16)
  hBuffer := DllCall("gdi32CreateDIBSection", "uint", mDC
  , "uint", &bi, "uint", 0, "uintP", pBits, "uint", 0, "uint", 0)

  oldObject := DllCall("SelectObject", "uint", mDC, "uint", hBuffer)
  screenDC := DllCall("GetDC", "uint", 0)
  DllCall("gdi32BitBlt", "uint", mDC, "int", 0, "int", 0, "int", nW
  , "int", nH, "uint", screenDC, "int", 0, "int", 0, "uint", 0x00CC0020)
  DllCall("ReleaseDC", "uint", 0, "uint", screenDC)

  DllCall("gdiplusGdipCreateBitmapFromHBITMAP"
  , "uint", hBuffer, "uint", 0, "uintP", pBitmap)

  DllCall("SelectObject", "uint", mDC, "uint", oldObject)
  DllCall("DeleteObject", "uint", hBuffer)
  DllCall("DeleteDC", "uint", screenDC)
  DllCall("DeleteDC", "uint", mDC)

  VarSetCapacity(Rect, 16)
  NumPut(0, Rect, 0, "uint")
  NumPut(0, Rect, 4, "uint")
  NumPut(nW, Rect, 8, "uint")
  NumPut(nH, Rect, 12, "uint")

  VarSetCapacity(BitmapData, 21, 0)
  DllCall("GdiplusGdipBitmapLockBits", "uint", pBitmap
  , "uint", &Rect, "uint", 3, "int", 0x26200a, "uint", &BitmapData)
  Stride:=NumGet(BitmapData, 8)
  Scan0:=NumGet(BitmapData, 16)

  ;//生成图像的灰度数组
  arr:=[]
  Loop, %width%
    arr[A_Index]:=[]
  j:=stride-width*4
  i:=top*stride+left*4-4-j
  Loop, %height% {
    y:=A_Index, i+=j
    Loop, %width%
      c:=NumGet(Scan0+0,i+=4)
      , arr[A_Index][y]:=((c>>16&0xFF)*299
        +(c>>8&0xFF)*587+(c&0xFF)*114)//1000
  }

  DllCall("gdiplusGdipBitmapUnlockBits", "uint", pBitmap, "uint", &BitmapData)
  DllCall("gdiplusGdipDisposeImage", "uint", pBitmap)

  DllCall("gdiplusGdiplusShutdown", "uint", pToken)
  if (hModule:=DllCall("GetModuleHandle", "str", "gdiplus"))
    DllCall("FreeLibrary", "uint", hModule)
  Return, arr    ;//返回数组
}


YanZhengMa(x1,y1,x2,y2,okzhi=10000,zishu=4)
{
  cc:=getc(x1,y1,x2,y2,nW,nH)  ;//首先得到图像的灰度数组

;//准备好GUI窗口用于查看归一化效果
k:=(zishu+1)//2
IfWinExist, 查看归一化效果
  Gui, Show, NA
else
{
  Gui, +LastFoundExist
  IfWinExist
    Gui, Destroy
  Gui, +AlwaysOnTop
  Loop, % k*2 {
    j:=Mod(A_Index,k)=1 ? "xm":"x+15"
    Gui, Add, Edit, %j% w150 r17
  }
  x:=A_ScreenWidth-(150+15)*k-15+3
  Gui, Show, NA y0 x%x%, 查看归一化效果
}

;;【第一步】,采用Ostu法二值化,并初步过滤椒盐噪点

;//生成灰度统计直方图,趁机过滤椒盐噪点(与周围八点都有色差)
pp:=[], SeCha:=50    ;//色差阀值越小过滤越多
Loop, 256
  pp[A_Index-1]:=0
Loop, %nH% {
  j:=A_Index
  Loop, %nW% {
    i:=A_Index, c:=cc[i][j]
    Loop {
      if (i=1 or j=1 or i=nW or j=nH)
        Break
      if Abs(c-cc[i-1][j])fmax)
    fmax:=sb, ek:=k
}
;//利用阀值将图像数组二值化为黑白图像
Loop, %nH% {
  j:=A_Index
  Loop, %nW%    ;//如果是黑底白字,这改为0:1进行反色
    cc[A_Index][j]:=cc[A_Index][j]aa[i][j-1])
      a:=aa[i][j-1]
    else
    {
      if (cc[i-1][j-1]=1 and a>aa[i-1][j-1])
        a:=aa[i-1][j-1]
      if (cc[i+1][j-1]=1 and a>aa[i+1][j-1])
        a:=aa[i+1][j-1]
    }
    if (cc[i+1][j]=1)
    {
      aa[i][j]:=a
      Continue
    }
    ;//达到一条线段的最右边,就开始向左生成连通等价关系表
    Loop, %i% {
      if (cc[i][j]=0)
        Break
      ;//用不含等号记录新连通域的一个起始标记
      if !RegExMatch(ks,"[-=]" a "[-=]")
        ks.=a "-"
      aa[i][j]:=a, a2:=aa[i][j-1]
      if (cc[i][j-1]=1 and aa2)
       and !InStr(ks,"-" a "=" a2 "-")
        ks.=a "=" a2 "-"
      else
      {
        a1:=aa[i-1][j-1], a3:=aa[i+1][j-1]
        if (cc[i-1][j-1]=1 and aa1)
         and !InStr(ks,"-" a "=" a1 "-")
          ks.=a "=" a1 "-"
        if (cc[i+1][j-1]=1 and aa3)
         and !InStr(ks,"-" a "=" a3 "-")
        ks.=a "=" a3 "-"
      }
      i--
    }
  }
}
;//整理连通等价关系表
zs:="-", num:=0, Stack:=[]  ;//用数组模拟堆栈
Loop, Parse, ks, -
{
  v:=A_LoopField
  if (v="") or InStr(v,"=") or InStr(zs,"-" v ">")
    Continue
  ;//初始的 v 代表新连通域的一个起始标记
  s:="-" v "-", ds:=ks, num++    ;//连通域总共找到了num个
  Loop {
    re1=-(d+)=%v%-
    re2=-%v%=(d+)-
    if RegExMatch(ds,re1,r) or RegExMatch(ds,re2,r)
    {
      if !InStr(s,"-" r1 "-")
        s.=r1 "-", Stack.Insert(r1)
      StringReplace, ds, ds, %r%, -, All
    }
    else if Stack.MaxIndex()
      v:=Stack.Remove()
    else Break     ;//循环直到堆栈为空,s可防止重复入栈
  }
  Sort, s, U D-
  s:=Trim(s,"-")
  Loop, Parse, s, -
    zs.=A_LoopField ">" num "-"
}
;//整理连通域标记,并统计连通域的点数直方图
pN:=[]
Loop, %num%
  pN[A_Index]:=0
Loop, %nH% {
  j:=A_Index
  Loop, %nW% {
    i:=A_Index
    if RegExMatch(zs,"-" aa[i][j] ">(d+)-",r)
      aa[i][j]:=r1, pN[r1]++
    else aa[i][j]:=0
  }
}
zs:="-"
Loop, %num%
  if (pN[A_Index]>=3)  ;//连通域分析可以过滤部分噪点
    zs.=A_Index "-"


;;【第四步】,两种方法自适应分割数字

ss:=wenzi:="", liantongmode:=0, wz_index:=ii:=0
Loop {
  if (++ii>nW)
  {
    ;//竖直分割的份数小于参数zishu时自动换到连通域分割
    if (wz_index=20)
  {
    wz_index++   ;//已处理文字数加一
    wz_%wz_index%:=ss    ;//保存每个字的字符串数据
    wz_%wz_index%_w:=zW  ;//保存每个字的宽度作为合并的依据
  }
  ;//如果是连通域分割,清理当前的连通域
  if (liantongmode=1)
  {
    StringReplace, zs, zs, -%wenzi%-, -
    wenzi:="", ii:=0
  }
  ss=    ;//清空为下一个字做准备
}

;//竖直分割的份数大于参数zishu时,考虑合并被切为两半的数字
if (wz_index>zishu and liantongmode=0)
{
  w:=0
  Loop, %wz_index%
    w+=wz_%A_index%_w  ;//得到所有宽度之和
  w:=Round(w/zishu)        ;//得到字的平均宽度
  Loop, %wz_index% {
    k:=A_Index, i:=k-1, j:=k+1
    if (wz_%k%_wzW)
{
  ;//使宽度和高度相等,缩放图像不致变形
  k1:=(zH-zW)//2, k2:=zH-zW-k1, zW:=zH
  t1:=t2:=""
  Loop, %k1%
    t1.="0"
  Loop, %k2%
    t2.="0"
  s:=SubStr(ts,1,-1), ts:=""
  Loop, Parse, s, `n
    ts.=t1 . A_LoopField . t2 . "`n"
}
s:=RegExReplace(ts,"n")
gc:=[], fx:=zW/16, fy:=zH/16
Loop, 16 {
  i:=A_Index, gc[i]:=[]
  Loop, 16 {
    j:=A_Index, x:=i*fx, y:=j*fy
    m:=x-Floor(x), n:=y-Floor(y)
    x:=Floor(x), y:=Floor(y)
    ;// l:左;u:上;r:右;d:下
    lu:=(x=0 or y=0) ? 0:SubStr(s,(y-1)*zW+x,1)
    ld:=(x=0 or y=zH) ? 0:SubStr(s,y*zW+x,1)
    ru:=(x=zW or y=0) ? 0:SubStr(s,(y-1)*zW+x+1,1)
    rd:=(x=zW or y=zH) ? 0:SubStr(s,y*zW+x+1,1)
    pix:=(1-m)*(1-n)*lu+(1-m)*n*ld+m*(1-n)*ru+m*n*rd
    gc[i][j]:=( pix>0.33 ) ? 1:0    ;//这个阀值也可取0.5
  }
}

;//生成16*16=256长度的加权特征数组
mb:=[], k:=0
Loop, 16 {
  j:=A_Index
  Loop, 16 {
    i:=A_Index, m:=0
    m+=gc[i-1][j-1]
    m+=gc[i][j-1]
    m+=gc[i+1][j-1]
    m+=gc[i-1][j]
    m+=gc[i][j]
    m+=gc[i+1][j]
    m+=gc[i-1][j+1]
    m+=gc[i][j+1]
    m+=gc[i+1][j+1]
    mb[++k]:=m
  }
}

;;//与字库中的模板比较,得到差距最小的
small:=1000000, wz:=""
Loop, read, 字库.txt
{
  v:=A_LoopReadLine
  IfNotInString, v, =, Continue
  StringSplit, r, v, =
  n1:=n2:=n3:=0    ;//允许每个模板左右平移一次来匹配
  Loop, Parse, r2
  {
    i:=A_Index, k:=A_LoopField
    n1+=Abs(k-mb[i])1        ;//模板左移一位
      n2+=Abs(k-mb[i-1])0        ;//模板右移一位
      n3+=Abs(k-mb[i+1])small and n2>small and n3>small)
      Break
  }
  n1:=n1"")
      cs.=v "`n`n"
  }
  cs.=k
  FileDelete, 字库.txt
  FileAppend, %cs%, 字库.txt
}
  Return, result
}


;//程序结束

给TA捐赠
共{{data.count}}人
人已捐赠
其他教程

远端JSON快速菜单[类网吧菜单]

2020-3-9 6:00:44

其他案例

浮岛拼图|将window键盘的CTRL,WIN,ALT改为mac键盘布局

2020-3-11 22:59:16

个人中心
购物车
优惠劵
有新私信 私信列表
搜索