WindowsAPI調用和OCR圖片識別


WindowsAPI在每一台Windows系統上開放標准API供開發人員調用.

          功能齊全.在這里只介紹三個部分.

                    1.利用API控制鼠標鍵盤.

                             2.對外部程序的讀寫和監聽

                                        3.對外部程序窗口的改動.

                                                     外部程序的意思就是.假設我的程序是360.辣么我能控制騰訊QQ客戶端啥的.

 

const int MOUSEEVENTF_MOVE = 0x0001; // 移動鼠標 
const int MOUSEEVENTF_LEFTDOWN = 0x0002; //模仿鼠標左鍵按下
const int MOUSEEVENTF_LEFTUP = 0x0004; //模仿鼠標左鍵抬起 
const int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模仿鼠標右鍵按下 
const int MOUSEEVENTF_RIGHTUP = 0x0010; //模仿鼠標右鍵抬起
const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;// 模仿鼠標中鍵按下 
const int MOUSEEVENTF_MIDDLEUP = 0x0040;// 模仿鼠標中鍵抬起 
const int MOUSEEVENTF_ABSOLUTE = 0x8000; //標示是否采取絕對坐標 
private const int WM_SETTEXT = 0x000C;
const int BM_CLICK = 0xF5;//鼠標點擊事件
const int WM_GETTEXT = 0xd;//獲取文本
const int WM_CLOSE = 0x0010;//關閉窗口

 

 

調用時程序會在Bin下尋找同名DLL.如果沒有會在C:\Windows\System32中尋找同名DLL.

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool BlockInput([In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt);

 

//BlockInput(true)鎖定鼠標鍵盤.BlockInput(false)激活鼠標鍵盤.鎖定時需要Thread.Sleep(500)才能生效

//如果在鎖定鼠標鍵盤后死機..可以用CTRL + ALT +DELETE 激活鼠標鍵盤.聽說用IO讀出任務管理器可以使CTRL + ALT +DELETE 無效

 

[DllImport("user32")]
public extern static void SetCursorPos(int x, int y);

 

 

//移動鼠標到指定坐標

 

[DllImport("user32")]
public static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);

 

//鼠標的點擊事件

SetCursorPos(X, Y);//移動鼠標
mouse_event((int)(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE), 0, 0, 0, IntPtr.Zero);//摁下
SetCursorPos(X, Y);//移動鼠標
mouse_event((int)(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE), 0, 0, 0, IntPtr.Zero);//放開

 

//移動鼠標到指定位置然后拖拽到指定位置

SetCursorPos(X, Y);//移動鼠標

mouse_event((int)(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP), 0, 0, 0, IntPtr.Zero);//摁下

mouse_event((int)(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP), 0, 0, 0, IntPtr.Zero);//摁下

 

//移動鼠標到指定位置左鍵雙擊

c#提供封裝的對象可以控制鍵盤

SendKeys.Send("1111高");//發送字符串
SendKeys.SendWait("{^c }");//發送鍵盤按鍵.組合鍵

 

API中有keybd_event函數.Win IO等也可以控制鍵盤.但是本人沒有找到使用組合鍵的方法..

對剪切板的操作

 

 IDataObject iData = Clipboard.GetDataObject();

  var a = (String)iData.GetData(DataFormats.Text);

 

//讀

 Clipboard.SetDataObject("1高G");

 

//寫

  var g = Graphics.GetImage();

 

//讀取剪切板里的圖片

對外部程序的讀寫:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr Hwnd, int Msg, int wpala, string lpala);

 private const int WM_SETTEXT = 0x000C;//定義寫的宏

 private  const int WM_GETTEXT = 0xd;//定義讀的宏

  public static int WM_CLICK = 0x00F5;//定義點擊的宏

public  const int BM_CLICK = 0xF5;//鼠標點擊事件

 

//可以對外部程序的控件做讀寫.按鈕點擊.窗口關閉等

SendMessage(new IntPtr(“句柄”), WM_SETTEXT, 0,“數據”);

 

//寫

StringBuilder code = new StringBuilder(1024);

SendMessage(new IntPtr(“句柄”), WM_GETTEXT, 1024, code);

 

//讀

 SendMessage(“句柄”,WM_CLOSE,0,null);

 

//關閉窗口

SendMessage(new IntPtr(“句柄”), BM_CLICK, 0, 0);

 

//按鈕的點擊

 

在Windows系統下。每生成一個控件或者窗口都會出現一個句柄.是本對象的唯一標識符.可以通過坐標抓取.也可以用SPY++和INSPECT捕獲句柄.稍后講

下面是監聽外部程序按鈕點擊的源碼.是我哭着鬧着求着微軟的大牛給我寫的一個案例.不要問我是怎么寫的.我只會抄.如果有興趣可以自行搜索全局鈎子.HOOK.以下案例是微軟的大牛用MSAA技術做的鈎子

 

 

const uint WINEVENT_INCONTEXT = 0x0004;
const uint EVENT_MIN = 0x00000001;
const uint EVENT_MAX = 0x7FFFFFFF;
const uint EVENT_OBJECT_INVOKED = 0x8013;
const uint EVENT_OBJECT_STATECHANGE = 0x800A;
const uint ROLE_SYSTEM_PUSHBUTTON = 43;
const uint ROLE_SYSTEM_WINDOW = 10;
const int STATE_SYSTE_PRESSED = 0X00000008;
const int STATE_SYSTE_FOCUSED = 0X00000004;

 

[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(
uint eventMin,
uint eventMax,
IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc,
uint idProcess,
uint idThread,
uint dwFlags);

delegate void WinEventDelegate(
IntPtr hWinEventHook,
uint eventType,
IntPtr hwnd,
int idObject,
int idChild,
uint dwEventThread,
uint dwmsEventTime);

[DllImport("Oleacc.dll")]
static extern uint AccessibleObjectFromEvent(IntPtr hwnd, int dwObjectID, int dwChildID, out IAccessible ppacc, [MarshalAs(UnmanagedType.Struct)] out object pvarChild);

private void WinEventCallback(
IntPtr hWinEventHook,
uint eventType,
IntPtr hwnd,
int idObject,
int idChild,
uint dwEventThread,
uint dwmsEventTime)
{
if (eventType == EVENT_OBJECT_STATECHANGE)
{
IAccessible accObj = null;
object o = null;
AccessibleObjectFromEvent(hwnd, idObject, idChild, out accObj, out o);

int state;
if (accObj != null &&
accObj.accRole.ToString().Equals(ROLE_SYSTEM_PUSHBUTTON.ToString()) &&
accObj.accName == txtButtonName.Text.Trim() &&
int.TryParse(accObj.accState.ToString(), out state))
{
if ((state & STATE_SYSTE_PRESSED) == STATE_SYSTE_PRESSED &&
FindParentWindow(accObj, txtFormName.Text.Trim()))
{

txtOutput.AppendText(string.Format("{0}: {1} clicked.\r\n", DateTime.Now.ToShortTimeString(), accObj.accName));
}
}
}

}

bool FindParent(IAccessible acc, string parentName)
{
if (acc == null)
{
return false;
}

int maxRetry = 5;
int count = 0;
IAccessible cur = acc.accParent as IAccessible;
while (cur != null && count < maxRetry)
{
if (parentName.Equals(cur.accName.ToString())&&
cur.accRole.ToString().Equals(ROLE_SYSTEM_WINDOW.ToString()))
{
return true;
}

cur = cur.accParent as IAccessible;

count++;
}

return false;
}

bool FindParentWindow(IAccessible acc, string parentName)
{
if (acc == null)
{
return false;
}

int count = 0;
IAccessible cur = acc.accParent as IAccessible;
while (cur != null)
{
if (cur.accRole.ToString().Equals(ROLE_SYSTEM_WINDOW.ToString()))
{
if (parentName.Equals(cur.accName.ToString()))
{
return true;
}
else
{
return false;
}
}

cur = cur.accParent as IAccessible;

count++;
}

return false;
}

 

以上都是C底層的設計.啥都不能改.有性趣可以自行搜索IAccessible  

 

private void button1_Click(object sender, EventArgs e)
{
//先獲取Process
string targetProcessName = txtProcessName.Text.Trim();
if (!string.IsNullOrEmpty(targetProcessName))
{
Process targetProcess = Process.GetProcessesByName(targetProcessName).First();

if (targetProcess != null)
{
//IAccessible acc = 
IntPtr result = SetWinEventHook(EVENT_MIN, EVENT_MAX, IntPtr.Zero,
new WinEventDelegate(WinEventCallback), (uint)targetProcess.Id, 0, 0);
Console.WriteLine(result);
}
}
}

 

這些是我唯一看懂的源碼.targetProcessName是掛鈎的進程名稱.targetProcessName是掛鈎的程序按鈕.

如果調用這個方法.就可以監聽外部程序的按鈕.如果目標點擊.就會觸發我們的事件.txtOutput文本會記錄事件.

 

以下講窗口的改動和句柄的捕獲.

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 

//第一個參數填NULL,第二個參數填窗口標題可以捕獲該窗口的句柄

 

[DllImport("user32.dll")]
private static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);

 

public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

 

 

 

 

//第一個參數窗口句柄.聲明Rect傳進去就會返回窗口的Rect

[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]
public static extern int WindowFromPoint(
int xPoint,
int yPoint
);

 

//傳遞XY就會返回坐標處的句柄

 

對於窗口的改動用API很蛋疼.步驟是先正常化窗口.然后設置活動窗口.最后置頂.由於是用代碼置頂.所以最后還要手動取消置頂

 

[DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

 

 

//第一個填窗口句柄.后面填函數識別的整數

//     //最大化3 最小化2 正常化1

[DllImport("user32.dll", EntryPoint = "SetForegroundWindow", SetLastError = true)]
private static extern void SetForegroundWindow(IntPtr hwnd);

 

//第一個填窗口句柄.

//設置活動窗口是必須的.不要問我為什么.

 

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int Width, int Height, int flags);

 

SetWindowPos(“句柄”, -1, 0, 0, 0, 0, 1 | 2);

SetWindowPos(“句柄”, -2, 0, 0, 0, 0, 1 | 2);

 

//-1置頂.-2取消置頂

以上就是API.多了也懶得講

public Bitmap GetScreenSnapshot(int x, int y, int wid, int hei)//截圖
{
Rectangle rectangle = new Rectangle(x, y, wid, hei);
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(rectangle.X, rectangle.Y, 0, 0, rectangle.Size, CopyPixelOperation.SourceCopy);
}
return bitmap;
}

 

做圖片識別先做截圖.傳遞TOP.LEFT.WIDTH.HEIGHT利用以上方法完成區域截圖。

                  以一串數字為例。

                         截圖切割成一個一個數字

                                當時吧.認為自己對圖片識別底層有一定了解.然后自己重寫了一套OCR.

                                               萬萬沒想到在WIN 10上識別率過低.

                                                           最后老老實實的用了網上的框架.

AspriseOCR.dll.

DevIL.dll

ILU.dll

private string OCRPrise(string imgfile,string width, string height)
{
String gcstr = Marshal.PtrToStringAnsi(OCRpart(@"" + imgfile, -1, 0, 0,Convert.ToInt32( width),Convert.ToInt32( height)));
gcstr = gcstr.Replace('O', '0');
gcstr = gcstr.Replace('o', '0');
gcstr = gcstr.Replace('Z', '2');
gcstr = gcstr.Replace('z', '2');
gcstr = gcstr.Replace('L', '1');
gcstr = gcstr.Replace('l', '1');
gcstr = gcstr.Replace('I', '1');
gcstr = gcstr.Replace('i', '1');

gcstr = gcstr.Replace('T', '7');
gcstr = gcstr.Replace('t', '7');

gcstr = gcstr.Replace('G', '9');
gcstr = gcstr.Replace('g', '9');

gcstr = gcstr.Replace('S', '5');
gcstr = gcstr.Replace('s', '5');

gcstr = gcstr.Replace('J', '2');
gcstr = gcstr.Replace('j', '2');

gcstr = gcstr.Replace(',', '.');


gcstr = gcstr.Replace("(P1C)", "");

gcstr = gcstr.Replace("-", "");

gcstr = gcstr.Replace("'", "");
string result = null;

for (int i = 0; i < gcstr.Length; i++)
{
if (!String.IsNullOrWhiteSpace(gcstr[i].ToString()))
{
result += gcstr[i];
}
}
return result;
}

 

以上就可以識別數字.在XP Win 7 Win10下識別率和兼容性還不錯

以下講我認知的OCR. 比如目前要識別一張黑紙白字的圖片中的數字 每一張圖片都可以被解析成數據 數據中會存放圖片的每一個像素和它對應的XY以及RGB 比如要識別白字.黑色像素的RGB是000.那么我們去除黑色像素的數據.保留白色像素的特征.相對坐標和像素值作為標准特征. 下一次在識別白字黑紙的圖片就在輪回一邊. 要注意數字的切割和與標准特征的對比. 一張圖片有上千個像素.在底層進行處理時算法的工作量非常大.如果能做到快速和高效.重寫的OCR就算成功. 僅僅提供一個思路和經驗.如果要做企業級應用.建議使用百度.阿里.微軟的圖片識別接口

 index 寫1就行.StaffData.OCRXY就是配置文件的Value.此案例只支持數字識別.

  private string OCRDiscern(int index)//圖片識別
        {
            var frist = StaffData.OCRXY.Where(a1 => a1.Key == "1600*900").FirstOrDefault().Value.Split(new char[] { '!'});
         

            int xystate = 0;//確定一個數字范圍.輪回一次
            List<int> startx = new List<int>();
            List<int> endx = new List<int>();
            Service.WindowsAPIService.Rect lpRect = new Service.WindowsAPIService.Rect();
            //IntPtr hwnds = FindWindow(null, "上海增值稅專用發票開具");
            GetWindowRect(HeWindows.Value, ref lpRect);
            List<int> divisionx = new List<int>();
            List<int> divisiony = new List<int>();
            WindowsAPI.APISetWindowPos(HeWindows.Value, -1, 0, 0, 0, 0, 1 | 2);
            WindowsAPI.APIShowWindow(HeWindows.Value, 1);
            WindowsAPI.APISetForegroundWindow(HeWindows.Value);

            #region 截圖


            #region
            // GC ADD
            Thread.Sleep(2000);
            var ocrdata = frist[index].Split(new char[] { '|'});
           // OCR.GetScreenSnapshot(lpRect.Left + Convert.ToInt32(ocrdata[0]), lpRect.Top + Convert.ToInt32(ocrdata[1]), Convert.ToInt32(ocrdata[2]), Convert.ToInt32(ocrdata[3])).Save(@"" + AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "g" + index, ImageFormat.Bmp);
            OCR.GetScreenSnapshot(lpRect.Left + Convert.ToInt32(ocrdata[0]), lpRect.Top + Convert.ToInt32(ocrdata[1]),100,15).Save(@"" + AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "g"+index, ImageFormat.Bmp); 
            Bitmap bmp = OCR.GetScreenSnapshot(lpRect.Left + Convert.ToInt32(ocrdata[0]), lpRect.Top + Convert.ToInt32(ocrdata[1]), Convert.ToInt32(ocrdata[2]), Convert.ToInt32(ocrdata[3]));
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
            IntPtr ptr = bmpData.Scan0;

            int bytes = bmpData.Stride * bmp.Height;
            byte[] rgbValues = new byte[bytes];

            Marshal.Copy(ptr, rgbValues, 0, bytes);

            byte red = 0;
            byte green = 0;
            byte blue = 0;

            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    //See the link above for an explanation 
                    //of this calculation
                    int position = (y * bmpData.Stride) + (x * Image.GetPixelFormatSize(bmpData.PixelFormat) / 8);
                    blue = rgbValues[position];
                    green = rgbValues[position + 1];
                    red = rgbValues[position + 2];
                    //Console.WriteLine("Fast: " + red + " "
                    //                   + green + " " + blue);
                    if (red == 128 && green == 0 && blue == 0)
                    {
                        divisionx.Add(x);
                        divisiony.Add(y);
                        break;
                    }
                }
            }
            bmp.UnlockBits(bmpData);


            //END GC ADD

            #endregion

            #region 獲取指定像素做截圖范圍
            //var ocrdata = frist[3].Split(new char[] { '|'});
            //hdc = GetDC(IntPtr.Zero);
            //for (int i = lpRect.Left + Convert.ToInt32( ocrdata[0]); i <= lpRect.Left + Convert.ToInt32(ocrdata[0]) + Convert.ToInt32(ocrdata[2]); i++)
            //{
            //    for (int a1 = lpRect.Top + Convert.ToInt32(ocrdata[1]); a1 < lpRect.Top + Convert.ToInt32(ocrdata[1]) + Convert.ToInt32(ocrdata[3]); a1++)
            //    {
            //        Color color = GetColor(i, a1);
            //        if (color.R == 128 && color.G == 0 && color.B == 0)
            //        {
            //            divisionx.Add(i);
            //            divisiony.Add(a1);
            //            break;
            //        }

            //    }

            //}
            //ReleaseDC(IntPtr.Zero, hdc);


            #endregion

            if (divisionx.Count > 0)
            {
                #region 刪除小數點
                for (int ic = 0; ic < divisionx.Count; ic++)
                {
                    if (ic <= divisionx.Count - 2)
                    {
                        if (ic == 0)
                        {
                            if (divisionx[ic] + 1 != divisionx[ic + 1])
                            {
                                divisionx.Remove(divisionx[ic]);
                                break;
                            }
                        }
                        else
                        {
                            if (divisionx[ic] + 1 != divisionx[ic + 1] && divisionx[ic] - 1 != divisionx[ic - 1])
                            {
                                divisionx.Remove(divisionx[ic]);
                                break;
                            }
                        }
                    }
                }
                #endregion

                #region 分割

                for (int i = 0; i < divisionx.Count; i++)
                {
                    if (i <= divisionx.Count - 2)
                    {
                        if (xystate == 0 && divisionx[i] + 1 == divisionx[i + 1])
                        {
                            xystate = 1;
                            startx.Add(divisionx[i]);
                            //MessageBox.Show(startx.ToString());
                        }
                        if (divisionx[i] + 1 != divisionx[i + 1] && xystate == 1)
                        {
                            xystate = 0;
                            endx.Add(divisionx[i]);
                            // MessageBox.Show(endx.ToString());//末尾數字無法確定像素范圍.單獨計算
                        }
                    }
                }
                #endregion

                #region 添加末尾指定像素

                int max = -1;
                int test;
                for (int i = 0; i < divisionx.Count; i++)
                {
                    if (i <= divisionx.Count - 2)
                    {
                        max = (divisionx[i] > divisionx[i + 1] ? test = divisionx[i] : test = divisionx[i + 1]) > max ?
                              (divisionx[i] > divisionx[i + 1] ? max = divisionx[i] : max = divisionx[i + 1]) : max;

                    }

                }

                #endregion

                endx.Add(max);
            }
            #region 獲取TOP像素

            int maxy = -1;
            int testy;
            for (int i = 0; i < divisiony.Count; i++)
            {
                if (i <= divisiony.Count - 2)
                {
                    if (maxy == -1)
                    {
                        maxy = (divisiony[i] > divisiony[i + 1] ? testy = divisiony[i + 1] : testy = divisiony[i]);
                    }
                    else
                    {
                        maxy = (divisiony[i] > divisiony[i + 1] ? testy = divisiony[i + 1] : testy = divisiony[i]) < maxy ?
                               (divisiony[i] > divisiony[i + 1] ? testy = divisiony[i + 1] : testy = divisiony[i]) : maxy;
                    }

                }

            }

            #endregion

            #region 獲取Buttom像素

            int buttommax = -1;
            int buttomtest;
            for (int i = 0; i < divisiony.Count; i++)
            {
                if (i <= divisiony.Count - 2)
                {
                    buttommax = (divisiony[i] > divisiony[i + 1] ? buttomtest = divisiony[i] : buttomtest = divisiony[i + 1]) > buttommax ?
                                (divisiony[i] > divisiony[i + 1] ? buttomtest = divisiony[i] : buttomtest = divisiony[i + 1]) : buttommax;

                }

            }

            #endregion

            #region 截圖
            int screenx;
            int screeny;
            int screenWidth;
            int screenHeight;
            if (startx.Count == endx.Count)
            {
                for (int i = 0; i < startx.Count; i++)
                {
                    screenx = startx[i];
                    screeny = maxy;
                    screenWidth = endx[i] - startx[i] + 2;
                    screenHeight = buttommax - maxy + 2;
                    //OCR.GetScreenSnapshot(screenx, screeny, screenWidth, screenHeight).Save(@"" + AppDomain.CurrentDomain.SetupInformation.ApplicationBase + i + ".bmp", ImageFormat.Bmp);
                    Image img = Image.FromHbitmap(bmp.GetHbitmap());
                    Bitmap newbmp = new Bitmap(screenWidth, screenHeight, PixelFormat.Format32bppArgb);

                    using (Graphics g = Graphics.FromImage(newbmp))
                    {
                        //Rectangle origReg = new Rectangle(0, 0, bmp.Width, bmp.Height);
                        //Rectangle destReg = new Rectangle(screenx, screeny, screenWidth, screenHeight);
                        g.DrawImage(img, 0, 0, new Rectangle(screenx, screeny, screenWidth, screenHeight), GraphicsUnit.Pixel);
                    }
                   
                    newbmp.Save(@"" + AppDomain.CurrentDomain.SetupInformation.ApplicationBase + i + ".bmp", ImageFormat.Bmp);

                }

            }
            else
            {
                MessageBox.Show("圖片識別失敗");
            }
            #endregion
            #endregion

            WindowsAPI.APISetWindowPos(HeWindows.Value, -2, 0, 0, 0, 0, 1 | 2);
            // WindowsAPI.APIShowWindow(WindowsAPI.APIFindWindow(null, "票據預覽"),1);

            #region 對比
            #region 讀取圖片
            string finallydata = null;
            List<string> ocr = FileIO.BitmapSean();
            List<string> value = new List<string>();
            KeyValuePair<string, string> dicdata = new KeyValuePair<string, string>();

            if (ocr.Count > 0)//圖片
            {
                if (StaffData.OCRData.Count > 0)//模板
                {
                    for (int g = 0; g < ocr.Count; g++)
                    {


                        for (int i = 0; i <= 9; i++)
                        {
                            value.Clear();
                            dicdata = StaffData.OCRData.Where(a => a.Key== i.ToString()).FirstOrDefault();//模板的數據

                            string[] ocrtest = dicdata.Value.Split(new char[] { '!' });

                            if (ocrtest.Count() > 0)
                            {

                                for (int a = 0; a < ocrtest.Count(); a++)
                                {
                                    value.Add(ocrtest[a]);//dic轉list
                                }

                                if (value.Count > 0)//匹配
                                {
                                    string resultocr = OCR.TestOCRProperty(gaulxy: value, gaulFile: ocr[g], gaulKey: StaffData.OCRData.Where(a => a.Key == i.ToString()).FirstOrDefault().Key.ToString());//圖片識別
                                    if (resultocr != "-1")
                                    {
                                        finallydata += resultocr;
                                        break;

                                    }


                                }
                            }
                        }
                    }
                    if (!String.IsNullOrWhiteSpace(finallydata))
                    {

                        string last1 = finallydata[finallydata.Count() - 1].ToString();
                        string last2 = finallydata[finallydata.Count() - 2].ToString();
                        finallydata = finallydata.Substring(0, finallydata.Count() - 2);
                        finallydata = finallydata + "." + last2 + last1;


                    }
                   // MessageBox.Show(finallydata);
                }

            }
            #endregion

            #region 刪除圖片
            //List<string> imgdata = FileIO.BitmapSean();
            //if (imgdata.Count > 0)
            //{
            //    for (int img = 0; img < imgdata.Count; img++)
            //    {
            //        if (File.Exists(imgdata[img]))
            //        {
            //            File.Delete(imgdata[img]);
            //        }
            //    }
            //}
            #endregion

            #endregion

            return finallydata;
            

            
        }
     public string TestOCRProperty(List<string> gaulxy, string gaulFile, string gaulKey)//圖片識別
        {
            using (Bitmap bt = new Bitmap(@"" + gaulFile))
            {
                List<string> goal = new List<string>();//目標圖片坐標
                List<string> read = gaulxy;//Read(@"C:\Users\Administrator\Desktop\XY\相對坐標\0相對坐標.txt");//標准坐標
                                           // Bitmap bt = new Bitmap(@""+ gaulFile);
                var data = GetImagePixel(bt);

                for (int i = 0; i < data.Count; i++)
                {
                    if (i != data.Count - 1)
                    {
                        string[] data1 = data[i].Split(new char[] { '|' });
                        string[] data2 = data[i + 1].Split(new char[] { '|' });
                        int a = Convert.ToInt32(data2[0]) - Convert.ToInt32(data1[0]);
                        int b = Convert.ToInt32(data2[1]) - Convert.ToInt32(data1[1]);
                        goal.Add(a + "|" + b);
                    }
                    else
                    {
                        string[] data2 = data[0].Split(new char[] { '|' });
                        string[] data1 = data[data.Count - 1].Split(new char[] { '|' });
                        int a = Convert.ToInt32(data2[0]) - Convert.ToInt32(data1[0]);
                        int b = Convert.ToInt32(data2[1]) - Convert.ToInt32(data1[1]);
                        goal.Add(a + "|" + b);
                    }


                }

                List<int> Equals = new List<int>();
                int result = -1;
                for (int i = 0; i < goal.Count; i++)
                {
                    if (i <= read.Count - 1)
                    {
                        result = -10;
                        result = String.Compare(goal[i], read[i]);
                        Equals.Add(result);
                    }

                }
                int resultdata = read.Count;
                int testdata = 0;
                for (int i = 0; i < Equals.Count; i++)
                {
                    if (Equals[i] == 0)
                    {
                        testdata += 1;
                    }
                }
                if (testdata >= resultdata * 90 / 100)
                {
                    // MessageBox.Show("成功");
                    return gaulKey;
                }
                return "-1";
            }
        }

 

<OCR>
<!--數字特征-->
<ocrdata key="0" value="1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!4|0!-4|1!4|0!-4|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-2|-7"/>
<ocrdata key="1" value="-1|1!1|0!0|1!0|1!0|1!0|1!0|1!-1|1!1|0!1|0!-1|-7"/>
<ocrdata key="2" value="1|0!1|0!-3|1!4|0!-4|1!4|0!-1|1!-1|1!-1|1!-1|1!0|1!1|0!1|0!1|0!1|0!-3|-7"/>
<ocrdata key="3" value="1|0!1|0!-3|1!4|0!0|1!-2|1!1|0!1|1!0|1!-4|1!4|0!-3|1!1|0!1|0!-2|-7"/>
<ocrdata key="4" value="-1|1!1|0!-2|1!2|0!-2|1!2|0!-3|1!3|0!-2|1!1|0!1|0!1|0!-1|1!0|1!1|0!-1|-7"/>
<ocrdata key="5" value="1|0!1|0!1|0!1|0!-4|1!0|1!0|1!1|0!1|0!1|0!1|1!0|1!-4|1!4|0!-3|1!1|0!1|0!-3|-7"/>
<ocrdata key="6" value="1|0!1|0!-3|1!3|0!-3|1!0|1!1|0!1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-2|-7"/>
<ocrdata key="7" value="1|0!1|0!1|0!1|0!-4|1!3|0!0|1!-1|1!0|1!0|1!0|1!0|1!-2|-7"/>
<ocrdata key="8" value="1|0!1|0!-3|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-2|-7"/>
<ocrdata key="9" value="1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!4|0!-3|1!1|0!1|0!1|0!0|1!-3|1!3|0!-3|1!1|0!1|0!-2|-7"/>
<!--以下為Win 10 數字特征-->
<ocrdata key="!0 " value="1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!4|0!-4|1!4|0!-4|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-2|-7"/>
<ocrdata key="!5 " value="1|0!1|0!1|0!1|0!-4|1!0|1!0|1!1|0!1|0!1|0!-3|1!4|0!0|1!-4|1!4|0!-3|1!1|0!1|0!-3|-7"/>
<ocrdata key="!6 " value="1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!3|0!1|0!-3|1!1|0!2|0!0|1!-4|1!3|0!-2|1!1|0!-1|-7"/>
<ocrdata key="!8 " value="1|0!1|0!-3|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!4|0!-3|1!1|0!1|0!-2|-7"/>
<ocrata key="!9 " value="1|0!1|0!-3|1!4|0!-4|1!4|0!-4|1!3|0!1|0!-3|1!1|0!2|0!0|1!-4|1!3|0!-2|1!1|0!-1|-7"/>
<!--截圖范圍-->
<!--第一組金額.第二組稅額.第三組小寫.第四組發票編號-->
<ocrxy key="1600*900" value="485|427|100|15!615|427|158|12!620|448|153|11!687|131|61|14"/>
</OCR>

 

以上是我保存的數字特征.每一個像素的相對間距.僅供參考

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM