esearch-ocr
Advanced tools
Comparing version 4.1.2 to 4.1.5
@@ -1,106 +0,355 @@ | ||
var d = require("opencv.js"), I, T = !0, F, H, _, E = 960, y = 48, R = 320, O = [NaN, NaN]; | ||
async function ct(t) { | ||
return I = t.ort, T = t.dev, F = await I.InferenceSession.create(t.detPath), H = await I.InferenceSession.create(t.recPath), _ = t.dic.split(/\r\n|\r|\n/), t.maxSide && (E = t.maxSide), t.imgh && (y = t.imgh), t.imgw && (R = t.imgw), t.detShape && (O = t.detShape), new Promise((o) => o(!0)); | ||
var St = Object.defineProperty; | ||
var Pt = (t, e, n) => e in t ? St(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n; | ||
var ot = (t, e, n) => (Pt(t, typeof e != "symbol" ? e + "" : e, n), n); | ||
function H(t) { | ||
return t > 0 ? Math.floor(t) : Math.ceil(t); | ||
} | ||
async function at(t) { | ||
console.time(), t.height, t.width; | ||
let { transposedData: o, image: c } = K(t, O[0], O[1]); | ||
const n = await U(o, c, F); | ||
let a = Q(n.data, n.dims[3], n.dims[2], t), r = []; | ||
for (let e of it(a)) { | ||
let { b: s, imgH: i, imgW: l } = e; | ||
const h = await J(s, i, l, H); | ||
_.at(-1) == "" ? _[_.length - 1] = " " : _.push(" "), r = rt(h, _).concat(r); | ||
function _t(t, e, n) { | ||
return Math.max(e, Math.min(t, n)); | ||
} | ||
function at(t, e, n) { | ||
let o = it(t), c = document.createElement("canvas"); | ||
return c.width = e, c.height = n, c.getContext("2d").scale(e / t.width, n / t.height), c.getContext("2d").drawImage(o, 0, 0), c.getContext("2d").getImageData(0, 0, e, n); | ||
} | ||
function it(t, e, n) { | ||
let o = document.createElement("canvas"); | ||
return o.width = e || t.width, o.height = n || t.height, o.getContext("2d").putImageData(t, 0, 0), o; | ||
} | ||
function lt(t, e, n) { | ||
const o = t.data, c = [], s = [], i = []; | ||
let a = 0, r = 0; | ||
for (let l = 0; l < o.length; l += 4) | ||
i[r] || (i[r] = []), s[r] || (s[r] = []), c[r] || (c[r] = []), c[r][a] = (o[l] / 255 - e[0]) / n[0], s[r][a] = (o[l + 1] / 255 - e[1]) / n[1], i[r][a] = (o[l + 2] / 255 - e[2]) / n[2], a++, a == t.width && (a = 0, r++); | ||
return [i, s, c]; | ||
} | ||
class yt { | ||
constructor(e) { | ||
ot(this, "tl", []); | ||
ot(this, "name"); | ||
this.name = e; | ||
} | ||
for (let e in r) { | ||
let s = a[r.length - Number(e) - 1].box; | ||
for (let i of s) | ||
i[0] = i[0], i[1] = i[1]; | ||
r[e].box = s; | ||
l(e) { | ||
const n = performance.now(); | ||
this.tl.push({ t: e, n }); | ||
let o = []; | ||
for (let s = 1; s < this.tl.length; s++) { | ||
const i = this.tl[s].n - this.tl[s - 1].n, a = this.tl[s - 1].t; | ||
let r = o.find((l) => l.n === a); | ||
r ? (r.c++, r.d += i) : o.push({ d: i, n: a, c: 1 }); | ||
} | ||
const c = []; | ||
for (let s of o) { | ||
const i = s.c > 1 ? `${s.n}x${s.c}` : s.n; | ||
c.push(`${i} ${s.d}`); | ||
} | ||
c.push(this.tl.at(-1).t), console.log(`${this.name} ${o.map((s) => s.d).reduce((s, i) => s + i, 0)}ms: `, c.join(" ")); | ||
} | ||
return r = r.filter((e) => e.mean >= 0.5), r = st(r), console.log(r), console.timeEnd(), r; | ||
} | ||
async function U(t, o, c) { | ||
let n = t.flat(1 / 0); | ||
const a = Float32Array.from(n), r = new I.Tensor("float32", a, [1, 3, o.height, o.width]); | ||
let e = {}; | ||
return e[c.inputNames[0]] = r, (await c.run(e))[c.outputNames[0]]; | ||
async function Et(t, e, n, o) { | ||
let c = t.height, s = t.width, i = Bt(t, 800, 608); | ||
const a = await Dt(i.transposedData, i.image, e, n); | ||
return console.log(a), Tt(a, s, c, o); | ||
} | ||
async function J(t, o, c, n) { | ||
const a = Float32Array.from(t.flat(1 / 0)), r = new I.Tensor("float32", a, [t.length, 3, o, c]); | ||
let e = {}; | ||
return e[n.inputNames[0]] = r, (await n.run(e))[n.outputNames[0]]; | ||
async function Dt(t, e, n, o) { | ||
let c = t.flat(1 / 0); | ||
const s = Float32Array.from(c), i = new n.Tensor("float32", s, [1, 3, e.height, e.width]); | ||
let a = {}; | ||
a[o.inputNames[0]] = i; | ||
const r = await o.run(a); | ||
return Object.values(r); | ||
} | ||
function v(t, o, c) { | ||
let n = document.createElement("canvas"); | ||
return n.width = o || t.width, n.height = c || t.height, n.getContext("2d").putImageData(t, 0, 0), n; | ||
function Bt(t, e, n) { | ||
t.height, t.width; | ||
let o = e, c = n; | ||
return o = Math.max(Math.round(o / 32) * 32, 32), c = Math.max(Math.round(c / 32) * 32, 32), t = at(t, c, o), { transposedData: lt(t, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), image: t }; | ||
} | ||
function W(t, o, c) { | ||
let n = v(t), a = document.createElement("canvas"); | ||
return a.width = o, a.height = c, a.getContext("2d").scale(o / t.width, c / t.height), a.getContext("2d").drawImage(n, 0, 0), a.getContext("2d").getImageData(0, 0, o, c); | ||
function Tt(t, e, n, o) { | ||
const c = [8, 16, 32, 64], s = 0.4, i = 0.5, a = 1e3, r = 100, l = [], h = [], f = t.length / 2; | ||
for (let g = 0; g < f; g++) | ||
l.push(t[g]), h.push(t[g + f]); | ||
const m = H(h[0].dims.at(-1) / 4 - 1); | ||
let p = [], _ = []; | ||
const b = [], M = [800, 608], w = [800 / n, 608 / e], N = [], O = []; | ||
for (let g = 0; g < c.length; g++) { | ||
const I = c[g], S = h[g], C = l[g], T = 800 / I, D = 608 / I, v = Array.from({ length: Math.ceil(T) }, (u, x) => x), y = Array.from({ length: Math.ceil(D) }, (u, x) => x), [P, Y] = Vt(y, v), Z = Y.flat().map((u) => (u + 0.5) * I), ht = P.flat().map((u) => (u + 0.5) * I), tt = []; | ||
for (let u in Z) | ||
tt.push([ht[u], Z[u], ht[u], Z[u]]); | ||
const G = m + 1, et = S.size / G, ut = []; | ||
for (let u = 0; u < et; u++) { | ||
let x = S.data.slice(u * G, (u + 1) * G); | ||
const R = Ot(Array.from(x)); | ||
for (let J = 0; J < G; J++) | ||
R[J] *= J; | ||
ut.push(R); | ||
} | ||
const ft = [], It = et / 4; | ||
for (let u = 0; u < et; u++) { | ||
let x = 0; | ||
for (let R = 0; R < G; R++) | ||
x += ut[u][R]; | ||
x *= I, ft.push(x); | ||
} | ||
const L = [], dt = C.dims[1], q = C.dims[2]; | ||
for (let u = 0; u < dt; u++) { | ||
const x = C.data.slice(u * q, (u + 1) * q); | ||
L.push([u, Math.max(...Array.from(x))]); | ||
} | ||
L.sort((u, x) => x[1] - u[1]); | ||
const nt = [], pt = [], mt = []; | ||
for (let u = 0; u < Math.min(tt.length, a); u++) | ||
nt[u] = tt[L[u][0]]; | ||
for (let u = 0; u < Math.min(dt, a); u++) { | ||
const x = C.data.slice( | ||
L[u][0] * q, | ||
(L[u][0] + 1) * q | ||
); | ||
pt[u] = Array.from(x); | ||
} | ||
for (let u = 0; u < Math.min(It, a); u++) { | ||
const x = ft.slice(L[u][0] * 4, (L[u][0] + 1) * 4); | ||
mt[u] = Array.from(x); | ||
} | ||
const gt = [], vt = [-1, -1, 1, 1]; | ||
for (let u in nt) { | ||
const x = []; | ||
for (let R = 0; R < 4; R++) | ||
x.push(nt[u][R] + vt[R] * mt[u][R]); | ||
gt.push(x); | ||
} | ||
O.push(pt), N.push(gt); | ||
} | ||
const E = N.flat(), X = O.flat(), $ = [], U = []; | ||
for (let g = 0; g < X[0].length; g++) { | ||
const I = X.map((y) => y[g]), S = I.map((y) => y > s), C = I.filter((y, P) => S[P]); | ||
if (C.length === 0) | ||
continue; | ||
const D = E.filter((y, P) => S[P]).map((y, P) => [...y, C[P]]), v = kt( | ||
D, | ||
i, | ||
// NMS的IoU阈值 | ||
r | ||
// 每个类别保留的最大目标框数 | ||
); | ||
$.push(v), U.push(...Array(v.length).fill(g)); | ||
} | ||
if ($.length === 0) | ||
_.push([]), p.push(0); | ||
else { | ||
const g = [], I = M, S = [w[1], w[0], w[1], w[0]], C = [], T = []; | ||
$.flat().forEach((v, y) => { | ||
C.push(v.slice(0, 4)), T.push(v[4]); | ||
}); | ||
const D = Lt(C, I); | ||
C.forEach((v, y) => { | ||
D[y].forEach((P, Y) => { | ||
console.log(P, S[Math.floor(Y / 2)]), D[y][Y] = P / S[Y]; | ||
}), g.push([...D[y], T[y]]); | ||
}), _.push(g.map((v, y) => [U[y], v[4], ...v.slice(0, 4)])), p.push(U.length); | ||
} | ||
const A = _.flat(); | ||
p = p.map((g) => g); | ||
const At = o; | ||
return A.forEach((g, I) => { | ||
const S = H(g[0]), C = g.slice(2); | ||
g[1]; | ||
const T = At[S], D = { bbox: C, label: T }; | ||
b.push(D); | ||
}), console.log(b), b; | ||
} | ||
function K(t, o, c) { | ||
let n = 1, a = t.height, r = t.width; | ||
Math.max(a, r) > E && (a > r ? n = E / a : n = E / r); | ||
let e = o || a * n, s = c || r * n; | ||
e = Math.max(Math.round(e / 32) * 32, 32), s = Math.max(Math.round(s / 32) * 32, 32), t = W(t, s, e); | ||
const i = j(t, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]); | ||
if (console.log(t), T) { | ||
let l = v(t); | ||
function K(t, e, n) { | ||
return Math.max(Math.min(t, n), e); | ||
} | ||
function Lt(t, e) { | ||
const n = e[1], o = e[0], c = t.length; | ||
if (c > 0) { | ||
const s = [], i = [], a = [], r = []; | ||
for (let h = 0; h < c; h++) { | ||
const [f, m, p, _] = t[h]; | ||
s.push(Math.min(f, p)), i.push(Math.min(m, _)), a.push(Math.max(f, p)), r.push(Math.max(m, _)); | ||
} | ||
const l = []; | ||
for (let h in s) | ||
l.push([ | ||
K(s[h], 0, n), | ||
K(i[h], 0, o), | ||
K(a[h], 0, n), | ||
K(r[h], 0, o) | ||
]); | ||
return l; | ||
} else | ||
return t; | ||
} | ||
function kt(t, e, n = -1, o = 200) { | ||
const c = t.map((r) => r[4]), s = t.map((r) => r.slice(0, 4)), i = []; | ||
let a = c.map((r, l) => l); | ||
for (a = a.sort((r, l) => c[l] - c[r]).slice(0, o).reverse(); a.length > 0; ) { | ||
const r = a.at(-1); | ||
if (i.push(r), n > 0 && i.length === n || a.length === 1) | ||
break; | ||
const l = s[r]; | ||
a = a.slice(0, a.length - 1); | ||
const h = a.map((m) => s[m]), f = zt(h, [l]); | ||
a = a.filter((m, p) => f[p] <= e); | ||
} | ||
return i.map((r) => t[r]); | ||
} | ||
function zt(t, e, n = 1e-5) { | ||
const o = t.map((r, l) => { | ||
var h, f; | ||
return [ | ||
Math.max(r[0], ((h = e[l]) == null ? void 0 : h[0]) ?? -1 / 0), | ||
Math.max(r[1], ((f = e[l]) == null ? void 0 : f[1]) ?? -1 / 0) | ||
]; | ||
}), c = t.map((r, l) => { | ||
var h, f; | ||
return [ | ||
Math.min(r[2], ((h = e[l]) == null ? void 0 : h[2]) ?? -1 / 0), | ||
Math.min(r[3], ((f = e[l]) == null ? void 0 : f[3]) ?? -1 / 0) | ||
]; | ||
}), s = Nt(o, c), i = t.map((r) => (r[2] - r[0]) * (r[3] - r[1])), a = e.map((r) => (r[2] - r[0]) * (r[3] - r[1])); | ||
return s.map((r, l) => r / (i[l] + a[l] - r + n)); | ||
} | ||
function Nt(t, e) { | ||
return t.map((o, c) => [ | ||
Math.max(e[c][0] - o[0], 0), | ||
Math.max(e[c][1] - o[1], 0) | ||
]).map((o) => o[0] * o[1]); | ||
} | ||
function Ot(t) { | ||
const e = Math.max(...t), n = t.map((s) => Math.exp(s - e)), o = n.reduce((s, i) => s + i, 0); | ||
return n.map((s) => s / o); | ||
} | ||
function Vt(...t) { | ||
const e = [[], [], []]; | ||
for (let n in t[1]) | ||
e[0].push(t[0]); | ||
for (let n in t[1]) { | ||
let o = []; | ||
for (let c in t[0]) | ||
o.push(t[1][n]); | ||
e[1].push(o); | ||
} | ||
return e; | ||
} | ||
var d = require("opencv.js"), z; | ||
const B = new yt("t"), k = new yt("af_det"); | ||
var j = !0, Mt, bt, ct, V, Q = 960, W = 48, rt = [NaN, NaN], Ct; | ||
async function oe(t) { | ||
var e; | ||
return z = t.ort, j = t.dev, j || (B.l = () => { | ||
}, k.l = () => { | ||
}), t.detPath && (Mt = await z.InferenceSession.create(t.detPath)), t.recPath && (bt = await z.InferenceSession.create(t.recPath)), t.layoutPath && (ct = await z.InferenceSession.create(t.layoutPath)), V = t.dic.split(/\r\n|\r|\n/), V.at(-1) === "" ? V[V.length - 1] = " " : V.push(" "), Ct = (e = t.layoutDic) == null ? void 0 : e.split(/\r\n|\r|\n/), t.maxSide && (Q = t.maxSide), t.imgh && (W = t.imgh), t.imgw && t.imgw, t.detShape && (rt = t.detShape), new Promise((n) => n(!0)); | ||
} | ||
async function se(t) { | ||
B.l(""), ct && await Et(t, z, ct, Ct); | ||
const e = await Ft(t); | ||
let n = await Ht(e); | ||
return n = ee(n), console.log(n), B.l("end"), n; | ||
} | ||
async function Ft(t) { | ||
let e = t.height, n = t.width; | ||
const o = 0.6, c = e, s = n; | ||
if (c < s * o || s < c * o) { | ||
c < s * o && (e = Math.floor(s * o)), s < c * o && (n = Math.floor(c * o)); | ||
const h = document.createElement("canvas"), f = h.getContext("2d"); | ||
h.width = n, h.height = e, f.putImageData(t, 0, 0), t = f.getImageData(0, 0, n, e); | ||
} | ||
B.l("pre_det"); | ||
let { transposedData: i, image: a } = Ut(t, rt[0], rt[1]); | ||
B.l("det"); | ||
const r = await jt(i, a, Mt); | ||
return B.l("aft_det"), Yt(r.data, r.dims[3], r.dims[2], t); | ||
} | ||
async function Ht(t) { | ||
let e = []; | ||
B.l("bf_rec"); | ||
const o = Zt(t).map(async (s) => { | ||
const { b: i, imgH: a, imgW: r } = s, l = await $t(i, a, r, bt); | ||
return te(l, V); | ||
}); | ||
e = (await Promise.all(o)).flat().toReversed(), B.l("rec_end"); | ||
for (let s in e) { | ||
let i = t[e.length - Number(s) - 1].box; | ||
for (let a of i) | ||
a[0] = a[0], a[1] = a[1]; | ||
e[s].box = i; | ||
} | ||
return e = e.filter((s) => s.mean >= 0.5), e; | ||
} | ||
async function jt(t, e, n) { | ||
const o = Float32Array.from(t.flat(3)), c = new z.Tensor("float32", o, [1, 3, e.height, e.width]); | ||
let s = {}; | ||
return s[n.inputNames[0]] = c, (await n.run(s))[n.outputNames[0]]; | ||
} | ||
async function $t(t, e, n, o) { | ||
const c = Float32Array.from(t.flat(3)), s = new z.Tensor("float32", c, [1, 3, e, n]); | ||
let i = {}; | ||
return i[o.inputNames[0]] = s, (await o.run(i))[o.outputNames[0]]; | ||
} | ||
function Ut(t, e, n) { | ||
let o = 1, c = t.height, s = t.width; | ||
Math.max(c, s) > Q && (c > s ? o = Q / c : o = Q / s); | ||
let i = e || c * o, a = n || s * o; | ||
i = Math.max(Math.round(i / 32) * 32, 32), a = Math.max(Math.round(a / 32) * 32, 32), t = at(t, a, i); | ||
const r = lt(t, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]); | ||
if (console.log(t), j) { | ||
let l = it(t); | ||
document.body.append(l); | ||
} | ||
return { transposedData: i, image: t }; | ||
return { transposedData: r, image: t }; | ||
} | ||
function Q(t, o, c, n) { | ||
var a = new ImageData(o, c); | ||
for (let h in t) { | ||
let u = Number(h) * 4; | ||
const g = t[h] > 0.3 ? 255 : 0; | ||
a.data[u] = a.data[u + 1] = a.data[u + 2] = g, a.data[u + 3] = 255; | ||
function Yt(t, e, n, o) { | ||
k.l(""); | ||
const c = new ImageData(e, n); | ||
for (let l = 0; l < t.length; l++) { | ||
const h = l * 4, f = t[l] > 0.3 ? 255 : 0; | ||
c.data[h] = c.data[h + 1] = c.data[h + 2] = f, c.data[h + 3] = 255; | ||
} | ||
let r = v(a), e = [], s = d.imread(r); | ||
d.cvtColor(s, s, d.COLOR_RGBA2GRAY, 0); | ||
let i = new d.MatVector(), l = new d.Mat(); | ||
d.findContours(s, i, l, d.RETR_LIST, d.CHAIN_APPROX_SIMPLE); | ||
for (let h = 0; h < i.size(); h++) { | ||
let u = function(p, q, G) { | ||
return Math.max(q, Math.min(p, G)); | ||
}, g = 3, m = i.get(h), { points: f, sside: w } = B(m); | ||
if (w < g) | ||
k.l("edge"); | ||
let s = [], i = Rt(c); | ||
d.cvtColor(i, i, d.COLOR_RGBA2GRAY, 0); | ||
let a = new d.MatVector(), r = new d.Mat(); | ||
d.findContours(i, a, r, d.RETR_LIST, d.CHAIN_APPROX_SIMPLE); | ||
for (let l = 0; l < a.size(); l++) { | ||
k.l("get_box"); | ||
let h = 3, f = a.get(l), { points: m, sside: p } = wt(f); | ||
if (p < h) | ||
continue; | ||
let x = tt(f); | ||
const b = new d.matFromArray(x.length / 2, 1, d.CV_32SC2, x), S = B(b); | ||
let M = S.points; | ||
if (S.sside < g + 2) | ||
let _ = Xt(m); | ||
const b = new d.matFromArray(_.length / 2, 1, d.CV_32SC2, _), M = wt(b); | ||
let w = M.points; | ||
if (M.sside < h + 2) | ||
continue; | ||
let z = n.width / o, Y = n.height / c; | ||
for (let p = 0; p < M.length; p++) | ||
M[p][0] *= z, M[p][1] *= Y; | ||
let A = nt(M); | ||
A.forEach((p) => { | ||
p[0] = u(Math.round(p[0]), 0, n.width), p[1] = u(Math.round(p[1]), 0, n.height); | ||
let N = o.width / e, O = o.height / n; | ||
for (let A = 0; A < w.length; A++) | ||
w[A][0] *= N, w[A][1] *= O; | ||
k.l("order"); | ||
let E = Jt(w); | ||
E.forEach((A) => { | ||
A[0] = _t(Math.round(A[0]), 0, o.width), A[1] = _t(Math.round(A[1]), 0, o.height); | ||
}); | ||
let V = P(C(A[0], A[1])), X = P(C(A[0], A[3])); | ||
if (V <= 3 || X <= 3) | ||
let X = H(F(E[0], E[1])), $ = H(F(E[0], E[3])); | ||
if (X <= 3 || $ <= 3) | ||
continue; | ||
let k = v(n), N = ot(k, M); | ||
e.push({ box: M, img: N.getContext("2d").getImageData(0, 0, N.width, N.height) }); | ||
k.l("crop"); | ||
let U = Kt(o, w); | ||
s.push({ box: w, img: U }); | ||
} | ||
return console.log(e), s.delete(), i.delete(), l.delete(), s = i = l = null, e; | ||
return k.l("e"), console.log(s), i.delete(), a.delete(), r.delete(), i = a = r = null, s; | ||
} | ||
const D = require("js-clipper"); | ||
function Z(t) { | ||
let o = -1, c = t.length, n, a = t[c - 1], r = 0; | ||
for (; ++o < c; ) | ||
n = a, a = t[o], r += n[1] * a[0] - n[0] * a[1]; | ||
return r / 2; | ||
const st = require("js-clipper"); | ||
function Gt(t) { | ||
let e = -1, n = t.length, o, c = t[n - 1], s = 0; | ||
for (; ++e < n; ) | ||
o = c, c = t[e], s += o[1] * c[0] - o[0] * c[1]; | ||
return s / 2; | ||
} | ||
function $(t) { | ||
let o = -1, c = t.length, n = t[c - 1], a, r, e = n[0], s = n[1], i = 0; | ||
for (; ++o < c; ) | ||
a = e, r = s, n = t[o], e = n[0], s = n[1], a -= e, r -= s, i += Math.hypot(a, r); | ||
return i; | ||
function Wt(t) { | ||
let e = -1, n = t.length, o = t[n - 1], c, s, i = o[0], a = o[1], r = 0; | ||
for (; ++e < n; ) | ||
c = i, s = a, o = t[e], i = o[0], a = o[1], c -= i, s -= a, r += Math.hypot(c, s); | ||
return r; | ||
} | ||
function tt(t) { | ||
const c = Math.abs(Z(t)), n = $(t), a = c * 1.5 / n, r = []; | ||
function Xt(t) { | ||
const n = Math.abs(Gt(t)), o = Wt(t), c = n * 1.5 / o, s = []; | ||
t.forEach((l) => { | ||
@@ -111,43 +360,40 @@ const h = { | ||
}; | ||
h.X = l[0], h.Y = l[1], r.push(h); | ||
h.X = l[0], h.Y = l[1], s.push(h); | ||
}); | ||
const e = new D.ClipperOffset(); | ||
e.AddPath(r, D.JoinType.jtRound, D.EndType.etClosedPolygon); | ||
const s = []; | ||
e.Execute(s, a); | ||
let i = []; | ||
return s[0] && s[0].forEach((l) => { | ||
i.push([l.X, l.Y]); | ||
}), i = [].concat(...i), i; | ||
const i = new st.ClipperOffset(); | ||
i.AddPath(s, st.JoinType.jtRound, st.EndType.etClosedPolygon); | ||
const a = []; | ||
i.Execute(a, c); | ||
let r = []; | ||
return a[0] && a[0].forEach((l) => { | ||
r.push([l.X, l.Y]); | ||
}), r = [].concat(...r), r; | ||
} | ||
function et(t, o, c) { | ||
const n = o.width, a = o.height, r = c * Math.PI / 180, e = Math.cos(r), s = Math.sin(r), i = t.x, l = t.y, h = n * 0.5, u = a * 0.5, g = [], m = i - h * e + u * s, f = l - h * s - u * e; | ||
g.push([m, f]); | ||
const w = i + h * e + u * s, x = l + h * s - u * e; | ||
g.push([w, x]); | ||
const b = i + h * e - u * s, S = l + h * s + u * e; | ||
g.push([b, S]); | ||
const M = i - h * e - u * s, z = l - h * s + u * e; | ||
return g.push([M, z]), g; | ||
function qt(t, e, n) { | ||
const o = e.width, c = e.height, s = n * Math.PI / 180, i = Math.cos(s), a = Math.sin(s), r = t.x, l = t.y, h = o * 0.5, f = c * 0.5, m = [], p = r - h * i + f * a, _ = l - h * a - f * i; | ||
m.push([p, _]); | ||
const b = r + h * i + f * a, M = l + h * a - f * i; | ||
m.push([b, M]); | ||
const w = r + h * i - f * a, N = l + h * a + f * i; | ||
m.push([w, N]); | ||
const O = r - h * i - f * a, E = l - h * a + f * i; | ||
return m.push([O, E]), m; | ||
} | ||
function B(t) { | ||
const o = d.minAreaRect(t), c = Array.from(et(o.center, o.size, o.angle)).sort( | ||
function wt(t) { | ||
const e = d.minAreaRect(t), n = Array.from(qt(e.center, e.size, e.angle)).sort( | ||
(l, h) => l[0] - h[0] | ||
); | ||
let n = 0, a = 1, r = 2, e = 3; | ||
c[1][1] > c[0][1] ? (n = 0, e = 1) : (n = 1, e = 0), c[3][1] > c[2][1] ? (a = 2, r = 3) : (a = 3, r = 2); | ||
const s = [c[n], c[a], c[r], c[e]], i = Math.min(o.size.height, o.size.width); | ||
return { points: s, sside: i }; | ||
let o = 0, c = 1, s = 2, i = 3; | ||
n[1][1] > n[0][1] ? (o = 0, i = 1) : (o = 1, i = 0), n[3][1] > n[2][1] ? (c = 2, s = 3) : (c = 3, s = 2); | ||
const a = [n[o], n[c], n[s], n[i]], r = Math.min(e.size.height, e.size.width); | ||
return { points: a, sside: r }; | ||
} | ||
function P(t) { | ||
return t > 0 ? Math.floor(t) : Math.ceil(t); | ||
function xt(t) { | ||
return t.flat(); | ||
} | ||
function L(t) { | ||
return t.toString().split(",").map((o) => +o); | ||
function F(t, e) { | ||
return Math.sqrt(Math.pow(t[0] - e[0], 2) + Math.pow(t[1] - e[1], 2)); | ||
} | ||
function C(t, o) { | ||
return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2)); | ||
} | ||
function nt(t) { | ||
const o = [ | ||
function Jt(t) { | ||
const e = [ | ||
[0, 0], | ||
@@ -157,126 +403,137 @@ [0, 0], | ||
[0, 0] | ||
], c = t.map((r) => r[0] + r[1]); | ||
o[0] = t[c.indexOf(Math.min(...c))], o[2] = t[c.indexOf(Math.max(...c))]; | ||
const n = t.filter((r) => r !== o[0] && r !== o[2]), a = n[1].map((r, e) => r - n[0][e]); | ||
return o[1] = n[a.indexOf(Math.min(...a))], o[3] = n[a.indexOf(Math.max(...a))], o; | ||
], n = t.map((s) => s[0] + s[1]); | ||
e[0] = t[n.indexOf(Math.min(...n))], e[2] = t[n.indexOf(Math.max(...n))]; | ||
const o = t.filter((s) => s !== e[0] && s !== e[2]), c = o[1].map((s, i) => s - o[0][i]); | ||
return e[1] = o[c.indexOf(Math.min(...c))], e[3] = o[c.indexOf(Math.max(...c))], e; | ||
} | ||
function ot(t, o) { | ||
const c = P(Math.max(C(o[0], o[1]), C(o[2], o[3]))), n = P(Math.max(C(o[0], o[3]), C(o[1], o[2]))), a = [ | ||
function Kt(t, e) { | ||
const n = H(Math.max(F(e[0], e[1]), F(e[2], e[3]))), o = H(Math.max(F(e[0], e[3]), F(e[1], e[2]))), c = [ | ||
[0, 0], | ||
[c, 0], | ||
[c, n], | ||
[0, n] | ||
], r = d.matFromArray(4, 1, d.CV_32FC2, L(o)), e = d.matFromArray(4, 1, d.CV_32FC2, L(a)), s = d.getPerspectiveTransform(r, e), i = d.imread(t), l = new d.Mat(), h = new d.Size(c, n); | ||
d.warpPerspective(i, l, s, h, d.INTER_CUBIC, d.BORDER_REPLICATE, new d.Scalar()), console.log(l); | ||
const u = l.matSize[0], g = l.matSize[1]; | ||
let m; | ||
if (u / g >= 1.5) { | ||
m = new d.Mat(); | ||
const w = new d.Size(l.rows, l.cols), x = new d.Point(l.cols / 2, l.cols / 2), b = d.getRotationMatrix2D(x, 90, 1); | ||
d.warpAffine(l, m, b, w, d.INTER_CUBIC, d.BORDER_REPLICATE, new d.Scalar()); | ||
[n, 0], | ||
[n, o], | ||
[0, o] | ||
], s = d.matFromArray(4, 1, d.CV_32FC2, xt(e)), i = d.matFromArray(4, 1, d.CV_32FC2, xt(c)), a = d.getPerspectiveTransform(s, i), r = Rt(t), l = new d.Mat(), h = new d.Size(n, o); | ||
d.warpPerspective(r, l, a, h, d.INTER_CUBIC, d.BORDER_REPLICATE, new d.Scalar()); | ||
const f = l.matSize[0], m = l.matSize[1]; | ||
let p; | ||
if (f / m >= 1.5) { | ||
p = new d.Mat(); | ||
const b = new d.Size(l.rows, l.cols), M = new d.Point(l.cols / 2, l.cols / 2), w = d.getRotationMatrix2D(M, 90, 1); | ||
d.warpAffine(l, p, w, b, d.INTER_CUBIC, d.BORDER_REPLICATE, new d.Scalar()); | ||
} | ||
let f = document.createElement("canvas"); | ||
return m ? (f.width = m.matSize[1], f.height = m.matSize[0]) : (f.width = g, f.height = u), d.imshow(f, m || l), T && document.body.append(f), i.delete(), l.delete(), r.delete(), e.delete(), f; | ||
const _ = Qt(p || l); | ||
return r.delete(), l.delete(), s.delete(), i.delete(), _; | ||
} | ||
function j(t, o, c) { | ||
const n = t.data, a = [], r = [], e = []; | ||
let s = 0, i = 0; | ||
for (let l = 0; l < n.length; l += 4) | ||
e[i] || (e[i] = []), r[i] || (r[i] = []), a[i] || (a[i] = []), a[i][s] = (n[l] / 255 - o[0]) / c[0], r[i][s] = (n[l + 1] / 255 - o[1]) / c[1], e[i][s] = (n[l + 2] / 255 - o[2]) / c[2], s++, s == t.width && (s = 0, i++); | ||
return [e, r, a]; | ||
function Rt(t) { | ||
return d.matFromImageData(t); | ||
} | ||
function it(t) { | ||
let o = []; | ||
function c(e) { | ||
R = Math.floor(y * r); | ||
let s = e.height, l = e.width / s, h; | ||
Math.ceil(y * l) > R ? h = R : h = Math.floor(Math.ceil(y * l)); | ||
let u = W(e, h, y), g = v(u, R, y); | ||
return T && document.body.append(g), g.getContext("2d").getImageData(0, 0, R, y); | ||
function Qt(t) { | ||
const e = new d.Mat(), n = t.type() % 8, o = n <= d.CV_8S ? 1 : n <= d.CV_32S ? 1 / 256 : 255, c = n === d.CV_8S || n === d.CV_16S ? 128 : 0; | ||
switch (t.convertTo(e, d.CV_8U, o, c), e.type()) { | ||
case d.CV_8UC1: | ||
d.cvtColor(e, e, d.COLOR_GRAY2RGBA); | ||
break; | ||
case d.CV_8UC3: | ||
d.cvtColor(e, e, d.COLOR_RGB2RGBA); | ||
break; | ||
case d.CV_8UC4: | ||
break; | ||
default: | ||
throw new Error("Bad number of channels (Source image must have 1, 3 or 4 channels)"); | ||
} | ||
let n = [], a = 0; | ||
for (let e of t) | ||
Math.abs(e.img.width - a) > 32 ? (a = e.img.width, n.push([e])) : (n[n.length - 1] || n.push([]), n[n.length - 1].push(e)); | ||
let r = 0; | ||
for (let e of n) { | ||
r = 0; | ||
for (let i of e) | ||
r = Math.max(i.img.width / i.img.height, r); | ||
let s = []; | ||
for (let i of e) | ||
s.push(j(c(i.img), [0.5, 0.5, 0.5], [0.5, 0.5, 0.5])); | ||
o.push({ b: s, imgH: y, imgW: R }); | ||
const s = new ImageData(new Uint8ClampedArray(e.data), e.cols, e.rows); | ||
return e.delete(), s; | ||
} | ||
function Zt(t) { | ||
const e = []; | ||
function n(o) { | ||
const c = Math.floor(W * (o.width / o.height)), s = at(o, c, W); | ||
return j && document.body.append(it(s, c, W)), { data: s, w: c, h: W }; | ||
} | ||
return console.log(o), o; | ||
for (const o of t) { | ||
const c = n(o.img); | ||
e.push({ b: lt(c.data, [0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), imgH: c.h, imgW: c.w }); | ||
} | ||
return j && console.log(e), e; | ||
} | ||
function rt(t, o) { | ||
let c = t.dims[2], n = [], a = t.dims[0] - 1; | ||
for (let e = 0; e < t.data.length; e += c * t.dims[1]) { | ||
const s = [], i = []; | ||
for (let l = e; l < e + c * t.dims[1]; l += c) { | ||
const h = t.data.slice(l, l + c), u = h.reduce((m, f) => Math.max(m, f), -1 / 0), g = h.indexOf(u); | ||
i.push(u), s.push(g); | ||
function te(t, e) { | ||
const n = t.dims[2], o = []; | ||
let c = t.dims[0] - 1; | ||
function s(a) { | ||
return e.at(a - 1); | ||
} | ||
for (let a = 0; a < t.data.length; a += n * t.dims[1]) { | ||
const r = [], l = []; | ||
for (let h = a; h < a + n * t.dims[1]; h += n) { | ||
const f = t.data.slice(h, h + n); | ||
let m = -1 / 0, p = -1, _ = -1 / 0, b = -1; | ||
for (let M = 0; M < f.length; M++) { | ||
const w = f[M]; | ||
w > m ? (_ = m, m = w, p = M) : w > _ && w < m && (_ = w, b = M); | ||
} | ||
p === 0 && s(b) === " " && _ > 1e-3 && (m = _, p = b), l.push(m), r.push(p); | ||
} | ||
n[a] = r(s, i, !0), a--; | ||
o[c] = i(r, l), c--; | ||
} | ||
function r(e, s, i) { | ||
const l = [0], h = [], u = []; | ||
for (let f = 0; f < e.length; f++) | ||
e[f] in l || i && f > 0 && e[f - 1] === e[f] || (h.push(o[e[f] - 1]), s ? u.push(s[f]) : u.push(1)); | ||
let g = "", m = 0; | ||
if (h.length) { | ||
g = h.join(""); | ||
let f = 0; | ||
u.forEach((w) => { | ||
f += w; | ||
}), m = f / u.length; | ||
function i(a, r) { | ||
const l = [], h = []; | ||
for (let p = 0; p < a.length; p++) | ||
a[p] !== 0 && (p > 0 && a[p - 1] === a[p] || (l.push(s(a[p])), h.push(r[p]))); | ||
let f = "", m = 0; | ||
if (l.length) { | ||
f = l.join("").trim(); | ||
let p = 0; | ||
h.forEach((_) => { | ||
p += _; | ||
}), m = p / h.length; | ||
} | ||
return { text: g, mean: m }; | ||
return { text: f, mean: m }; | ||
} | ||
return n; | ||
return o; | ||
} | ||
function st(t) { | ||
console.log(t); | ||
let o = [], c = /* @__PURE__ */ new Map(); | ||
for (let e in t) | ||
c.set(t[e].box, Number(e)); | ||
function n(e) { | ||
let s = 0; | ||
for (const i of e) { | ||
const [[, l], , [, h]] = i, u = h - l; | ||
s += u; | ||
function ee(t) { | ||
j && console.log(t); | ||
let e = [], n = /* @__PURE__ */ new Map(); | ||
for (let i in t) | ||
n.set(t[i].box, Number(i)); | ||
function o(i) { | ||
let a = 0; | ||
for (const r of i) { | ||
const [[, l], , [, h]] = r, f = h - l; | ||
a += f; | ||
} | ||
return s / e.length; | ||
return a / i.length; | ||
} | ||
function a(e) { | ||
const s = n(e), i = []; | ||
for (const l of e) { | ||
const [[, h], , [, u]] = l, g = (h + u) / 2, m = i.find((f) => { | ||
const [[, w], , [, x]] = f[0], b = (w + x) / 2; | ||
return Math.abs(b - g) < s / 2; | ||
function c(i) { | ||
const a = o(i), r = []; | ||
for (const l of i) { | ||
const [[, h], , [, f]] = l, m = (h + f) / 2, p = r.find((_) => { | ||
const [[, b], , [, M]] = _[0], w = (b + M) / 2; | ||
return Math.abs(w - m) < a / 2; | ||
}); | ||
m ? m.push(l) : i.push([l]); | ||
p ? p.push(l) : r.push([l]); | ||
} | ||
for (const l of i) | ||
l.sort((h, u) => { | ||
const [g] = h, [m] = u; | ||
return g[0] - m[0]; | ||
for (const l of r) | ||
l.sort((h, f) => { | ||
const [m] = h, [p] = f; | ||
return m[0] - p[0]; | ||
}); | ||
return i.sort((l, h) => l[0][0][1] - h[0][0][1]), i; | ||
return r.sort((l, h) => l[0][0][1] - h[0][0][1]), r; | ||
} | ||
let r = a([...c.keys()]); | ||
for (let e of r) { | ||
let s = [], i = 0; | ||
for (let l of e) { | ||
let h = t[c.get(l)]; | ||
s.push(h.text), i += h.mean; | ||
let s = c([...n.keys()]); | ||
for (let i of s) { | ||
let a = [], r = 0; | ||
for (let l of i) { | ||
let h = t[n.get(l)]; | ||
a.push(h.text), r += h.mean; | ||
} | ||
o.push({ mean: i / e.length, text: s.join(" "), box: [e.at(0)[0], e.at(-1)[1], e.at(-1)[2], e.at(0)[3]] }); | ||
e.push({ mean: r / i.length, text: a.join(" "), box: [i.at(0)[0], i.at(-1)[1], i.at(-1)[2], i.at(0)[3]] }); | ||
} | ||
return o; | ||
return e; | ||
} | ||
export { | ||
ct as init, | ||
at as ocr | ||
Ft as det, | ||
oe as init, | ||
se as ocr, | ||
Ht as rec | ||
}; | ||
//# sourceMappingURL=esearch-ocr.js.map |
{ | ||
"name": "esearch-ocr", | ||
"version": "4.1.2", | ||
"version": "4.1.5", | ||
"description": "paddleocr models run on onnx", | ||
@@ -41,5 +41,6 @@ "main": "./dist/esearch-ocr.umd.cjs", | ||
"onnxruntime-common": "^1.16.3", | ||
"typescript": "^5.1.3", | ||
"vite": "^4.3.9" | ||
"onnxruntime-node": "^1.17.0", | ||
"typescript": "^5.4.5", | ||
"vite": "^5.2.11" | ||
} | ||
} |
@@ -15,3 +15,3 @@ # eSearch-OCR | ||
在 js 文件下使用 electron 进行调试(主要是 require 几个模块和 fs 读取字典,若想纯网页实现,可以自行修改) | ||
在 js 文件下可以使用 electron 进行调试 | ||
@@ -21,3 +21,3 @@ ## 使用 | ||
```shell | ||
npm i esearch-ocr | ||
npm i esearch-ocr onnxruntime-web | ||
``` | ||
@@ -29,10 +29,16 @@ | ||
import * as ocr from "esearch-ocr"; | ||
import * as ort from "onnxruntime-web"; | ||
``` | ||
nodejs | ||
electron,nodejs 不支持 canvas | ||
```javascript | ||
const ocr = require("esearch-ocr"); | ||
const ort = require("onnxruntime-node"); | ||
``` | ||
> [!IMPORTANT] | ||
> 需要手动安装 onnxruntime(onnxruntime-node 或 onnxruntime-web,视平台而定),并在`init`参数中传入`ort` | ||
> 这样设计是因为 web 和 electron 可以使用不同的 ort,很难协调,不如让开发者自己决定 :( | ||
```javascript | ||
@@ -43,2 +49,3 @@ await ocr.init({ | ||
dic: "abcdefg...", | ||
ort, | ||
}); | ||
@@ -63,2 +70,3 @@ | ||
{ | ||
ort: typeof import("onnxruntime-web"); | ||
detPath: string; | ||
@@ -72,4 +80,3 @@ recPath: string; | ||
imgw?: number; | ||
ort?: typeof import("onnxruntime-web"); | ||
detShape?: [number, number]; // ppocr v3 需要指定为[960, 960] | ||
detShape?: [number, number]; // ppocr v3 需要指定为[960, 960], v4 为[640, 640] | ||
} | ||
@@ -76,0 +83,0 @@ ``` |
327
src/main.ts
var cv = require("opencv.js"); | ||
var ort: typeof import("onnxruntime-common"); | ||
export { x as ocr, init }; | ||
import { runLayout } from "./layout"; | ||
import { toPaddleInput, SessionType, AsyncType, data2canvas, resizeImg, int, tLog, clip } from "./untils"; | ||
const task = new tLog("t"); | ||
const task2 = new tLog("af_det"); | ||
export { init, x as ocr, Det as det, Rec as rec }; | ||
var dev = true; | ||
type AsyncType<T> = T extends Promise<infer U> ? U : never; | ||
type SessionType = AsyncType<ReturnType<typeof import("onnxruntime-common").InferenceSession.create>>; | ||
var det: SessionType, rec: SessionType, dic: string[]; | ||
var det: SessionType, rec: SessionType, layout: SessionType, dic: string[]; | ||
var limitSideLen = 960, | ||
@@ -14,8 +18,10 @@ imgH = 48, | ||
var detShape = [NaN, NaN]; | ||
var layoutDic: string[]; | ||
async function init(x: { | ||
detPath: string; | ||
recPath: string; | ||
dic: string; | ||
node?: boolean; | ||
detPath?: string; | ||
recPath?: string; | ||
layoutPath?: string; | ||
dic?: string; | ||
layoutDic?: string; | ||
dev?: boolean; | ||
@@ -30,5 +36,17 @@ maxSide?: number; | ||
dev = x.dev; | ||
det = await ort.InferenceSession.create(x.detPath); | ||
rec = await ort.InferenceSession.create(x.recPath); | ||
if (!dev) { | ||
task.l = () => {}; | ||
task2.l = () => {}; | ||
} | ||
if (x.detPath) det = await ort.InferenceSession.create(x.detPath); | ||
if (x.recPath) rec = await ort.InferenceSession.create(x.recPath); | ||
if (x.layoutPath) layout = await ort.InferenceSession.create(x.layoutPath); | ||
dic = x.dic.split(/\r\n|\r|\n/); | ||
if (dic.at(-1) === "") { | ||
// 多出的换行 | ||
dic[dic.length - 1] = " "; | ||
} else { | ||
dic.push(" "); | ||
} | ||
layoutDic = x.layoutDic?.split(/\r\n|\r|\n/); | ||
if (x.maxSide) limitSideLen = x.maxSide; | ||
@@ -43,23 +61,56 @@ if (x.imgh) imgH = x.imgh; | ||
async function x(img: ImageData) { | ||
console.time(); | ||
task.l(""); | ||
if (layout) { | ||
const sr = await runLayout(img, ort, layout, layoutDic); | ||
} | ||
const box = await Det(img); | ||
let mainLine = await Rec(box); | ||
mainLine = afAfRec(mainLine); | ||
console.log(mainLine); | ||
task.l("end"); | ||
return mainLine; | ||
} | ||
async function Det(img: ImageData) { | ||
let h = img.height, | ||
w = img.width; | ||
const _r = 0.6; | ||
const _h = h, | ||
_w = w; | ||
if (_h < _w * _r || _w < _h * _r) { | ||
if (_h < _w * _r) h = Math.floor(_w * _r); | ||
if (_w < _h * _r) w = Math.floor(_h * _r); | ||
const c = document.createElement("canvas"); | ||
const ctx = c.getContext("2d"); | ||
c.width = w; | ||
c.height = h; | ||
ctx.putImageData(img, 0, 0); | ||
img = ctx.getImageData(0, 0, w, h); | ||
} | ||
task.l("pre_det"); | ||
let { transposedData, image } = beforeDet(img, detShape[0], detShape[1]); | ||
task.l("det"); | ||
const detResults = await runDet(transposedData, image, det); | ||
task.l("aft_det"); | ||
let box = afterDet(detResults.data, detResults.dims[3], detResults.dims[2], img); | ||
return box; | ||
} | ||
async function Rec(box: { box: BoxType; img: ImageData }[]) { | ||
let mainLine: resultType = []; | ||
for (let i of beforeRec(box)) { | ||
let { b, imgH, imgW } = i; | ||
task.l("bf_rec"); | ||
const recL = beforeRec(box); | ||
const recPromises = recL.map(async (item) => { | ||
const { b, imgH, imgW } = item; | ||
const recResults = await runRec(b, imgH, imgW, rec); | ||
if (dic.at(-1) == "") { | ||
// 多出的换行 | ||
dic[dic.length - 1] = " "; | ||
} else { | ||
dic.push(" "); | ||
} | ||
let line = afterRec(recResults, dic); | ||
mainLine = line.concat(mainLine); | ||
} | ||
return afterRec(recResults, dic); | ||
}); | ||
const l = await Promise.all(recPromises); | ||
mainLine = l.flat().toReversed(); | ||
task.l("rec_end"); | ||
for (let i in mainLine) { | ||
@@ -74,5 +125,2 @@ let b = box[mainLine.length - Number(i) - 1].box; | ||
mainLine = mainLine.filter((x) => x.mean >= 0.5); | ||
mainLine = afAfRec(mainLine); | ||
console.log(mainLine); | ||
console.timeEnd(); | ||
return mainLine; | ||
@@ -82,4 +130,3 @@ } | ||
async function runDet(transposedData: number[][][], image: ImageData, det: SessionType) { | ||
let x = transposedData.flat(Infinity) as number[]; | ||
const detData = Float32Array.from(x); | ||
const detData = Float32Array.from(transposedData.flat(3)); | ||
@@ -95,5 +142,5 @@ const detTensor = new ort.Tensor("float32", detData, [1, 3, image.height, image.width]); | ||
async function runRec(b: number[][][], imgH: number, imgW: number, rec: SessionType) { | ||
const recData = Float32Array.from(b.flat(Infinity) as number[]); | ||
const recData = Float32Array.from(b.flat(3)); | ||
const recTensor = new ort.Tensor("float32", recData, [b.length, 3, imgH, imgW]); | ||
const recTensor = new ort.Tensor("float32", recData, [1, 3, imgH, imgW]); | ||
let recFeed = {}; | ||
@@ -106,26 +153,2 @@ recFeed[rec.inputNames[0]] = recTensor; | ||
function data2canvas(data: ImageData, w?: number, h?: number) { | ||
let x = document.createElement("canvas"); | ||
x.width = w || data.width; | ||
x.height = h || data.height; | ||
x.getContext("2d").putImageData(data, 0, 0); | ||
return x; | ||
} | ||
/** | ||
* | ||
* @param {ImageData} data 原图 | ||
* @param {number} w 输出宽 | ||
* @param {number} h 输出高 | ||
*/ | ||
function resizeImg(data: ImageData, w: number, h: number) { | ||
let x = data2canvas(data); | ||
let src = document.createElement("canvas"); | ||
src.width = w; | ||
src.height = h; | ||
src.getContext("2d").scale(w / data.width, h / data.height); | ||
src.getContext("2d").drawImage(x, 0, 0); | ||
return src.getContext("2d").getImageData(0, 0, w, h); | ||
} | ||
function beforeDet(image: ImageData, shapeH: number, shapeW: number) { | ||
@@ -159,5 +182,6 @@ let ratio = 1; | ||
function afterDet(data: AsyncType<ReturnType<typeof runDet>>["data"], w: number, h: number, srcData: ImageData) { | ||
var myImageData = new ImageData(w, h); | ||
for (let i in data) { | ||
let n = Number(i) * 4; | ||
task2.l(""); | ||
const myImageData = new ImageData(w, h); | ||
for (let i = 0; i < data.length; i++) { | ||
const n = i * 4; | ||
const v = (data[i] as number) > 0.3 ? 255 : 0; | ||
@@ -167,7 +191,7 @@ myImageData.data[n] = myImageData.data[n + 1] = myImageData.data[n + 2] = v; | ||
} | ||
let canvas = data2canvas(myImageData); | ||
task2.l("edge"); | ||
let edgeRect: { box: BoxType; img: ImageData }[] = []; | ||
let src = cv.imread(canvas); | ||
let src = cvImRead(myImageData); | ||
@@ -181,2 +205,3 @@ cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0); | ||
for (let i = 0; i < contours.size(); i++) { | ||
task2.l("get_box"); | ||
let minSize = 3; | ||
@@ -197,5 +222,2 @@ let cnt = contours.get(i); | ||
} | ||
function clip(n: number, min: number, max: number) { | ||
return Math.max(min, Math.min(n, max)); | ||
} | ||
@@ -209,2 +231,3 @@ let rx = srcData.width / w; | ||
} | ||
task2.l("order"); | ||
@@ -220,8 +243,9 @@ let box1 = orderPointsClockwise(box); | ||
let c0 = data2canvas(srcData); | ||
task2.l("crop"); | ||
let c = getRotateCropImage(c0, box); | ||
let c = getRotateCropImage(srcData, box); | ||
edgeRect.push({ box, img: c.getContext("2d").getImageData(0, 0, c.width, c.height) }); | ||
edgeRect.push({ box, img: c }); | ||
} | ||
task2.l("e"); | ||
@@ -238,2 +262,3 @@ console.log(edgeRect); | ||
} | ||
type pointType = [number, number]; | ||
@@ -380,10 +405,4 @@ type BoxType = [pointType, pointType, pointType, pointType]; | ||
function int(num: number) { | ||
return num > 0 ? Math.floor(num) : Math.ceil(num); | ||
} | ||
function flatten(arr: number[] | number[][]) { | ||
return arr | ||
.toString() | ||
.split(",") | ||
.map((item) => +item); | ||
return arr.flat(); | ||
} | ||
@@ -409,3 +428,3 @@ function linalgNorm(p0: pointType, p1: pointType) { | ||
} | ||
function getRotateCropImage(img: HTMLCanvasElement | HTMLImageElement, points: BoxType) { | ||
function getRotateCropImage(img: ImageData, points: BoxType) { | ||
const img_crop_width = int(Math.max(linalgNorm(points[0], points[1]), linalgNorm(points[2], points[3]))); | ||
@@ -425,3 +444,3 @@ const img_crop_height = int(Math.max(linalgNorm(points[0], points[3]), linalgNorm(points[1], points[2]))); | ||
const M = cv.getPerspectiveTransform(srcTri, dstTri); | ||
const src = cv.imread(img); | ||
const src = cvImRead(img); | ||
const dst = new cv.Mat(); | ||
@@ -431,3 +450,2 @@ const dsize = new cv.Size(img_crop_width, img_crop_height); | ||
cv.warpPerspective(src, dst, M, dsize, cv.INTER_CUBIC, cv.BORDER_REPLICATE, new cv.Scalar()); | ||
console.log(dst); | ||
@@ -446,12 +464,3 @@ const dst_img_height = dst.matSize[0]; | ||
let c = document.createElement("canvas"); | ||
if (dst_rot) { | ||
c.width = dst_rot.matSize[1]; | ||
c.height = dst_rot.matSize[0]; | ||
} else { | ||
c.width = dst_img_width; | ||
c.height = dst_img_height; | ||
} | ||
cv.imshow(c, dst_rot || dst); | ||
if (dev) document.body.append(c); | ||
const d = cvImShow(dst_rot || dst); | ||
@@ -462,72 +471,47 @@ src.delete(); | ||
dstTri.delete(); | ||
return c; | ||
return d; | ||
} | ||
function toPaddleInput(image: ImageData, mean: number[], std: number[]) { | ||
const imagedata = image.data; | ||
const redArray: number[][] = []; | ||
const greenArray: number[][] = []; | ||
const blueArray: number[][] = []; | ||
let x = 0, | ||
y = 0; | ||
for (let i = 0; i < imagedata.length; i += 4) { | ||
if (!blueArray[y]) blueArray[y] = []; | ||
if (!greenArray[y]) greenArray[y] = []; | ||
if (!redArray[y]) redArray[y] = []; | ||
redArray[y][x] = (imagedata[i] / 255 - mean[0]) / std[0]; | ||
greenArray[y][x] = (imagedata[i + 1] / 255 - mean[1]) / std[1]; | ||
blueArray[y][x] = (imagedata[i + 2] / 255 - mean[2]) / std[2]; | ||
x++; | ||
if (x == image.width) { | ||
x = 0; | ||
y++; | ||
} | ||
function cvImRead(img: ImageData) { | ||
return cv.matFromImageData(img); | ||
} | ||
function cvImShow(mat) { | ||
const img = new cv.Mat(); | ||
const depth = mat.type() % 8; | ||
const scale = depth <= cv.CV_8S ? 1 : depth <= cv.CV_32S ? 1 / 256 : 255; | ||
const shift = depth === cv.CV_8S || depth === cv.CV_16S ? 128 : 0; | ||
mat.convertTo(img, cv.CV_8U, scale, shift); | ||
switch (img.type()) { | ||
case cv.CV_8UC1: | ||
cv.cvtColor(img, img, cv.COLOR_GRAY2RGBA); | ||
break; | ||
case cv.CV_8UC3: | ||
cv.cvtColor(img, img, cv.COLOR_RGB2RGBA); | ||
break; | ||
case cv.CV_8UC4: | ||
break; | ||
default: | ||
throw new Error("Bad number of channels (Source image must have 1, 3 or 4 channels)"); | ||
return; | ||
} | ||
return [blueArray, greenArray, redArray]; | ||
const imgData = new ImageData(new Uint8ClampedArray(img.data), img.cols, img.rows); | ||
img.delete(); | ||
return imgData; | ||
} | ||
function beforeRec(box: { box: BoxType; img: ImageData }[]) { | ||
let l: { b: number[][][]; imgH: number; imgW: number }[] = []; | ||
const l: { b: number[][][]; imgH: number; imgW: number }[] = []; | ||
function resizeNormImg(img: ImageData) { | ||
imgW = Math.floor(imgH * maxWhRatio); | ||
let h = img.height, | ||
w = img.width; | ||
let ratio = w / h; | ||
let resizedW: number; | ||
if (Math.ceil(imgH * ratio) > imgW) { | ||
resizedW = imgW; | ||
} else { | ||
resizedW = Math.floor(Math.ceil(imgH * ratio)); | ||
} | ||
let d = resizeImg(img, resizedW, imgH); | ||
let cc = data2canvas(d, imgW, imgH); | ||
if (dev) document.body.append(cc); | ||
return cc.getContext("2d").getImageData(0, 0, imgW, imgH); | ||
const w = Math.floor(imgH * (img.width / img.height)); | ||
const d = resizeImg(img, w, imgH); | ||
if (dev) document.body.append(data2canvas(d, w, imgH)); | ||
return { data: d, w, h: imgH }; | ||
} | ||
let boxes = []; | ||
let nowWidth = 0; | ||
for (let i of box) { | ||
if (Math.abs(i.img.width - nowWidth) > 32) { | ||
nowWidth = i.img.width; | ||
boxes.push([i]); | ||
} else { | ||
if (!boxes[boxes.length - 1]) boxes.push([]); | ||
boxes[boxes.length - 1].push(i); | ||
} | ||
for (const r of box) { | ||
const reImg = resizeNormImg(r.img); | ||
l.push({ b: toPaddleInput(reImg.data, [0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), imgH: reImg.h, imgW: reImg.w }); | ||
} | ||
let maxWhRatio = 0; | ||
for (let box of boxes) { | ||
maxWhRatio = 0; | ||
for (let r of box) { | ||
maxWhRatio = Math.max(r.img.width / r.img.height, maxWhRatio); | ||
} | ||
let b = []; | ||
for (let r of box) { | ||
b.push(toPaddleInput(resizeNormImg(r.img), [0.5, 0.5, 0.5], [0.5, 0.5, 0.5])); | ||
} | ||
l.push({ b, imgH, imgW }); | ||
} | ||
console.log(l); | ||
if (dev) console.log(l); | ||
return l; | ||
@@ -537,5 +521,10 @@ } | ||
function afterRec(data: AsyncType<ReturnType<typeof runRec>>, character: string[]) { | ||
let predLen = data.dims[2]; | ||
let line: { text: string; mean: number }[] = []; | ||
const predLen = data.dims[2]; | ||
const line: { text: string; mean: number }[] = []; | ||
let ml = data.dims[0] - 1; | ||
function getChar(i: number) { | ||
return character.at(i - 1); | ||
} | ||
for (let l = 0; l < data.data.length; l += predLen * data.dims[1]) { | ||
@@ -547,18 +536,36 @@ const predsIdx: number[] = []; | ||
const tmpArr = data.data.slice(i, i + predLen) as Float32Array; | ||
const tmpMax = tmpArr.reduce((a, b) => Math.max(a, b), -Infinity); | ||
const tmpIdx = tmpArr.indexOf(tmpMax); | ||
let tmpMax = -Infinity; | ||
let tmpIdx = -1; | ||
let tmpSecond = -Infinity; | ||
let tmpSecondI = -1; | ||
for (let j = 0; j < tmpArr.length; j++) { | ||
const currentValue = tmpArr[j]; | ||
if (currentValue > tmpMax) { | ||
tmpSecond = tmpMax; | ||
tmpMax = currentValue; | ||
tmpIdx = j; | ||
} else if (currentValue > tmpSecond && currentValue < tmpMax) { | ||
tmpSecond = currentValue; | ||
tmpSecondI = j; | ||
} | ||
} | ||
if (tmpIdx === 0 && getChar(tmpSecondI) === " " && tmpSecond > 0.001) { | ||
tmpMax = tmpSecond; | ||
tmpIdx = tmpSecondI; | ||
} | ||
predsProb.push(tmpMax); | ||
predsIdx.push(tmpIdx); | ||
} | ||
line[ml] = decode(predsIdx, predsProb, true); | ||
line[ml] = decode(predsIdx, predsProb); | ||
ml--; | ||
} | ||
function decode(textIndex: number[], textProb: number[], isRemoveDuplicate: boolean) { | ||
const ignoredTokens = [0]; | ||
function decode(textIndex: number[], textProb: number[]) { | ||
const charList = []; | ||
const confList = []; | ||
const isRemoveDuplicate = true; | ||
for (let idx = 0; idx < textIndex.length; idx++) { | ||
if (textIndex[idx] in ignoredTokens) { | ||
continue; | ||
} | ||
if (textIndex[idx] === 0) continue; | ||
if (isRemoveDuplicate) { | ||
@@ -569,8 +576,4 @@ if (idx > 0 && textIndex[idx - 1] === textIndex[idx]) { | ||
} | ||
charList.push(character[textIndex[idx] - 1]); | ||
if (textProb) { | ||
confList.push(textProb[idx]); | ||
} else { | ||
confList.push(1); | ||
} | ||
charList.push(getChar(textIndex[idx])); | ||
confList.push(textProb[idx]); | ||
} | ||
@@ -580,3 +583,3 @@ let text = ""; | ||
if (charList.length) { | ||
text = charList.join(""); | ||
text = charList.join("").trim(); | ||
let sum = 0; | ||
@@ -596,3 +599,3 @@ confList.forEach((item) => { | ||
function afAfRec(l: resultType) { | ||
console.log(l); | ||
if (dev) console.log(l); | ||
@@ -599,0 +602,0 @@ let line: resultType = []; |
@@ -11,4 +11,3 @@ import { defineConfig } from "vite"; | ||
}, | ||
sourcemap: true, | ||
}, | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1676
89
93181
5
1