【问题标题】:How to make tesseract-ocr read from coordinates on a screen?如何让 tesseract-ocr 从屏幕上的坐标读取?
【发布时间】:2014-05-20 09:24:34
【问题描述】:

我一直在尝试寻找一个示例,说明如何创建一个类/函数,该类/函数将尝试从指定坐标处的屏幕读取文本。

使用 bitblt 捕获屏幕的指定部分并在其上运行 tesseract 的简单方法。全部在内存中完成,无需将图像文件创建到磁盘。

Tesseract 的 API 似乎真的很差,需要所有东西的 TIF 图像,据我所知,如果不深入研究其代码,它甚至无法接受位图内存图像。

任何帮助将不胜感激,一个实际的例子将是理想的。

【问题讨论】:

    标签: c++ ocr tesseract bitblt


    【解决方案1】:

    http://i.imgur.com/HaJ2zOI.png

    继续阅读/查看以下内容,了解如何使用 Tesseract-OCR 处理内存中的图像。

    #include <iostream>
    #include <vector>
    #include <stdexcept>
    #include <fstream>
    #include <memory>
    #include <cstring>
    #include <tesseract/baseapi.h>
    #include <leptonica/allheaders.h>
    
    #if defined _WIN32 || defined _WIN64
    #include <windows.h>
    #endif
    
    class Image
    {
        private:
            std::vector<std::uint8_t> Pixels;
            std::uint32_t width, height;
            std::uint16_t BitsPerPixel;
    
            void Flip(void* In, void* Out, int width, int height, unsigned int Bpp);
    
        public:
            #if defined _WIN32 || defined _WIN64
            explicit Image(HDC DC, int X, int Y, int Width, int Height);
            #endif
    
            inline std::uint16_t GetBitsPerPixel() {return this->BitsPerPixel;}
            inline std::uint16_t GetBytesPerPixel() {return this->BitsPerPixel / 8;}
            inline std::uint16_t GetBytesPerScanLine() {return (this->BitsPerPixel / 8) * this->width;}
            inline int GetWidth() const {return this->width;}
            inline int GetHeight() const {return this->height;}
            inline const std::uint8_t* GetPixels() {return this->Pixels.data();}
    };
    
    void Image::Flip(void* In, void* Out, int width, int height, unsigned int Bpp)
    {
       unsigned long Chunk = (Bpp > 24 ? width * 4 : width * 3 + width % 4);
       unsigned char* Destination = static_cast<unsigned char*>(Out);
       unsigned char* Source = static_cast<unsigned char*>(In) + Chunk * (height - 1);
    
       while(Source != In)
       {
          std::memcpy(Destination, Source, Chunk);
          Destination += Chunk;
          Source -= Chunk;
       }
    }
    
    #if defined _WIN32 || defined _WIN64
    Image::Image(HDC DC, int X, int Y, int Width, int Height) : Pixels(), width(Width), height(Height), BitsPerPixel(32)
    {
        BITMAP Bmp = {0};
        HBITMAP hBmp = reinterpret_cast<HBITMAP>(GetCurrentObject(DC, OBJ_BITMAP));
    
        if (GetObject(hBmp, sizeof(BITMAP), &Bmp) == 0)
            throw std::runtime_error("BITMAP DC NOT FOUND.");
    
        RECT area = {X, Y, X + Width, Y + Height};
        HWND Window = WindowFromDC(DC);
        GetClientRect(Window, &area);
    
        HDC MemDC = GetDC(nullptr);
        HDC SDC = CreateCompatibleDC(MemDC);
        HBITMAP hSBmp = CreateCompatibleBitmap(MemDC, width, height);
        DeleteObject(SelectObject(SDC, hSBmp));
    
        BitBlt(SDC, 0, 0, width, height, DC, X, Y, SRCCOPY);
        unsigned int data_size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
        std::vector<std::uint8_t> Data(data_size);
        this->Pixels.resize(data_size);
    
        BITMAPINFO Info = {sizeof(BITMAPINFOHEADER), static_cast<long>(width), static_cast<long>(height), 1, BitsPerPixel, BI_RGB, data_size, 0, 0, 0, 0};
        GetDIBits(SDC, hSBmp, 0, height, &Data[0], &Info, DIB_RGB_COLORS);
        this->Flip(&Data[0], &Pixels[0], width, height, BitsPerPixel);
    
        DeleteDC(SDC);
        DeleteObject(hSBmp);
        ReleaseDC(nullptr, MemDC);
    }
    #endif
    
    int main()
    {
        #if defined _WIN32 || defined _WIN64
        HWND SomeWindowHandle = GetDesktopWindow();
        HDC DC = GetDC(SomeWindowHandle);
    
        Image Img = Image(DC, 0, 0, 200, 200); //screenshot of 0, 0, 200, 200..
    
        ReleaseDC(SomeWindowHandle, DC);
        #else
        Image Img = Image(some_pixel_pointer, 200, 200); //pointer to pixels..
        #endif
    
        std::unique_ptr<tesseract::TessBaseAPI> tesseract_ptr(new tesseract::TessBaseAPI());
    
        tesseract_ptr->Init("/tesseract/tessdata', 'eng");
        tesseract_ptr->SetImage(Img.GetPixels(), Img.GetWidth(), Img.GetHeight(), Img.GetBytesPerPixel(), Img.GetBytesPerScanLine()); //Fixed this line..
    
        std::unique_ptr<char[]> utf8_text_ptr(tesseract_ptr->GetUTF8Text());
    
        std::cout<<utf8_text_ptr.get()<<"\n";
    
        return 0;
    }
    

    【讨论】:

    • 它对我来说打印得很好。我在Image class 中添加了Save 选项。您现在应该能够保存图像并查看屏幕截图的样子。这将 let you see 你传递给 tesseract-ocr 的内容。
    • 如果屏幕截图很好,其他一切都很好,很可能 tesseract 无法识别字符或需要设置其他选项.. 自从我实际使用 tesseract 已经有一段时间了(除了用于测试这篇文章).. 看到上面的代码有效并且 tesseract 得到了正确的图像,我唯一能想到的是你可能不得不在白色背景上使用黑色文本?不太确定,但这就是我测试过的。无论如何,我有学校,所以我会在早上回来看看你的情况如何。我会想办法的。
    • 如果有的话,您可以创建一个线程来解释您的问题,即 tesseract 无法识别字符,看看是否有其他人有想法,直到我从学校回来帮助调试它..
    • 确实需要一些调试才能正确。 Villavu(一个 Pascal 脚本站点)的人几乎每天都在使用它,没有任何问题 iirc。当我醒来时,我会在 Firefox 上测试它,我会告诉你它是怎么回事。现在只需在记事本之类的东西上试一试,看看它是否能识别您的文本。我将从文件加载到图像类中,以便您可以对其进行测试。
    • 好吧,我现在添加了翻转图像的功能。位图本质上是倒置存储在内存中的。现在应该将其翻转过来。现在应该可以工作了。
    【解决方案2】:

    你可以在 Windows 上这样做。

    #include <tesseract/capi.h>
    #include <windows.h>
    
    void ReadFromScreen(RECT rc)
    {
        HWND hWndDesktop = GetDesktopWindow();
        HDC hDC = GetDC(hWndDesktop);
    
    #define BITS_PER_PIXEL   32
    #define BYTES_PER_PIXEL  (BITS_PER_PIXEL / 8)
        int nWidth = rc.right - rc.left;
        int nHeight = rc.bottom - rc.top;
        BITMAPINFO bi;
        memset(&bi, 0, sizeof(bi));
        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bi.bmiHeader.biWidth = nWidth;
        bi.bmiHeader.biHeight = -nHeight;
        bi.bmiHeader.biPlanes = 1;
        bi.bmiHeader.biBitCount = BITS_PER_PIXEL;
        bi.bmiHeader.biCompression = BI_RGB;
    
        void* pixels;
        HBITMAP hBitmap = ::CreateDIBSection(0, &bi, DIB_RGB_COLORS, &pixels, NULL, 0);
        HDC hMemDC = CreateCompatibleDC(NULL);
        SelectObject(hMemDC, hBitmap);
        BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, rc.left, rc.top, SRCCOPY);
        int nDataSize = nWidth * nHeight * BYTES_PER_PIXEL;
        TessBaseAPISetImage(pTessBaseAPI, (const unsigned char*)pixels, nWidth, nHeight, BYTES_PER_PIXEL, BYTES_PER_PIXEL * nWidth);
        if (TessBaseAPIRecognize(pTessBaseAPI, NULL) != 0)
        {
            return;
        }
        char* szText = TessBaseAPIGetUTF8Text(pTessBaseAPI);
        // Todo something with szText
    
        TessDeleteText(szText);
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-22
      • 2015-08-01
      • 2019-11-02
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      • 2017-03-04
      相关资源
      最近更新 更多