@areb0s/ocr-common 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/Ocr.d.ts +15 -0
- package/build/Ocr.js +24 -0
- package/build/Ocr.js.map +1 -0
- package/build/backend/FileUtilsBase.d.ts +3 -0
- package/build/backend/FileUtilsBase.js +6 -0
- package/build/backend/FileUtilsBase.js.map +1 -0
- package/build/backend/ImageRawBase.d.ts +8 -0
- package/build/backend/ImageRawBase.js +14 -0
- package/build/backend/ImageRawBase.js.map +1 -0
- package/build/backend/backend.d.ts +14 -0
- package/build/backend/backend.js +14 -0
- package/build/backend/backend.js.map +1 -0
- package/build/backend/index.d.ts +3 -0
- package/build/backend/index.js +4 -0
- package/build/backend/index.js.map +1 -0
- package/build/backend/splitIntoLineImages.d.ts +2 -0
- package/build/backend/splitIntoLineImages.js +231 -0
- package/build/backend/splitIntoLineImages.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.js +6 -0
- package/build/index.js.map +1 -0
- package/build/models/Detection.d.ts +13 -0
- package/build/models/Detection.js +82 -0
- package/build/models/Detection.js.map +1 -0
- package/build/models/ModelBase.d.ts +14 -0
- package/build/models/ModelBase.js +53 -0
- package/build/models/ModelBase.js.map +1 -0
- package/build/models/Recognition.d.ts +12 -0
- package/build/models/Recognition.js +190 -0
- package/build/models/Recognition.js.map +1 -0
- package/build/models/index.d.ts +2 -0
- package/build/models/index.js +3 -0
- package/build/models/index.js.map +1 -0
- package/build/types/index.d.ts +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/build/types/types.d.ts +67 -0
- package/build/types/types.js +5 -0
- package/build/types/types.js.map +1 -0
- package/package.json +34 -0
- package/src/Ocr.ts +34 -0
- package/src/backend/FileUtilsBase.ts +5 -0
- package/src/backend/ImageRawBase.ts +17 -0
- package/src/backend/backend.ts +29 -0
- package/src/backend/index.ts +3 -0
- package/src/backend/splitIntoLineImages.ts +296 -0
- package/src/index.ts +8 -0
- package/src/models/Detection.ts +96 -0
- package/src/models/ModelBase.ts +74 -0
- package/src/models/Recognition.ts +217 -0
- package/src/models/index.ts +2 -0
- package/src/types/global.d.ts +7 -0
- package/src/types/index.ts +1 -0
- package/src/types/types.ts +90 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import invariant from 'tiny-invariant';
|
|
2
|
+
import { FileUtils, InferenceSession, defaultModels } from '../backend/index.js';
|
|
3
|
+
import { ModelBase } from './ModelBase.js';
|
|
4
|
+
export class Recognition extends ModelBase {
|
|
5
|
+
#dictionary;
|
|
6
|
+
static async create({ models, onnxOptions = {}, ...restOptions }) {
|
|
7
|
+
const recognitionPath = models?.recognitionPath || defaultModels?.recognitionPath;
|
|
8
|
+
invariant(recognitionPath, 'recognitionPath is required');
|
|
9
|
+
const dictionaryPath = models?.dictionaryPath || defaultModels?.dictionaryPath;
|
|
10
|
+
invariant(dictionaryPath, 'dictionaryPath is required');
|
|
11
|
+
const model = await InferenceSession.create(recognitionPath, onnxOptions);
|
|
12
|
+
const dictionaryText = await FileUtils.read(dictionaryPath);
|
|
13
|
+
const dictionary = [...dictionaryText.split('\n'), ' '];
|
|
14
|
+
return new Recognition({ model, options: restOptions }, dictionary);
|
|
15
|
+
}
|
|
16
|
+
constructor(options, dictionary) {
|
|
17
|
+
super(options);
|
|
18
|
+
this.#dictionary = dictionary;
|
|
19
|
+
}
|
|
20
|
+
async run(lineImages, { onnxOptions = {} } = {}) {
|
|
21
|
+
const modelDatas = await Promise.all(
|
|
22
|
+
// Detect text from each line image
|
|
23
|
+
lineImages.map(async (lineImage, index) => {
|
|
24
|
+
// Resize Image to 48px height
|
|
25
|
+
// - height must <= 48
|
|
26
|
+
// - height: 48 is more accurate then 40, but same as 30
|
|
27
|
+
const image = await lineImage.image.resize({
|
|
28
|
+
height: 48,
|
|
29
|
+
});
|
|
30
|
+
this.debugImage(lineImage.image, `out9-line-${index}.jpg`);
|
|
31
|
+
this.debugImage(image, `out9-line-${index}-resized.jpg`);
|
|
32
|
+
// transform image data to model data
|
|
33
|
+
const modelData = this.imageToInput(image, {
|
|
34
|
+
// mean: [0.5, 0.5, 0.5],
|
|
35
|
+
// std: [0.5, 0.5, 0.5],
|
|
36
|
+
});
|
|
37
|
+
return modelData;
|
|
38
|
+
}));
|
|
39
|
+
const allLines = [];
|
|
40
|
+
// console.time('Recognition')
|
|
41
|
+
for (const modelData of modelDatas) {
|
|
42
|
+
// Run model for each line image
|
|
43
|
+
const output = await this.runModel({ modelData, onnxOptions });
|
|
44
|
+
// use Dictoinary to decode output to text
|
|
45
|
+
const lines = await this.decodeText(output);
|
|
46
|
+
allLines.unshift(...lines);
|
|
47
|
+
}
|
|
48
|
+
// console.timeEnd('Recognition')
|
|
49
|
+
const result = calculateBox({ lines: allLines, lineImages });
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
decodeText(output) {
|
|
53
|
+
const data = output;
|
|
54
|
+
const predLen = data.dims[2];
|
|
55
|
+
const line = [];
|
|
56
|
+
let ml = data.dims[0] - 1;
|
|
57
|
+
for (let l = 0; l < data.data.length; l += predLen * data.dims[1]) {
|
|
58
|
+
const predsIdx = [];
|
|
59
|
+
const predsProb = [];
|
|
60
|
+
for (let i = l; i < l + predLen * data.dims[1]; i += predLen) {
|
|
61
|
+
const tmpArr = data.data.slice(i, i + predLen);
|
|
62
|
+
const tmpMax = tmpArr.reduce((a, b) => Math.max(a, b), Number.NEGATIVE_INFINITY);
|
|
63
|
+
const tmpIdx = tmpArr.indexOf(tmpMax);
|
|
64
|
+
predsProb.push(tmpMax);
|
|
65
|
+
predsIdx.push(tmpIdx);
|
|
66
|
+
}
|
|
67
|
+
line[ml] = decode(this.#dictionary, predsIdx, predsProb, true);
|
|
68
|
+
ml--;
|
|
69
|
+
}
|
|
70
|
+
return line;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function decode(dictionary, textIndex, textProb, isRemoveDuplicate) {
|
|
74
|
+
const ignoredTokens = [0];
|
|
75
|
+
const charList = [];
|
|
76
|
+
const confList = [];
|
|
77
|
+
for (let idx = 0; idx < textIndex.length; idx++) {
|
|
78
|
+
if (textIndex[idx] in ignoredTokens) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (isRemoveDuplicate) {
|
|
82
|
+
if (idx > 0 && textIndex[idx - 1] === textIndex[idx]) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
charList.push(dictionary[textIndex[idx] - 1]);
|
|
87
|
+
if (textProb) {
|
|
88
|
+
confList.push(textProb[idx]);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
confList.push(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let text = '';
|
|
95
|
+
let mean = 0;
|
|
96
|
+
if (charList.length) {
|
|
97
|
+
text = charList.join('');
|
|
98
|
+
let sum = 0;
|
|
99
|
+
confList.forEach((item) => {
|
|
100
|
+
sum += item;
|
|
101
|
+
});
|
|
102
|
+
mean = sum / confList.length;
|
|
103
|
+
}
|
|
104
|
+
return { text, mean };
|
|
105
|
+
}
|
|
106
|
+
function calculateBox({ lines, lineImages, }) {
|
|
107
|
+
let mainLine = lines;
|
|
108
|
+
const box = lineImages;
|
|
109
|
+
for (const i in mainLine) {
|
|
110
|
+
const b = box[mainLine.length - Number(i) - 1].box;
|
|
111
|
+
for (const p of b) {
|
|
112
|
+
p[0] = p[0];
|
|
113
|
+
p[1] = p[1];
|
|
114
|
+
}
|
|
115
|
+
mainLine[i]['box'] = b;
|
|
116
|
+
}
|
|
117
|
+
mainLine = mainLine.filter((x) => x.mean >= 0.5);
|
|
118
|
+
mainLine = afAfRec(mainLine);
|
|
119
|
+
return mainLine;
|
|
120
|
+
}
|
|
121
|
+
function afAfRec(lines) {
|
|
122
|
+
const outputLines = [];
|
|
123
|
+
const indexes = new Map();
|
|
124
|
+
for (const index in lines) {
|
|
125
|
+
const box = lines[index].box;
|
|
126
|
+
indexes.set(box, Number(index));
|
|
127
|
+
}
|
|
128
|
+
const groupedBoxes = groupBoxesByMidlineDifference([...indexes.keys()]);
|
|
129
|
+
for (const boxes of groupedBoxes) {
|
|
130
|
+
const texts = [];
|
|
131
|
+
let mean = 0;
|
|
132
|
+
for (const box of boxes) {
|
|
133
|
+
const index = indexes.get(box);
|
|
134
|
+
if (index === undefined) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const line = lines[index];
|
|
138
|
+
texts.push(line.text);
|
|
139
|
+
mean += line.mean;
|
|
140
|
+
}
|
|
141
|
+
let outputBox = undefined;
|
|
142
|
+
if (boxes.at(0) && boxes.at(-1)) {
|
|
143
|
+
outputBox = [boxes.at(0)[0], boxes.at(-1)[1], boxes.at(-1)[2], boxes.at(0)[3]];
|
|
144
|
+
}
|
|
145
|
+
outputLines.push({
|
|
146
|
+
mean: mean / boxes.length,
|
|
147
|
+
text: texts.join(' '),
|
|
148
|
+
box: outputBox,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return outputLines;
|
|
152
|
+
}
|
|
153
|
+
function calculateAverageHeight(boxes) {
|
|
154
|
+
let totalHeight = 0;
|
|
155
|
+
for (const box of boxes) {
|
|
156
|
+
const [[, y1], , [, y2]] = box;
|
|
157
|
+
const height = y2 - y1;
|
|
158
|
+
totalHeight += height;
|
|
159
|
+
}
|
|
160
|
+
return totalHeight / boxes.length;
|
|
161
|
+
}
|
|
162
|
+
function groupBoxesByMidlineDifference(boxes) {
|
|
163
|
+
const averageHeight = calculateAverageHeight(boxes);
|
|
164
|
+
const result = [];
|
|
165
|
+
for (const box of boxes) {
|
|
166
|
+
const [[, y1], , [, y2]] = box;
|
|
167
|
+
const midline = (y1 + y2) / 2;
|
|
168
|
+
const group = result.find((b) => {
|
|
169
|
+
const [[, groupY1], , [, groupY2]] = b[0];
|
|
170
|
+
const groupMidline = (groupY1 + groupY2) / 2;
|
|
171
|
+
return Math.abs(groupMidline - midline) < averageHeight / 2;
|
|
172
|
+
});
|
|
173
|
+
if (group) {
|
|
174
|
+
group.push(box);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
result.push([box]);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const group of result) {
|
|
181
|
+
group.sort((a, b) => {
|
|
182
|
+
const [ltA] = a;
|
|
183
|
+
const [ltB] = b;
|
|
184
|
+
return ltA[0] - ltB[0];
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
result.sort((a, b) => a[0][0][1] - b[0][0][1]);
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=Recognition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Recognition.js","sourceRoot":"","sources":["../../src/models/Recognition.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,MAAM,OAAO,WAAY,SAAQ,SAAS;IACxC,WAAW,CAAY;IAEvB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,WAAW,EAAsB;QAClF,MAAM,eAAe,GAAG,MAAM,EAAE,eAAe,IAAI,aAAa,EAAE,eAAe,CAAA;QACjF,SAAS,CAAC,eAAe,EAAE,6BAA6B,CAAC,CAAA;QACzD,MAAM,cAAc,GAAG,MAAM,EAAE,cAAc,IAAI,aAAa,EAAE,cAAc,CAAA;QAC9E,SAAS,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAA;QACvD,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,eAAe,EAAE,WAAW,CAAC,CAAA;QACzE,MAAM,cAAc,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAC3D,MAAM,UAAU,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAA;QACvD,OAAO,IAAI,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,UAAU,CAAC,CAAA;IACrE,CAAC;IAED,YAAY,OAAgC,EAAE,UAAsB;QAClE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,UAAuB,EAAE,EAAE,WAAW,GAAG,EAAE,KAA0D,EAAE;QAC/G,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG;QAClC,mCAAmC;QACnC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;YACxC,8BAA8B;YAC9B,uBAAuB;YACvB,yDAAyD;YACzD,MAAM,KAAK,GAAG,MAAO,SAAS,CAAC,KAAa,CAAC,MAAM,CAAC;gBAClD,MAAM,EAAE,EAAE;aACX,CAAC,CAAA;YACF,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAC,CAAA;YAC1D,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,KAAK,cAAc,CAAC,CAAA;YAExD,qCAAqC;YACrC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;YACzC,yBAAyB;YACzB,wBAAwB;aACzB,CAAC,CAAA;YACF,OAAO,SAAS,CAAA;QAClB,CAAC,CAAC,CACH,CAAA;QAED,MAAM,QAAQ,GAAW,EAAE,CAAA;QAC3B,8BAA8B;QAC9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,gCAAgC;YAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAA;YAC9D,0CAA0C;YAC1C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAC3C,QAAQ,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA;QAC5B,CAAC;QACD,iCAAiC;QACjC,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA;QAC5D,OAAO,MAAM,CAAA;IACf,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,MAAM,IAAI,GAAG,MAAM,CAAA;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAW,EAAE,CAAA;QACvB,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,MAAM,QAAQ,GAAa,EAAE,CAAA;YAC7B,MAAM,SAAS,GAAa,EAAE,CAAA;YAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC;gBAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAiB,CAAA;gBAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAA;gBAChF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;gBACrC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACtB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACvB,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;YAC9D,EAAE,EAAE,CAAA;QACN,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AAED,SAAS,MAAM,CAAC,UAAoB,EAAE,SAAmB,EAAE,QAAkB,EAAE,iBAA0B;IACvG,MAAM,aAAa,GAAG,CAAC,CAAC,CAAC,CAAA;IACzB,MAAM,QAAQ,GAAG,EAAE,CAAA;IACnB,MAAM,QAAQ,GAAG,EAAE,CAAA;IACnB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,aAAa,EAAE,CAAC;YACpC,SAAQ;QACV,CAAC;QACD,IAAI,iBAAiB,EAAE,CAAC;YACtB,IAAI,GAAG,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrD,SAAQ;YACV,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAC7C,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;IACD,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACxB,IAAI,GAAG,GAAG,CAAC,CAAA;QACX,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACxB,GAAG,IAAI,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QACF,IAAI,GAAG,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAA;IAC9B,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvB,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,KAAK,EACL,UAAU,GAIX;IACC,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,MAAM,GAAG,GAAG,UAAU,CAAA;IACtB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;QAClD,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YACX,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACb,CAAC;QACD,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IACD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAA;IAChD,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC5B,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,OAAO,CAAC,KAAa;IAC5B,MAAM,WAAW,GAAW,EAAE,CAAA;IAC9B,MAAM,OAAO,GAAyB,IAAI,GAAG,EAAE,CAAA;IAC/C,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAQ,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAA;QACjC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,YAAY,GAAG,6BAA6B,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAEvE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,EAAE,CAAA;QAChB,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,SAAQ;YACV,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;YACzB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAA;QACnB,CAAC;QACD,IAAI,SAAS,GAAG,SAAS,CAAA;QACzB,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChC,SAAS,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACpF,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,IAAI,GAAG,KAAK,CAAC,MAAM;YACzB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;YACrB,GAAG,EAAE,SAAS;SACf,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAgB;IAC9C,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,AAAD,EAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAA;QAC9B,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,CAAA;QACtB,WAAW,IAAI,MAAM,CAAA;IACvB,CAAC;IACD,OAAO,WAAW,GAAG,KAAK,CAAC,MAAM,CAAA;AACnC,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAgB;IACrD,MAAM,aAAa,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAA;IACnD,MAAM,MAAM,GAAgB,EAAE,CAAA;IAC9B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,AAAD,EAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAA;QAC9B,MAAM,OAAO,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9B,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,AAAD,EAAG,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,YAAY,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;YAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,OAAO,CAAC,GAAG,aAAa,GAAG,CAAC,CAAA;QAC7D,CAAC,CAAC,CAAA;QACF,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACpB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAClB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACf,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACf,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;QACxB,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAE9C,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { InferenceSession } from 'onnxruntime-common';
|
|
2
|
+
import { ImageRawBase as ImageRaw } from '../backend/ImageRawBase.js';
|
|
3
|
+
import type { splitIntoLineImages } from '../backend/splitIntoLineImages.js';
|
|
4
|
+
export { FileUtilsBase as FileUtils } from '../backend/FileUtilsBase.js';
|
|
5
|
+
export { ImageRaw, InferenceSession };
|
|
6
|
+
export type SplitIntoLineImages = typeof splitIntoLineImages;
|
|
7
|
+
export type ReshapeOptions = {
|
|
8
|
+
mean?: number[];
|
|
9
|
+
std?: number[];
|
|
10
|
+
};
|
|
11
|
+
export type ImageRawData = {
|
|
12
|
+
data: Uint8Array | Uint8ClampedArray;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Browser-specific image input types
|
|
18
|
+
* Supports various browser image sources that can be converted to ImageRawData
|
|
19
|
+
*/
|
|
20
|
+
export type BrowserImageInput = string | ImageRawData | ImageBitmap | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement;
|
|
21
|
+
export type ModelData = {
|
|
22
|
+
data: number[] | Uint8Array;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
};
|
|
26
|
+
export type Size = {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
export type SizeOption = {
|
|
31
|
+
width?: number;
|
|
32
|
+
height?: number;
|
|
33
|
+
fit?: 'contain' | 'cover' | 'fill' | 'inside' | 'outside';
|
|
34
|
+
};
|
|
35
|
+
export type LineImage = {
|
|
36
|
+
image: ImageRaw;
|
|
37
|
+
box: number[][];
|
|
38
|
+
};
|
|
39
|
+
export type Region = {
|
|
40
|
+
left: number;
|
|
41
|
+
top: number;
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
};
|
|
45
|
+
export type Line = {
|
|
46
|
+
text: string;
|
|
47
|
+
mean: number;
|
|
48
|
+
box?: number[][];
|
|
49
|
+
};
|
|
50
|
+
export type Dictionary = string[];
|
|
51
|
+
export type Point = [x: number, y: number];
|
|
52
|
+
export interface ModelBaseConstructorArg {
|
|
53
|
+
model: InferenceSession;
|
|
54
|
+
options: ModelBaseOptions;
|
|
55
|
+
}
|
|
56
|
+
export interface ModelBaseOptions {
|
|
57
|
+
isDebug?: boolean;
|
|
58
|
+
debugOutputDir?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ModelCreateOptions extends ModelBaseOptions {
|
|
61
|
+
models?: {
|
|
62
|
+
detectionPath: string;
|
|
63
|
+
recognitionPath: string;
|
|
64
|
+
dictionaryPath: string;
|
|
65
|
+
};
|
|
66
|
+
onnxOptions?: InferenceSession.SessionOptions;
|
|
67
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { InferenceSession } from 'onnxruntime-common';
|
|
2
|
+
import { ImageRawBase as ImageRaw } from '../backend/ImageRawBase.js';
|
|
3
|
+
export { FileUtilsBase as FileUtils } from '../backend/FileUtilsBase.js';
|
|
4
|
+
export { ImageRaw, InferenceSession };
|
|
5
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,YAAY,IAAI,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAGvE,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,MAAM,+BAA+B,CAAA;AAC1E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@areb0s/ocr-common",
|
|
3
|
+
"description": "Fork of @gutenye/ocr-common with ImageBitmap support. Shared OCR library for Browser/Node based on PaddleOCR and ONNX runtime.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/areb0s/ocr.git",
|
|
10
|
+
"directory": "packages/common"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"bun": "./src/index.ts",
|
|
15
|
+
"react-native": "./src/index.ts",
|
|
16
|
+
"default": "./build/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./splitIntoLineImages": {
|
|
19
|
+
"bun": "./src/backend/splitIntoLineImages.ts",
|
|
20
|
+
"react-native": "./src/backend/splitIntoLineImages.ts",
|
|
21
|
+
"default": "./build/backend/splitIntoLineImages.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": ["src", "build", "tsconfig.json", "!**/__tests__"],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "npx tsc --project tsconfig.build.json && npx tsc-alias --project tsconfig.build.json",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"tiny-invariant": "^1.3.3",
|
|
31
|
+
"@techstark/opencv-js": "^4.9.0-release.3",
|
|
32
|
+
"js-clipper": "^1.0.1"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/Ocr.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ImageRawData, BrowserImageInput, ModelCreateOptions } from '#common/types'
|
|
2
|
+
import { Detection, Recognition } from './models'
|
|
3
|
+
|
|
4
|
+
export class Ocr {
|
|
5
|
+
static async create(options: ModelCreateOptions = {}) {
|
|
6
|
+
const detection = await Detection.create(options)
|
|
7
|
+
const recognition = await Recognition.create(options)
|
|
8
|
+
return new Ocr({ detection, recognition })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#detection: Detection
|
|
12
|
+
#recognition: Recognition
|
|
13
|
+
|
|
14
|
+
constructor({
|
|
15
|
+
detection,
|
|
16
|
+
recognition,
|
|
17
|
+
}: {
|
|
18
|
+
detection: Detection
|
|
19
|
+
recognition: Recognition
|
|
20
|
+
}) {
|
|
21
|
+
this.#detection = detection
|
|
22
|
+
this.#recognition = recognition
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async detect(image: string | ImageRawData | BrowserImageInput, options = {}) {
|
|
26
|
+
const { lineImages, resizedImageWidth, resizedImageHeight } = await this.#detection.run(image, options)
|
|
27
|
+
const texts = await this.#recognition.run(lineImages, options)
|
|
28
|
+
return {
|
|
29
|
+
texts,
|
|
30
|
+
resizedImageWidth,
|
|
31
|
+
resizedImageHeight,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ImageRawData } from '#common/types'
|
|
2
|
+
|
|
3
|
+
export class ImageRawBase {
|
|
4
|
+
data: ImageRawData['data']
|
|
5
|
+
width: ImageRawData['width']
|
|
6
|
+
height: ImageRawData['height']
|
|
7
|
+
|
|
8
|
+
constructor({ data, width, height }: ImageRawData) {
|
|
9
|
+
this.data = data
|
|
10
|
+
this.width = width
|
|
11
|
+
this.height = height
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getImageRawData(): ImageRawData {
|
|
15
|
+
return { data: this.data, width: this.width, height: this.height }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FileUtils as FileUtilsType,
|
|
3
|
+
ImageRaw as ImageRawType,
|
|
4
|
+
InferenceSession as InferenceSessionType,
|
|
5
|
+
ModelCreateOptions as ModelCreateOptionsType,
|
|
6
|
+
SplitIntoLineImages as SplitIntoLineImagesType,
|
|
7
|
+
} from '#common/types'
|
|
8
|
+
|
|
9
|
+
let FileUtils: FileUtilsType | any = undefined as unknown as FileUtilsType
|
|
10
|
+
let ImageRaw: ImageRawType | any = undefined as unknown as ImageRawType
|
|
11
|
+
let InferenceSession: InferenceSessionType | any = undefined as unknown as InferenceSessionType
|
|
12
|
+
let splitIntoLineImages: SplitIntoLineImagesType = undefined as unknown as SplitIntoLineImagesType
|
|
13
|
+
let defaultModels: ModelCreateOptionsType['models'] = undefined as unknown as ModelCreateOptionsType['models']
|
|
14
|
+
|
|
15
|
+
export function registerBackend(backend: {
|
|
16
|
+
FileUtils: FileUtilsType
|
|
17
|
+
ImageRaw: ImageRawType | any
|
|
18
|
+
InferenceSession: InferenceSessionType | any
|
|
19
|
+
splitIntoLineImages: SplitIntoLineImagesType
|
|
20
|
+
defaultModels: ModelCreateOptionsType['models']
|
|
21
|
+
}) {
|
|
22
|
+
FileUtils = backend.FileUtils
|
|
23
|
+
ImageRaw = backend.ImageRaw
|
|
24
|
+
InferenceSession = backend.InferenceSession
|
|
25
|
+
splitIntoLineImages = backend.splitIntoLineImages
|
|
26
|
+
defaultModels = backend.defaultModels
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { FileUtils, ImageRaw, InferenceSession, splitIntoLineImages, defaultModels }
|