forked from thqby/ahk2_lib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRapidOcr.ahk
182 lines (174 loc) · 6.79 KB
/
RapidOcr.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/************************************************************************
* @description [RapidOcrOnnx](https://github.com/RapidAI/RapidOcrOnnx)
* A cross platform OCR Library based on PaddleOCR & OnnxRuntime
* @author thqby, RapidAI
* @date 2023/10/28
* @version 1.0.1
* @license Apache-2.0
***********************************************************************/
class RapidOcr {
ptr := 0
/**
* @param {Map|Object} config Set det, rec, cls model location path, keys.txt path, thread number.
* @param {String} [config.models] dir of model files
* @param {String} [config.det] model file name of det
* @param {String} [config.rec] model file name of rec
* @param {String} [config.keys] keys file name
* @param {String} [config.cls] model file name of cls
* @param {Integer} [config.numThread] The thread number, default: 4
* @param {String} dllpath The path of RapidOcrOnnx.dll
* @example
* param := RapidOcr.OcrParam()
* param.doAngle := false ;, param.maxSideLen := 300
* ocr := RapidOcr({ models: A_ScriptDir '\models' })
* MsgBox ocr.ocr_from_file('1.jpg', param)
*/
__New(config?, dllpath?) {
static init := 0
if (!init) {
init := DllCall('LoadLibrary', 'str', dllpath ?? A_LineFile '\..\' (A_PtrSize * 8) 'bit\RapidOcrOnnx.dll', 'ptr')
if (!init)
Throw OSError()
}
if !IsSet(config)
config := { models: A_LineFile '\..\models' }, !FileExist(config.models) && (config.models := unset)
det_model := cls_model := rec_model := keys_dict := '', numThread := 4
for k, v in (config is Map ? config : config.OwnProps()) {
switch k, false {
case 'det', 'cls', 'rec': %k%_model := v
case 'keys', 'dict': keys_dict := v
case 'det_model', 'cls_model', 'rec_model', 'keys_dict', 'numThread': %k% := v
case 'models', 'modelpath':
if !(v ~= '[/\\]$')
v .= '\'
if !keys_dict {
loop files v '*.txt'
if A_LoopFileName ~= 'i)_(keys|dict)[_.]' {
keys_dict := A_LoopFileFullPath
break
}
}
loop files v '*.onnx' {
if RegExMatch(A_LoopFileName, 'i)_(det|cls|rec)[_.]', &m) && !%m[1]%_model
%m[1]%_model := A_LoopFileFullPath
} until det_model && cls_model && rec_model
}
}
for k in ['keys_dict', 'det_model', 'cls_model', 'rec_model']
if !%k% {
if k != 'cls_model'
Throw ValueError('No value is specified: ' k)
} else if !FileExist(%k%)
Throw TargetError('file "' k '" does not exist')
this.ptr := DllCall('RapidOcrOnnx\OcrInit', 'str', det_model, 'str', cls_model, 'str', rec_model, 'str', keys_dict, 'int', numThread, 'ptr')
}
__Delete() => this.ptr && DllCall('RapidOcrOnnx\OcrDestroy', 'ptr', this)
static __cb(i) {
static cbs := [
{ ptr: CallbackCreate(get_text), __Delete: this => CallbackFree(this.ptr) },
{ ptr: CallbackCreate(get_result), __Delete: this => CallbackFree(this.ptr) },
]
return cbs[i]
get_text(userdata, ptext, presult) => %ObjFromPtrAddRef(userdata)% := StrGet(ptext, 'utf-8')
get_result(userdata, ptext, presult) {
result := %ObjFromPtrAddRef(userdata)% := RapidOcr.OcrResult(presult)
result.text := StrGet(ptext, 'utf-8')
return result
}
}
; opencv4.8.0 Mat
ocr_from_mat(mat, param := 0, allresult := false) => DllCall('RapidOcrOnnx\OcrDetectMat', 'ptr', this, 'ptr', mat, 'ptr', param, 'ptr', RapidOcr.__cb(2 - !allresult), 'ptr', ObjPtr(&res)) ? res : ''
; path of pic
ocr_from_file(picpath, param := 0, allresult := false) => DllCall('RapidOcrOnnx\OcrDetectFile', 'ptr', this, 'astr', picpath, 'ptr', param, 'ptr', RapidOcr.__cb(2 - !allresult), 'ptr', ObjPtr(&res)) ? res : ''
; Image binary data
ocr_from_binary(data, size, param := 0, allresult := false) => DllCall('RapidOcrOnnx\OcrDetectBinary', 'ptr', this, 'ptr', data, 'uptr', size, 'ptr', param, 'ptr', RapidOcr.__cb(2 - !allresult), 'ptr', ObjPtr(&res)) ? res : ''
; `struct BITMAP_DATA { void *bits; uint pitch; int width, height, bytespixel;};`
ocr_from_bitmapdata(data, param := 0, allresult := false) => DllCall('RapidOcrOnnx\OcrDetectBitmapData', 'ptr', this, 'ptr', data, 'ptr', param, 'ptr', RapidOcr.__cb(2 - !allresult), 'ptr', ObjPtr(&res)) ? res : ''
class OcrParam extends Buffer {
__New(param?) {
super.__New(42, 0)
p := NumPut('int', 50, 'int', 1024, 'float', 0.6, 'float', 0.3, 'float', 2.0, this)
if !IsSet(param)
return NumPut('int', 1, 'int', 1, p)
for k, v in (param is Map ? param : param.OwnProps())
if this.Base.HasOwnProp(k)
this.%k% := v
}
; default: 50
padding {
get => NumGet(this, 0, 'int')
set => NumPut('int', Value, this, 0)
}
; default: 1024
maxSideLen {
get => NumGet(this, 4, 'int')
set => NumPut('int', Value, this, 4)
}
; default: 0.5
boxScoreThresh {
get => NumGet(this, 8, 'float')
set => NumPut('float', Value, this, 8)
}
; default: 0.3
boxThresh {
get => NumGet(this, 12, 'float')
set => NumPut('float', Value, this, 12)
}
; default: 1.6
unClipRatio {
get => NumGet(this, 16, 'float')
set => NumPut('float', Value, this, 16)
}
; default: false
doAngle {
get => NumGet(this, 20, 'int')
set => NumPut('int', Value, this, 20)
}
; default: false
mostAngle {
get => NumGet(this, 24, 'int')
set => NumPut('int', Value, this, 24)
}
; Output path of image with the boxes
outputPath {
get => StrGet(NumGet(this, 24 + A_PtrSize, 'ptr') || StrPtr(''), 'cp0')
set => (StrPut(Value, this.__outputbuf := Buffer(StrPut(Value, 'cp0')), 'cp0'), NumPut('ptr', this.__outputbuf.Ptr, this, 24 + A_PtrSize))
}
}
class OcrResult extends Array {
__New(ptr) {
this.dbNetTime := NumGet(ptr, 'double')
this.detectTime := NumGet(ptr, 8, 'double')
read_vector(this, &ptr += 16, read_textblock)
align(ptr, begin, to_align) => begin + ((ptr - begin + --to_align) & ~to_align)
read_textblock(&ptr, begin := ptr) => {
boxPoint: read_vector([], &ptr, read_point),
boxScore: read_float(&ptr),
angleIndex: read_int(&ptr),
angleScore: read_float(&ptr),
angleTime: read_double(&ptr := align(ptr, begin, 8)),
text: read_string(&ptr),
charScores: read_vector([], &ptr, read_float),
crnnTime: read_double(&ptr := align(ptr, begin, 8)),
blockTime: read_double(&ptr)
}
read_double(&ptr) => (v := NumGet(ptr, 'double'), ptr += 8, v)
read_float(&ptr) => (v := NumGet(ptr, 'float'), ptr += 4, v)
read_int(&ptr) => (v := NumGet(ptr, 'int'), ptr += 4, v)
read_point(&ptr) => { x: read_int(&ptr), y: read_int(&ptr) }
read_string(&ptr) {
static size := 2 * A_PtrSize + 16
sz := NumGet(ptr + 16, 'uptr'), p := sz < 16 ? ptr : NumGet(ptr, 'ptr'), ptr += size
s := StrGet(p, sz, 'utf-8')
return s
}
read_vector(arr, &ptr, read_element) {
static size := 3 * A_PtrSize
pend := NumGet(ptr, A_PtrSize, 'ptr'), p := NumGet(ptr, 'ptr'), ptr += size
while p < pend
arr.Push(read_element(&p))
return arr
}
}
}
}