Тема: AHK: Оптическое распознавание символов (OCR) с UWP API
Тема для обсуждения "AHK: Оптическое распознавание символов (OCR) с UWP API".
http://forum.script-coding.com/viewtopic.php?id=17649
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Тема для обсуждения "AHK: Оптическое распознавание символов (OCR) с UWP API".
http://forum.script-coding.com/viewtopic.php?id=17649
Отлично работает, твои последние разработки надо бы в коллекцию.
Если не охота оформлять, то просто пост со ссылками.
Возможно добавить вариант с битмапом а не файлом?
Да, отлично! Проверил, у меня работает с русским языком и с png-файлами.
твои последние разработки надо бы в коллекцию.
Да, можно как-нибудь разбить по темам и составить список, но главное, что поисковик по ключевым словам находит - кому надо, тот найдет.
Возможно добавить вариант с битмапом а не файлом?
teadrinker добавил.
https://www.autohotkey.com/boards/viewt … 87#p314787
Я первый пост поправил - не тот объект освобождал.
Это апи для win10.
Для семерки встроенных аналогов нет и не будет.
А если не встроенные? Типа, dll какую-то скачать?
Не знаю, не интересовался.
Программы распознавания текста бывают всякие разные, в том числе бесплатные и условно-бесплатные.
https://softcatalog.info/ru/obzor/progr … iya-teksta
Проапдейтил первый пост.
Сейчас можно битмап вместо пути файла передать?
Так выше же ссылку давали.
Официальный форум еле живой.
Я добавил твой код в последнюю версию скрипта.
#NoEnv
SetBatchLines, -1
Return
Esc:: ExitApp
^X::
hBitmap := HBitmapFromScreen(GetArea()*)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
text := ocr(pIRandomAccessStream, "ru")
MsgBox, % text
Return
GetArea() {
area := []
StartSelection(area)
while !area.w
Sleep, 100
Return area
}
StartSelection(area) {
handler := Func("Select").Bind(area)
Hotkey, LButton, % handler, On
ReplaceSystemCursors("IDC_CROSS")
}
Select(area) {
static hGui := CreateSelectionGui()
Hook := new WindowsHook(WH_MOUSE_LL := 14, "LowLevelMouseProc", hGui)
Loop {
KeyWait, LButton
WinGetPos, X, Y, W, H, ahk_id %hGui%
} until w > 0
ReplaceSystemCursors("")
Hotkey, LButton, Off
Hook := ""
Gui, %hGui%:Show, Hide
for k, v in ["x", "y", "w", "h"]
area[v] := %v%
}
ReplaceSystemCursors(IDC = "")
{
static IMAGE_CURSOR := 2, SPI_SETCURSORS := 0x57
, exitFunc := Func("ReplaceSystemCursors").Bind("")
, SysCursors := { IDC_APPSTARTING: 32650
, IDC_ARROW : 32512
, IDC_CROSS : 32515
, IDC_HAND : 32649
, IDC_HELP : 32651
, IDC_IBEAM : 32513
, IDC_NO : 32648
, IDC_SIZEALL : 32646
, IDC_SIZENESW : 32643
, IDC_SIZENWSE : 32642
, IDC_SIZEWE : 32644
, IDC_SIZENS : 32645
, IDC_UPARROW : 32516
, IDC_WAIT : 32514 }
if !IDC {
DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
OnExit(exitFunc, 0)
}
else {
hCursor := DllCall("LoadCursor", Ptr, 0, UInt, SysCursors[IDC], Ptr)
for k, v in SysCursors {
hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, IMAGE_CURSOR, Int, 0, Int, 0, UInt, 0, Ptr)
DllCall("SetSystemCursor", Ptr, hCopy, UInt, v)
}
OnExit(exitFunc)
}
}
CreateSelectionGui() {
Gui, New, +hwndhGui +Alwaysontop -Caption +LastFound +ToolWindow +E0x20 -DPIScale
WinSet, Transparent, 130
Gui, Color, FFC800
Return hGui
}
LowLevelMouseProc(nCode, wParam, lParam) {
static WM_MOUSEMOVE := 0x200, WM_LBUTTONUP := 0x202
, coords := [], startMouseX, startMouseY, hGui
, timer := Func("LowLevelMouseProc").Bind("timer", "", "")
if (nCode = "timer") {
while coords[1] {
point := coords.RemoveAt(1)
mouseX := point[1], mouseY := point[2]
x := startMouseX < mouseX ? startMouseX : mouseX
y := startMouseY < mouseY ? startMouseY : mouseY
w := Abs(mouseX - startMouseX)
h := Abs(mouseY - startMouseY)
try Gui, %hGUi%: Show, x%x% y%y% w%w% h%h% NA
}
}
else {
(!hGui && hGui := A_EventInfo)
if (wParam = WM_LBUTTONUP)
startMouseX := startMouseY := ""
if (wParam = WM_MOUSEMOVE) {
mouseX := NumGet(lParam + 0, "Int")
mouseY := NumGet(lParam + 4, "Int")
if (startMouseX = "") {
startMouseX := mouseX
startMouseY := mouseY
}
coords.Push([mouseX, mouseY])
SetTimer, % timer, -10
}
Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, Ptr, lParam)
}
}
class WindowsHook {
__New(type, callback, eventInfo := "", isGlobal := true) {
this.callbackPtr := RegisterCallback(callback, "Fast", 3, eventInfo)
this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.callbackPtr
, "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr")
, "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr")
}
__Delete() {
DllCall("UnhookWindowsHookEx", "Ptr", this.hHook)
DllCall("GlobalFree", "Ptr", this.callBackPtr, "Ptr")
}
}
HBitmapFromScreen(X, Y, W, H) {
HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
HBM := DllCall("CreateCompatibleBitmap", "Ptr", HDC, "Int", W, "Int", H, "UPtr")
PDC := DllCall("CreateCompatibleDC", "Ptr", HDC, "UPtr")
DllCall("SelectObject", "Ptr", PDC, "Ptr", HBM)
DllCall("BitBlt", "Ptr", PDC, "Int", 0, "Int", 0, "Int", W, "Int", H
, "Ptr", HDC, "Int", X, "Int", Y, "UInt", 0x00CC0020)
DllCall("DeleteDC", "Ptr", PDC)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", HDC)
Return HBM
}
HBitmapToRandomAccessStream(hBitmap) {
static IID_IRandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}"
, IID_IPicture := "{7BF80980-BF32-101A-8BBB-00AA00300CAB}"
, PICTYPE_BITMAP := 1
, BSOS_DEFAULT := 0
DllCall("Ole32\CreateStreamOnHGlobal", "Ptr", 0, "UInt", true, "PtrP", pIStream, "UInt")
VarSetCapacity(PICTDESC, sz := 8 + A_PtrSize*2, 0)
NumPut(sz, PICTDESC)
NumPut(PICTYPE_BITMAP, PICTDESC, 4)
NumPut(hBitmap, PICTDESC, 8)
riid := CLSIDFromString(IID_IPicture, GUID1)
DllCall("OleAut32\OleCreatePictureIndirect", "Ptr", &PICTDESC, "Ptr", riid, "UInt", false, "PtrP", pIPicture, "UInt")
; IPicture::SaveAsFile
DllCall(NumGet(NumGet(pIPicture+0) + A_PtrSize*15), "Ptr", pIPicture, "Ptr", pIStream, "UInt", true, "UIntP", size, "UInt")
riid := CLSIDFromString(IID_IRandomAccessStream, GUID2)
DllCall("ShCore\CreateRandomAccessStreamOverStream", "Ptr", pIStream, "UInt", BSOS_DEFAULT, "Ptr", riid, "PtrP", pIRandomAccessStream, "UInt")
ObjRelease(pIPicture)
ObjRelease(pIStream)
Return pIRandomAccessStream
}
CLSIDFromString(IID, ByRef CLSID) {
VarSetCapacity(CLSID, 16, 0)
if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
Return &CLSID
}
ocr(file, lang := "FirstFromAvailableLanguages")
{
static OcrEngineStatics, OcrEngine, MaxDimension, LanguageFactory, Language, CurrentLanguage, BitmapDecoderStatics, GlobalizationPreferencesStatics
if (OcrEngineStatics = "")
{
CreateClass("Windows.Globalization.Language", ILanguageFactory := "{9B0252AC-0C27-44F8-B792-9793FB66C63E}", LanguageFactory)
CreateClass("Windows.Graphics.Imaging.BitmapDecoder", IBitmapDecoderStatics := "{438CCB26-BCEF-4E95-BAD6-23A822E58D01}", BitmapDecoderStatics)
CreateClass("Windows.Media.Ocr.OcrEngine", IOcrEngineStatics := "{5BFFA85A-3384-3540-9940-699120D428A8}", OcrEngineStatics)
DllCall(NumGet(NumGet(OcrEngineStatics+0)+6*A_PtrSize), "ptr", OcrEngineStatics, "uint*", MaxDimension) ; MaxImageDimension
}
if (file = "ShowAvailableLanguages")
{
if (GlobalizationPreferencesStatics = "")
CreateClass("Windows.System.UserProfile.GlobalizationPreferences", IGlobalizationPreferencesStatics := "{01BF4326-ED37-4E96-B0E9-C1340D1EA158}", GlobalizationPreferencesStatics)
DllCall(NumGet(NumGet(GlobalizationPreferencesStatics+0)+9*A_PtrSize), "ptr", GlobalizationPreferencesStatics, "ptr*", LanguageList) ; get_Languages
DllCall(NumGet(NumGet(LanguageList+0)+7*A_PtrSize), "ptr", LanguageList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(LanguageList+0)+6*A_PtrSize), "ptr", LanguageList, "int", A_Index-1, "ptr*", hString) ; get_Item
DllCall(NumGet(NumGet(LanguageFactory+0)+6*A_PtrSize), "ptr", LanguageFactory, "ptr", hString, "ptr*", LanguageTest) ; CreateLanguage
DllCall(NumGet(NumGet(OcrEngineStatics+0)+8*A_PtrSize), "ptr", OcrEngineStatics, "ptr", LanguageTest, "int*", bool) ; IsLanguageSupported
if (bool = 1)
{
DllCall(NumGet(NumGet(LanguageTest+0)+6*A_PtrSize), "ptr", LanguageTest, "ptr*", hText)
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
text .= StrGet(buffer, "UTF-16") "`n"
}
ObjRelease(LanguageTest)
}
ObjRelease(LanguageList)
return text
}
if (lang != CurrentLanguage) or (lang = "FirstFromAvailableLanguages")
{
if (OcrEngine != "")
{
ObjRelease(OcrEngine)
if (CurrentLanguage != "FirstFromAvailableLanguages")
ObjRelease(Language)
}
if (lang = "FirstFromAvailableLanguages")
DllCall(NumGet(NumGet(OcrEngineStatics+0)+10*A_PtrSize), "ptr", OcrEngineStatics, "ptr*", OcrEngine) ; TryCreateFromUserProfileLanguages
else
{
CreateHString(lang, hString)
DllCall(NumGet(NumGet(LanguageFactory+0)+6*A_PtrSize), "ptr", LanguageFactory, "ptr", hString, "ptr*", Language) ; CreateLanguage
DeleteHString(hString)
DllCall(NumGet(NumGet(OcrEngineStatics+0)+9*A_PtrSize), "ptr", OcrEngineStatics, ptr, Language, "ptr*", OcrEngine) ; TryCreateFromLanguage
}
if (OcrEngine = 0)
{
msgbox Can not use language "%lang%" for OCR, please install language pack.
ExitApp
}
CurrentLanguage := lang
}
IRandomAccessStream := file
DllCall(NumGet(NumGet(BitmapDecoderStatics+0)+14*A_PtrSize), "ptr", BitmapDecoderStatics, "ptr", IRandomAccessStream, "ptr*", BitmapDecoder) ; CreateAsync
WaitForAsync(BitmapDecoder)
BitmapFrame := ComObjQuery(BitmapDecoder, IBitmapFrame := "{72A49A1C-8081-438D-91BC-94ECFC8185C6}")
DllCall(NumGet(NumGet(BitmapFrame+0)+12*A_PtrSize), "ptr", BitmapFrame, "uint*", width) ; get_PixelWidth
DllCall(NumGet(NumGet(BitmapFrame+0)+13*A_PtrSize), "ptr", BitmapFrame, "uint*", height) ; get_PixelHeight
if (width > MaxDimension) or (height > MaxDimension)
{
msgbox Image is to big - %width%x%height%.`nIt should be maximum - %MaxDimension% pixels
ExitApp
}
BitmapFrameWithSoftwareBitmap := ComObjQuery(BitmapDecoder, IBitmapFrameWithSoftwareBitmap := "{FE287C9A-420C-4963-87AD-691436E08383}")
DllCall(NumGet(NumGet(BitmapFrameWithSoftwareBitmap+0)+6*A_PtrSize), "ptr", BitmapFrameWithSoftwareBitmap, "ptr*", SoftwareBitmap) ; GetSoftwareBitmapAsync
WaitForAsync(SoftwareBitmap)
DllCall(NumGet(NumGet(OcrEngine+0)+6*A_PtrSize), "ptr", OcrEngine, ptr, SoftwareBitmap, "ptr*", OcrResult) ; RecognizeAsync
WaitForAsync(OcrResult)
DllCall(NumGet(NumGet(OcrResult+0)+6*A_PtrSize), "ptr", OcrResult, "ptr*", LinesList) ; get_Lines
DllCall(NumGet(NumGet(LinesList+0)+7*A_PtrSize), "ptr", LinesList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(LinesList+0)+6*A_PtrSize), "ptr", LinesList, "int", A_Index-1, "ptr*", OcrLine)
DllCall(NumGet(NumGet(OcrLine+0)+7*A_PtrSize), "ptr", OcrLine, "ptr*", hText)
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
text .= StrGet(buffer, "UTF-16") "`n"
ObjRelease(OcrLine)
}
Close := ComObjQuery(IRandomAccessStream, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")
DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close
ObjRelease(Close)
Close := ComObjQuery(SoftwareBitmap, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")
DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close
ObjRelease(Close)
ObjRelease(IRandomAccessStream)
ObjRelease(BitmapDecoder)
ObjRelease(BitmapFrame)
ObjRelease(BitmapFrameWithSoftwareBitmap)
ObjRelease(SoftwareBitmap)
ObjRelease(OcrResult)
ObjRelease(LinesList)
return text
}
CreateClass(string, interface, ByRef Class)
{
CreateHString(string, hString)
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID)
result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class)
if (result != 0)
{
if (result = 0x80004002)
msgbox No such interface supported
else if (result = 0x80040154)
msgbox Class not registered
else
msgbox error: %result%
ExitApp
}
DeleteHString(hString)
}
CreateHString(string, ByRef hString)
{
DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString)
}
DeleteHString(hString)
{
DllCall("Combase.dll\WindowsDeleteString", "ptr", hString)
}
WaitForAsync(ByRef Object)
{
AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}")
loop
{
DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status
if (status != 0)
{
if (status != 1)
{
DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode
msgbox AsyncInfo status error: %ErrorCode%
ExitApp
}
ObjRelease(AsyncInfo)
break
}
sleep 10
}
DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults
ObjRelease(Object)
Object := ObjectResult
}
Да, что-то несколько дней уже тупит.
Так выше же ссылку давали.
В 4? Не открывается, я думал в первом посте правки.
Это я как-то криво линк вписал.
Но можно пользоваться из 13.
А, понял. Я просто думал ты это в "основную" версию опционально добавишь.
Я бы добавил просто не понимаю как.
В одном скрипте текст распознается из одного файла или множества файлов.
В другом с экрана.
Задачи как бы разные.
Если изменений никаких в ближайшее время не будет, то добавлю вариант с записью экрана, как отдельный скрипт в первый пост.
Этот метод считывания будет работать в приложениях на DirectX или OpenGL ?
С OpenGL думаю да, а с полноэкранными приложениями DirectX нет.
Нужно инжектить dll.
А можете подсказать как сделать так что бы при нажатии кнопки в заранее указанной области распознавалось значение и записывалось в переменную?
*
И нормально ли что скрипт не распознает текст если выделена не достаточно большая часть экрана?
А можете подсказать как сделать так что бы при нажатии кнопки в заранее указанной области распознавалось значение и записывалось в переменную?
Надо заменить
hBitmap := HBitmapFromScreen(GetArea()*)
на
hBitmap := HBitmapFromScreen(X, Y, W, H)
Остальное читайте справку.
И нормально ли что скрипт не распознает текст если выделена не достаточно большая часть экрана?
Не знаю.
Спасибо за оперативный ответ! К сожалению не понимаю почему скрипт не работает с маленькой областью( Если кому то удалось решить проблему, буду благодарен подсказке!
И нормально ли что скрипт не распознает текст если выделена не достаточно большая часть экрана?
В таких случаях надо увеличивать картинку в памяти.
Вот попробуйте сначала на 1 - HBitmapFromScreen, после туже зону на 2 - HBitmapFromScreenZoom, или на 3.
#NoEnv
SetBatchLines, -1
; HBitmapFromScreenZoom
; Если одна из сторон захваченного изображения меньше
; MinW или MinH, то обе стороны умножить на MinMult
Global MinW := 200, MinH := 100, MinMult := 2
Return
Esc:: ExitApp
1::
hBitmap := HBitmapFromScreen(GetArea()*)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
text := ocr(pIRandomAccessStream, "ru")
MsgBox, % text
Return
2::
hBitmap := HBitmapFromScreenZoom(GetArea()*)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
text := ocr(pIRandomAccessStream, "ru")
MsgBox, % text
Return
3::
Area := GetArea()
hBitmap := HBitmapFromScreen(Area*)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
text := ocr(pIRandomAccessStream)
MsgBox, , HBitmapFromScreen, % text
hBitmap := HBitmapFromScreenZoom(Area*)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
text := ocr(pIRandomAccessStream)
MsgBox, , HBitmapFromScreenZoom, % text
Return
GetArea() {
area := []
StartSelection(area)
while !area.w
Sleep, 100
Return area
}
StartSelection(area) {
handler := Func("Select").Bind(area)
Hotkey, LButton, % handler, On
ReplaceSystemCursors("IDC_CROSS")
}
Select(area) {
static hGui := CreateSelectionGui()
Hook := new WindowsHook(WH_MOUSE_LL := 14, "LowLevelMouseProc", hGui)
Loop {
KeyWait, LButton
WinGetPos, X, Y, W, H, ahk_id %hGui%
} until w > 0
ReplaceSystemCursors("")
Hotkey, LButton, Off
Hook := ""
Gui, %hGui%:Show, Hide
for k, v in ["x", "y", "w", "h"]
area[v] := %v%
}
ReplaceSystemCursors(IDC = "")
{
static IMAGE_CURSOR := 2, SPI_SETCURSORS := 0x57
, exitFunc := Func("ReplaceSystemCursors").Bind("")
, SysCursors := { IDC_APPSTARTING: 32650
, IDC_ARROW : 32512
, IDC_CROSS : 32515
, IDC_HAND : 32649
, IDC_HELP : 32651
, IDC_IBEAM : 32513
, IDC_NO : 32648
, IDC_SIZEALL : 32646
, IDC_SIZENESW : 32643
, IDC_SIZENWSE : 32642
, IDC_SIZEWE : 32644
, IDC_SIZENS : 32645
, IDC_UPARROW : 32516
, IDC_WAIT : 32514 }
if !IDC {
DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
OnExit(exitFunc, 0)
}
else {
hCursor := DllCall("LoadCursor", Ptr, 0, UInt, SysCursors[IDC], Ptr)
for k, v in SysCursors {
hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, IMAGE_CURSOR, Int, 0, Int, 0, UInt, 0, Ptr)
DllCall("SetSystemCursor", Ptr, hCopy, UInt, v)
}
OnExit(exitFunc)
}
}
CreateSelectionGui() {
Gui, New, +hwndhGui +Alwaysontop -Caption +LastFound +ToolWindow +E0x20 -DPIScale
WinSet, Transparent, 130
Gui, Color, FFC800
Return hGui
}
LowLevelMouseProc(nCode, wParam, lParam) {
static WM_MOUSEMOVE := 0x200, WM_LBUTTONUP := 0x202
, coords := [], startMouseX, startMouseY, hGui
, timer := Func("LowLevelMouseProc").Bind("timer", "", "")
if (nCode = "timer") {
while coords[1] {
point := coords.RemoveAt(1)
mouseX := point[1], mouseY := point[2]
x := startMouseX < mouseX ? startMouseX : mouseX
y := startMouseY < mouseY ? startMouseY : mouseY
w := Abs(mouseX - startMouseX)
h := Abs(mouseY - startMouseY)
try Gui, %hGUi%: Show, x%x% y%y% w%w% h%h% NA
}
}
else {
(!hGui && hGui := A_EventInfo)
if (wParam = WM_LBUTTONUP)
startMouseX := startMouseY := ""
if (wParam = WM_MOUSEMOVE) {
mouseX := NumGet(lParam + 0, "Int")
mouseY := NumGet(lParam + 4, "Int")
if (startMouseX = "") {
startMouseX := mouseX
startMouseY := mouseY
}
coords.Push([mouseX, mouseY])
SetTimer, % timer, -10
}
Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, Ptr, lParam)
}
}
class WindowsHook {
__New(type, callback, eventInfo := "", isGlobal := true) {
this.callbackPtr := RegisterCallback(callback, "Fast", 3, eventInfo)
this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.callbackPtr
, "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr")
, "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr")
}
__Delete() {
DllCall("UnhookWindowsHookEx", "Ptr", this.hHook)
DllCall("GlobalFree", "Ptr", this.callBackPtr, "Ptr")
}
}
HBitmapFromScreen(X, Y, W, H) {
HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
HBM := DllCall("CreateCompatibleBitmap", "Ptr", HDC, "Int", W, "Int", H, "UPtr")
PDC := DllCall("CreateCompatibleDC", "Ptr", HDC, "UPtr")
DllCall("SelectObject", "Ptr", PDC, "Ptr", HBM)
DllCall("BitBlt", "Ptr", PDC, "Int", 0, "Int", 0, "Int", W, "Int", H
, "Ptr", HDC, "Int", X, "Int", Y, "UInt", 0x00CC0020)
DllCall("DeleteDC", "Ptr", PDC)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", HDC)
Return HBM
}
HBitmapFromScreenZoom(X, Y, W, H) {
If (W < MinW || H < MinH)
dw := W * MinMult, dh := H * MinMult
Else
dw := W, dh := H
HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
HBM := DllCall("CreateCompatibleBitmap", "Ptr", HDC, "Int", dw, "Int", dh, "UPtr")
PDC := DllCall("CreateCompatibleDC", "Ptr", HDC, "UPtr")
DllCall("SelectObject", "Ptr", PDC, "Ptr", HBM)
DllCall("StretchBlt", "Ptr", PDC, "int", 0, "int", 0, "int", dw, "int", dh
, "Ptr", HDC, "int", X, "int", Y, "int", W, "int", H, "UInt", 0x00CC0020)
DllCall("DeleteDC", "Ptr", PDC)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", HDC)
Return HBM
}
HBitmapToRandomAccessStream(hBitmap) {
static IID_IRandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}"
, IID_IPicture := "{7BF80980-BF32-101A-8BBB-00AA00300CAB}"
, PICTYPE_BITMAP := 1
, BSOS_DEFAULT := 0
DllCall("Ole32\CreateStreamOnHGlobal", "Ptr", 0, "UInt", true, "PtrP", pIStream, "UInt")
VarSetCapacity(PICTDESC, sz := 8 + A_PtrSize*2, 0)
NumPut(sz, PICTDESC)
NumPut(PICTYPE_BITMAP, PICTDESC, 4)
NumPut(hBitmap, PICTDESC, 8)
riid := CLSIDFromString(IID_IPicture, GUID1)
DllCall("OleAut32\OleCreatePictureIndirect", "Ptr", &PICTDESC, "Ptr", riid, "UInt", false, "PtrP", pIPicture, "UInt")
; IPicture::SaveAsFile
DllCall(NumGet(NumGet(pIPicture+0) + A_PtrSize*15), "Ptr", pIPicture, "Ptr", pIStream, "UInt", true, "UIntP", size, "UInt")
riid := CLSIDFromString(IID_IRandomAccessStream, GUID2)
DllCall("ShCore\CreateRandomAccessStreamOverStream", "Ptr", pIStream, "UInt", BSOS_DEFAULT, "Ptr", riid, "PtrP", pIRandomAccessStream, "UInt")
ObjRelease(pIPicture)
ObjRelease(pIStream)
Return pIRandomAccessStream
}
CLSIDFromString(IID, ByRef CLSID) {
VarSetCapacity(CLSID, 16, 0)
if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
Return &CLSID
}
ocr(file, lang := "FirstFromAvailableLanguages")
{
static OcrEngineStatics, OcrEngine, MaxDimension, LanguageFactory, Language, CurrentLanguage, BitmapDecoderStatics, GlobalizationPreferencesStatics
if (OcrEngineStatics = "")
{
CreateClass("Windows.Globalization.Language", ILanguageFactory := "{9B0252AC-0C27-44F8-B792-9793FB66C63E}", LanguageFactory)
CreateClass("Windows.Graphics.Imaging.BitmapDecoder", IBitmapDecoderStatics := "{438CCB26-BCEF-4E95-BAD6-23A822E58D01}", BitmapDecoderStatics)
CreateClass("Windows.Media.Ocr.OcrEngine", IOcrEngineStatics := "{5BFFA85A-3384-3540-9940-699120D428A8}", OcrEngineStatics)
DllCall(NumGet(NumGet(OcrEngineStatics+0)+6*A_PtrSize), "ptr", OcrEngineStatics, "uint*", MaxDimension) ; MaxImageDimension
}
if (file = "ShowAvailableLanguages")
{
if (GlobalizationPreferencesStatics = "")
CreateClass("Windows.System.UserProfile.GlobalizationPreferences", IGlobalizationPreferencesStatics := "{01BF4326-ED37-4E96-B0E9-C1340D1EA158}", GlobalizationPreferencesStatics)
DllCall(NumGet(NumGet(GlobalizationPreferencesStatics+0)+9*A_PtrSize), "ptr", GlobalizationPreferencesStatics, "ptr*", LanguageList) ; get_Languages
DllCall(NumGet(NumGet(LanguageList+0)+7*A_PtrSize), "ptr", LanguageList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(LanguageList+0)+6*A_PtrSize), "ptr", LanguageList, "int", A_Index-1, "ptr*", hString) ; get_Item
DllCall(NumGet(NumGet(LanguageFactory+0)+6*A_PtrSize), "ptr", LanguageFactory, "ptr", hString, "ptr*", LanguageTest) ; CreateLanguage
DllCall(NumGet(NumGet(OcrEngineStatics+0)+8*A_PtrSize), "ptr", OcrEngineStatics, "ptr", LanguageTest, "int*", bool) ; IsLanguageSupported
if (bool = 1)
{
DllCall(NumGet(NumGet(LanguageTest+0)+6*A_PtrSize), "ptr", LanguageTest, "ptr*", hText)
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
text .= StrGet(buffer, "UTF-16") "`n"
}
ObjRelease(LanguageTest)
}
ObjRelease(LanguageList)
return text
}
if (lang != CurrentLanguage) or (lang = "FirstFromAvailableLanguages")
{
if (OcrEngine != "")
{
ObjRelease(OcrEngine)
if (CurrentLanguage != "FirstFromAvailableLanguages")
ObjRelease(Language)
}
if (lang = "FirstFromAvailableLanguages")
DllCall(NumGet(NumGet(OcrEngineStatics+0)+10*A_PtrSize), "ptr", OcrEngineStatics, "ptr*", OcrEngine) ; TryCreateFromUserProfileLanguages
else
{
CreateHString(lang, hString)
DllCall(NumGet(NumGet(LanguageFactory+0)+6*A_PtrSize), "ptr", LanguageFactory, "ptr", hString, "ptr*", Language) ; CreateLanguage
DeleteHString(hString)
DllCall(NumGet(NumGet(OcrEngineStatics+0)+9*A_PtrSize), "ptr", OcrEngineStatics, ptr, Language, "ptr*", OcrEngine) ; TryCreateFromLanguage
}
if (OcrEngine = 0)
{
msgbox Can not use language "%lang%" for OCR, please install language pack.
ExitApp
}
CurrentLanguage := lang
}
IRandomAccessStream := file
DllCall(NumGet(NumGet(BitmapDecoderStatics+0)+14*A_PtrSize), "ptr", BitmapDecoderStatics, "ptr", IRandomAccessStream, "ptr*", BitmapDecoder) ; CreateAsync
WaitForAsync(BitmapDecoder)
BitmapFrame := ComObjQuery(BitmapDecoder, IBitmapFrame := "{72A49A1C-8081-438D-91BC-94ECFC8185C6}")
DllCall(NumGet(NumGet(BitmapFrame+0)+12*A_PtrSize), "ptr", BitmapFrame, "uint*", width) ; get_PixelWidth
DllCall(NumGet(NumGet(BitmapFrame+0)+13*A_PtrSize), "ptr", BitmapFrame, "uint*", height) ; get_PixelHeight
if (width > MaxDimension) or (height > MaxDimension)
{
msgbox Image is to big - %width%x%height%.`nIt should be maximum - %MaxDimension% pixels
ExitApp
}
BitmapFrameWithSoftwareBitmap := ComObjQuery(BitmapDecoder, IBitmapFrameWithSoftwareBitmap := "{FE287C9A-420C-4963-87AD-691436E08383}")
DllCall(NumGet(NumGet(BitmapFrameWithSoftwareBitmap+0)+6*A_PtrSize), "ptr", BitmapFrameWithSoftwareBitmap, "ptr*", SoftwareBitmap) ; GetSoftwareBitmapAsync
WaitForAsync(SoftwareBitmap)
DllCall(NumGet(NumGet(OcrEngine+0)+6*A_PtrSize), "ptr", OcrEngine, ptr, SoftwareBitmap, "ptr*", OcrResult) ; RecognizeAsync
WaitForAsync(OcrResult)
DllCall(NumGet(NumGet(OcrResult+0)+6*A_PtrSize), "ptr", OcrResult, "ptr*", LinesList) ; get_Lines
DllCall(NumGet(NumGet(LinesList+0)+7*A_PtrSize), "ptr", LinesList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(LinesList+0)+6*A_PtrSize), "ptr", LinesList, "int", A_Index-1, "ptr*", OcrLine)
DllCall(NumGet(NumGet(OcrLine+0)+7*A_PtrSize), "ptr", OcrLine, "ptr*", hText)
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
text .= StrGet(buffer, "UTF-16") "`n"
ObjRelease(OcrLine)
}
Close := ComObjQuery(IRandomAccessStream, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")
DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close
ObjRelease(Close)
Close := ComObjQuery(SoftwareBitmap, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")
DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close
ObjRelease(Close)
ObjRelease(IRandomAccessStream)
ObjRelease(BitmapDecoder)
ObjRelease(BitmapFrame)
ObjRelease(BitmapFrameWithSoftwareBitmap)
ObjRelease(SoftwareBitmap)
ObjRelease(OcrResult)
ObjRelease(LinesList)
return text
}
CreateClass(string, interface, ByRef Class)
{
CreateHString(string, hString)
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID)
result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class)
if (result != 0)
{
if (result = 0x80004002)
msgbox No such interface supported
else if (result = 0x80040154)
msgbox Class not registered
else
msgbox error: %result%
ExitApp
}
DeleteHString(hString)
}
CreateHString(string, ByRef hString)
{
DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString)
}
DeleteHString(hString)
{
DllCall("Combase.dll\WindowsDeleteString", "ptr", hString)
}
WaitForAsync(ByRef Object)
{
AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}")
loop
{
DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status
if (status != 0)
{
if (status != 1)
{
DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode
msgbox AsyncInfo status error: %ErrorCode%
ExitApp
}
ObjRelease(AsyncInfo)
break
}
sleep 10
}
DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults
ObjRelease(Object)
Object := ObjectResult
}
В таких случаях надо увеличивать картинку в памяти.
А зачем увеличивать, а не просто добавлять под нее пустой канвас?
Мне показалось это проще, и кажется логичным что больший текст будет проще распознать, может я ошибаюсь, приведи код.
кажется логичным что больший текст будет проще распознать
А мне как-раз показалось нелогичным, так как проблема была не в маленьком размере текста, а в маленькой области выделения.
приведи код.
Лень.
Ну не знаю, я обвёл текст по границам его символов, не распознало. Я обвёл этот же текст захватив фон по краям, не распознало. С увеличением в обоих случаях работает.
АП: С фоном изредка срабатывает.
Возьми пост с этого форума, обведи с увеличением и увидишь ошибки в распозновании.
Сравни:
Ну не знаю, я обвёл текст по границам его символов, не распознало. Я обвёл этот же текст захватив фон по краям, не распознало. С увеличением 8 обоих случаях работает.
дп: С фоном изредка срабатывает.
Ну на знаю, я обвёл текст по границам аго символов, на распознало. Я обвёл этот жа текст захватив фон по краям, на распознало. С уваличаниам 8 обоих случаях работает.
дп: С фоном изредка срабатывает.
Мне показалось это проще
А чего сложного создать битмап, залить его белым цветом и присобачить битмап взятый с экрана?
Так лучше. Я пробовал на тёмном фоне, там часто не определяется ничего, и пробовал на маленькой ширине по одному слову. Думаю случаи могут быть разные.
А чего сложного
Ничего, тоже лень.
Думаю случаи могут быть разные.
Может быть. Но у автора вопроса конкретный.
скрипт не распознает текст если выделена не достаточно большая часть экрана
Поэтому я и посчитал увеличение в данном случае нелогичным.
Ну да, тут речь не про мелкий текст, ты прав.
Хотел бы поднять данную шикарную тему. У меня не распознаются числа, рядом с числом находится какая-то иконка и для многих иконок оно придумывает какую-то букву, а для какой-то похоже не всегда. Можно ли как-то это побороть? Приложу изображение, в данном случае не распознается "1730".
Используется английский язык (на русском все еще куда хуже и появлялись лишние цифры), сейчас выдает такой результат:
\"1910 02150 \"1610 m 2500 • 2520 • 1880 @ 3400 *3190 z 3390
Что если через поиск картинки (этих символов-иконок) организовать определение координат, затем можно например OCR текст определять начиная с этих координат.
Муторно правда выйдет.
У меня не распознаются числа
А как Вы организовали распознавание? Я как-то давно сохранял все возможные цифры в виде картинок, и у меня получалось через ImageSearch.
hBitmap := Gdip_HBitmapFromScreen(900, 55, 780, 50)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
text := ocr(pIRandomAccessStream, "en-US")
ObjRelease(pIRandomAccessStream)
Закрашивайте лишние участки черным, а потом уже распознавайте.
Я тоже об этом думал, но читал, что оно не распознает цифры без букв, хотя после проверок - все нормально.
У меня получилось что-то такое, но можно это сделать как-то более элегантно что-ли?
hBitmap := Gdip_HBitmapFromScreen(900, 55, 780, 50)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
pBrush := Gdip_BrushCreateSolid(0xFF000000)
pGraphics := Gdip_GraphicsFromImage(pBitmap)
Gdip_FillRectangle(pGraphics, pBrush, 0, 0, 60, 105)
loop, 9
{
x := 60 + (51 * A_Index) + (20 * (A_Index - 1))
Gdip_FillRectangle(pGraphics, pBrush, x, 0, 25, 105)
}
Gdip_DeleteBrush(pBrush)
Gdip_DrawImage(pGraphics, pBitmap)
Gdip_DeleteGraphics(pGraphics)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
; SetImage(hpControl, hBitmap)
Gdip_DisposeImage(pBitmap)
pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap)
text := ocr(pIRandomAccessStream, "en-US")
ObjRelease(pIRandomAccessStream)
DllCall("DeleteObject", "Ptr", hBitmap)
Добрый вечер.
Подскажите пожалуйста UWP API может распознавать геометрические фигуры? Квадрат, круг, прямоугольник, треугольник.
Вряд ли тут кто-то знает все возможности UWP API. Вы можете поизучать их здесь.
fkhlamingo, распозновайте с помощью opencv.
opencv знаю, видел примеры с контурами, но не видел где он определяет к какой фигуре он принадлежит. Ну и таскать библиотеку конечно не хочется, при наличии альтернативы.
Вряд ли тут кто-то знает все возможности UWP API. Вы можете поизучать их здесь.
Изучал прежде чем написать. Но насколько я понял функций распознавания там с гулькин нос.
Ну, если так хотите через uwp и подзапариться, то можете поискать или натренировать сами onnx модель и запустить её через uwp machine learning api.
http://forum.script-coding.com/viewtopic.php?id=16766
А как мне получить эту переменную? Вот я хочу делать скриншот потом искать по скрину цифры и потом делать все тоже самое с другой половиной и искать совпадения.
А как мне получить эту переменную?
Какую?
Код из 13 замечательный. Мне нужно суметь задавать программно регионы поиска, а с преобразованием результатов я думаю проблем не будет.
Malcev, у меня появился вопрос по коду из поста 13.
Перестроить, чтобы поиск производился в нужных мне координатах, а не по действиям мыши, мне удалось. Но к сожалению всё работает в абсолютных координатах, а мне желательно именно для окна. По идее так и чуть быстрее будет. Не нашёл в каком месте кода определяется этот параметр.
Подскажите, пожалуйста!
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться