识别指定window窗口的文本

发布时间 2023-12-18 22:07:51作者: 至道中和

1. 简单需求

通过图文识别读取一个指定window窗口的文本。 获取窗口句柄,截图保存成bitmap ,调用图文识别库.

测试结果是对中文下的识别不是特别好。

需要注意的是,tessdata要下载指定目录页下。

2. 引用包

a. 引用 tesseract4.1  b.  Emgu.CV组件

3. 上代码

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using Emgu.CV;
using Emgu.CV.OCR;
using Emgu.CV.Structure;
using Tesseract;
using System.Windows.Forms;
using Pix = Tesseract.Pix;
using PageSegMode = Tesseract.PageSegMode;

public class Program
{
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);

    [DllImport("user32.dll")]
    public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("gdi32.dll")]
    public static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);


    [DllImport("user32.dll")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }


    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
    public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

    private const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    private const int KEYEVENTF_KEYUP = 0x0002;

    private const int VK_MENU = 0x12; // Alt
    private const int VK_S = 0x53; // S key


    public static Bitmap CaptureWindow(IntPtr hWnd)
    {
        RECT rect;
        GetWindowRect(hWnd, out rect);

        Bitmap bmp = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top, PixelFormat.Format32bppArgb);
        Graphics g = Graphics.FromImage(bmp);
        g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);

        return bmp;
    }

    public static void Main()
    {
        string windowTitle = "*无标题 - 记事本";

        //*无标题 - 记事本
        IntPtr hWnd = FindWindow(null, windowTitle);

        if (hWnd == IntPtr.Zero)
        {
            Console.WriteLine($"Could not find window with title '{windowTitle}'");
            return;
        }

        SetForegroundWindow(hWnd);
        //SendKeys.SendWait("%(s)"); //发送Alt+S事件


        // Press Alt + S
        //keybd_event(VK_MENU, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
        //keybd_event(VK_S, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);

        //// Release Alt + S
        //keybd_event(VK_S, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
        //keybd_event(VK_MENU, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);




        //图文识别
        Bitmap bmp = CaptureWindow(hWnd);

        //tessdata/tessdata-4.1.0
        TesseractEngine engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.TesseractAndLstm);

        using (Bitmap bmpImage = new Bitmap(bmp))
        {
            byte[] imageData = ImageToByte(bmpImage);
            using (var image = Pix.LoadFromMemory(imageData))
            {
                using (var page = engine.Process(image))
                {
                    var text = page.GetText();
                    Console.WriteLine("Text recognized from image: {0}", text);
                }
            }
        }

    }

    private static byte[] ImageToByte(Bitmap img)
    {
        ImageConverter converter = new ImageConverter();
        return (byte[])converter.ConvertTo(img, typeof(byte[]));
    }
}

 上述代码使用的是net6.0 开发的。控制台程序模拟windows事件,尤其是键盘快捷键时,有点问题。暂未处理。

就这样吧,兴趣所致,就是玩玩。 天太冷了,不想写的太多。 纯粹凑字数。