Can anyone implement a simple tesseract dllcall example? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
william_ahk
Posts: 470
Joined: 03 Dec 2018, 20:02

Can anyone implement a simple tesseract dllcall example?

27 Jul 2021, 19:08

I tried Vis2 but it's quite slow because each time it runs tesseract cli binary. The UWP OCR is fast but it won't recognize certain texts and is less accurate than tesseract. It would be great if ahk can directly interop with the tesseract library.
There is a C++ example here but unfortunately I don't know much C++ :D
It will be a big step forward if this is implemented (accurate and fast OCR library).
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Can anyone implement a simple tesseract dllcall example?

28 Jul 2021, 14:51

in a folder, download and put: run with x64. error handling omitted
Last edited by swagfag on 17 Apr 2023, 02:25, edited 1 time in total.
william_ahk
Posts: 470
Joined: 03 Dec 2018, 20:02

Re: Can anyone implement a simple tesseract dllcall example?

01 Aug 2021, 23:45

@swagfag Is it possible to pass an image from memory to pixRead? That way we can recognize texts on screen directly without saving the screenshot as a file. Looks like there is a pixReadMem function in the leptonica library.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Can anyone implement a simple tesseract dllcall example?

02 Aug 2021, 14:39

pixReadMem - reads bitmap file from memory.
So You need create BITMAPFILEHEADER and BITMAPINFOHEADER structures and combine with bitmap data by Yourself.
william_ahk
Posts: 470
Joined: 03 Dec 2018, 20:02

Re: Can anyone implement a simple tesseract dllcall example?

03 Aug 2021, 03:38

Thanks! Should I pass the image as a buffer? How do I get bytes_per_pixel, bytes_per_line for the image?

Code: Select all

DllCall("libtesseract500\TessBaseAPISetImage", "Ptr", hAPI, "Ptr", hImg, "Int", image_width, "Int", image_height, "Int", , "Int", )
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Can anyone implement a simple tesseract dllcall example?

03 Aug 2021, 04:04

u loaded the image. either u know these properties ahead of time, or if theyre encoded in the image's metadata u can read them off, or u could derive them according to the image's format specification or u use whatever image introspection functions are available to u(if any, and presumably from the same set of APIs that allowed u to load the image in the first place)
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Can anyone implement a simple tesseract dllcall example?

03 Aug 2021, 04:15

Should I pass the image as a buffer?
You should pass pointer to a bit array of Your bitmap.

Code: Select all

bytes_per_pixel := bits_per_pixel/8
bytes_per_line := bytes_per_pixel*image_width
MrHue
Posts: 17
Joined: 01 Oct 2015, 02:51

Re: Can anyone implement a simple tesseract dllcall example?  Topic is solved

19 Oct 2021, 08:05

Thanks to swagfag I made sample script below to demonstrate use of using Tesseract to ocr a file and screenshot using pixReadMemBmp / TessBaseAPISetImage. Uncomment the line with out.bmp to see output of screenshot

Code: Select all

#NoEnv	; Don't check empty variables to see if they are environment variables (significantly improves performance)
; https://www.autohotkey.com/boards/viewtopic.php?f=76&t=93120
; download to same folder
; https://github.com/tesseract-ocr/tessdata/blob/master/eng.traineddata
; https://github.com/nguyenq/tess4j/blob/master/src/main/resources/win32-x86-64/libtesseract500.dll (dont forget to Unblock)
; https://github.com/nguyenq/lept4j/blob/master/src/main/resources/win32-x86-64/liblept1820.dll (same)
; https://github.com/tesseract-ocr/test/blob/master/testing/phototest.tif

msgbox % ocr("phototest.tif")	; ocr file
msgbox % ocr()				; ocr screen
return

ocr(win_id="",x1=0,y1=0,x2="",y2="",whitelist="",bw="",v=20,leptonica=0)
{
	static hAPI, header
	if !hAPI
		LoadLibrary("libtesseract500.dll")
		, LoadLibrary("liblept1820.dll")
		, hAPI := DllCall("libtesseract500\TessBaseAPICreate", "Ptr")
		, DllCall("libtesseract500\TessBaseAPIInit3", "Ptr", hAPI, "AStr", A_ScriptDir, "AStr", "eng")
		, VarSetCapacity(header, 54, 0)
		, NumPut(0x360000, NumPut(1, NumPut(0x5FC64D42, header, "UInt"), "UInt"), "UInt")	; Bitmap file header (14 bytes)

	if whitelist
		DllCall("libtesseract500\TessBaseAPISetVariable", "Ptr", hAPI, "Str", "tessedit_char_whitelist", "Str", whitelist)

	if (win_id<>"") && FileExist(win_id)
		hPix := DllCall("liblept1820\pixRead", "AStr", win_id, "Ptr")
		, DllCall("libtesseract500\TessBaseAPISetImage2", "Ptr", hAPI, "Ptr", hPix)
		, str:= DllCall("libtesseract500\TessBaseAPIGetUTF8Text", "Ptr", hAPI, "AStr")
	else {
		if (win_id=="")
			win_id:=WinExist("A")
		if (x2=="")
			WinGetPos,,,x2,,ahk_id %win_id%
		if (y2=="")
			WinGetPos,,,,y2,ahk_id %win_id%

		x:=min(x1,x2), y:=min(y1,y2), w:=abs(x2-x1)+1, h:=abs(y2-y1)+1
		, bh := -h	; must be -h for Tesseract
		, NumPut(32, NumPut(1, NumPut(bh, NumPut(w, NumPut(40, header, 14, "uint"), "int"), "int"), "UShort"), 0, "UShort") ; bitmap info for CreateDIB (40 bytes) positive h for Capture2Text to work
		, src := DllCall("user32.dll\GetDCEx", "Ptr", win_id, "Ptr", 0, "UInt", 3, "Ptr")
		, dst := DllCall("CreateCompatibleDC", "Ptr", src, "Ptr")
		, DIB := DllCall("CreateDIBSection", "Ptr", dst, "Ptr", &header+14, "UInt", 0, "Ptr*", pbits, "Ptr", 0, "UInt", 0, "Ptr")
		, DllCall("SelectObject", "Ptr", dst, "Ptr", DIB, "Ptr")
		, DllCall("BitBlt", "ptr", dst, "int", 0, "int", 0, "int", w, "int", h, "ptr", src, "int", x, "int", y, "Uint", 0xCC0020)
		if (bw<>"")
		{
			b:=(bw>>16)&x0xFF, g:=(bw>>8)&0xFF, r:=bw&0xFF
			Loop % w*h
			{
				Addr := pbits + A_Index*4
				if (abs(r - NumGet(Addr+2, 0, "UChar"))<=v)
				&& (abs(g - NumGet(Addr+1, 0, "UChar"))<=v)
				&& (abs(b - NumGet(Addr+0, 0, "UChar"))<=v)
					Numput(0, Addr+0, "UInt")
				else	Numput(0xFFFFFF, Addr+0, "UInt")			
			}
		}
		if leptonica
		{
			hData := DllCall("GlobalAlloc", "uint", 0x2, "uint", 54 + w*h*4, "ptr")
			, pData := DllCall("GlobalLock", "ptr", hData, "ptr")
			, DllCall("RtlMoveMemory", "ptr", pData + 0, "ptr", &header, "UInt", 54)		; destination, source, length
			, DllCall("RtlMoveMemory", "ptr", pData + 54, "ptr", pbits, "UInt", w*h*4)
			, hPix := DllCall("liblept1820\pixReadMemBmp", "Ptr", pData, "UInt", 54+w*h*4, "Ptr")
			, DllCall("libtesseract500\TessBaseAPISetImage2", "Ptr", hAPI, "Ptr", hPix)
			; , out := FileOpen("out.bmp", "w"), out.Rawwrite(pData+0,54+w*h*4), out.Close()
			, DllCall("GlobalUnlock", "ptr", hData)		; don't unlock immediately after rtlmovememory, wait a little bit
		} else	DllCall("libtesseract500\TessBaseAPISetImage", "Ptr", hAPI, "Ptr", pbits, "UInt", w, "UInt", h, "UInt", bytes_per_pixel := 4, "UInt", bytes_per_line := 4*w)
		str := DllCall("libtesseract500\TessBaseAPIGetUTF8Text", "Ptr", hAPI, "AStr")

		DllCall("DeleteDC", "ptr", dst)
		, DllCall("DeleteObject", "ptr", dib)
		, DllCall("ReleaseDC", "ptr", win_id, "ptr", src)
	}
	return str
}

LoadLibrary(dll)
{
	if !hModule:=DllCall("LoadLibrary", "Str", dll, "Ptr")
		msgbox % "LoadLibrary(" dll "): " GetLastError(A_LastError)
	return hModule
}

GetLastError(Error=0)
{
	VarSetCapacity(ErrorString, 1024)
	IfEqual, Error, 0, SetEnv, Error, %A_LastError%
	if DllCall("FormatMessage" 
		, "UINT", 0x1000	; FORMAT_MESSAGE_FROM_SYSTEM: The function should search the system message-table resource(s) for the requested message. 
		, "PTR", 0		; A handle to the module that contains the message table to search. 
		, "UINT", Error
		, "UINT", 0             ; Language-ID is automatically retreived 
		, "Str",  ErrorString 
		, "UINT", 1024          ; Buffer-Length 
		, "STR", "")		; "str",  "")            ;An array of values that are used as insert values in the formatted message. (not used) 
		return ErrorString
}
teadrinker
Posts: 4295
Joined: 29 Mar 2015, 09:41
Contact:

Re: Can anyone implement a simple tesseract dllcall example?

19 Oct 2021, 16:22

swagfag wrote: MsgBox % DllCall("libtesseract500\TessBaseAPIGetUTF8Text", "Ptr", hAPI, "AStr")
This is most likely incorrect, should be

Code: Select all

pStr := DllCall("libtesseract500\TessBaseAPIGetUTF8Text", "Ptr", hAPI, "Ptr")
MsgBox, % StrGet(pStr, "UTF-8")
andreas_s_
Posts: 2
Joined: 30 Nov 2022, 22:51

Re: Can anyone implement a simple tesseract dllcall example?

30 Nov 2022, 22:56

Can somebody help me,

1. Where to get liplept dll ?
2. i cant load tesseract dll and always got error code 126, how to resolve that ?
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Can anyone implement a simple tesseract dllcall example?

17 Apr 2023, 04:07

teadrinker wrote:
19 Oct 2021, 16:22
swagfag wrote: MsgBox % DllCall("libtesseract500\TessBaseAPIGetUTF8Text", "Ptr", hAPI, "AStr")
This is most likely incorrect, should be

Code: Select all

pStr := DllCall("libtesseract500\TessBaseAPIGetUTF8Text", "Ptr", hAPI, "Ptr")
MsgBox, % StrGet(pStr, "UTF-8")
wasnt really the point of the example, but yes its incorrect. should be freed with:

Code: Select all

DllCall("libtesseract500\TessDeleteText", "Ptr", pStr)
ananthuthilakan
Posts: 188
Joined: 08 Jul 2019, 05:37
Contact:

Re: Can anyone implement a simple tesseract dllcall example?

31 May 2023, 13:21

Code: Select all

~ObjectCache(): WARNING! LEAK! object 00000000009AE440 still has count 1
can be fixed by

Code: Select all

DllCall("libtesseract531\TessBaseAPIDelete","Ptr", hAPI)
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Can anyone implement a simple tesseract dllcall example?

05 Jun 2023, 12:33

I free like this:

Code: Select all

DllCall("libtesseract500\TessDeleteText", "ptr", pStr)
DllCall("libtesseract500\TessBaseAPIClear", "ptr", hApi)
DllCall("libtesseract500\TessBaseAPIEnd", "ptr", hApi)
DllCall("libtesseract500\TessBaseAPIDelete", "ptr", hApi)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: iamMG, morkovka18, ntepa, william_ahk and 177 guests