| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export class DataArray { |
| data: Uint8Array; |
| readonly shape: number[]; |
|
|
| constructor(data: Uint8Array, shape: Array<number>) { |
| this.data = data; |
| this.shape = shape; |
| } |
| } |
|
|
| export type RLEObject = { |
| size: [h: number, w: number]; |
| counts: string; |
| }; |
|
|
| type RLE = { |
| h: number; |
| w: number; |
| m: number; |
| cnts: number[]; |
| }; |
|
|
| type BB = number[]; |
|
|
| function rleInit(R: RLE, h: number, w: number, m: number, cnts: number[]) { |
| R.h = h; |
| R.w = w; |
| R.m = m; |
| R.cnts = m === 0 ? [0] : cnts; |
| } |
|
|
| function rlesInit(R: RLE[], n: number) { |
| let i; |
| for (i = 0; i < n; i++) { |
| R[i] = {h: 0, w: 0, m: 0, cnts: [0]}; |
| rleInit(R[i], 0, 0, 0, [0]); |
| } |
| } |
|
|
| class RLEs { |
| _R: RLE[]; |
| _n: number; |
|
|
| constructor(n: number) { |
| this._R = []; |
| rlesInit(this._R, n); |
| this._n = n; |
| } |
| } |
|
|
| export class Masks { |
| _mask: Uint8Array; |
| _h: number; |
| _w: number; |
| _n: number; |
|
|
| constructor(h: number, w: number, n: number) { |
| this._mask = new Uint8Array(h * w * n); |
| this._h = h; |
| this._w = w; |
| this._n = n; |
| } |
|
|
| toDataArray(): DataArray { |
| return new DataArray(this._mask, [this._h, this._w, this._n]); |
| } |
| } |
|
|
| |
| |
| export function encode(mask: DataArray): RLEObject[] { |
| const h = mask.shape[0]; |
| const w = mask.shape[1]; |
| const n = mask.shape[2]; |
| const Rs = new RLEs(n); |
| rleEncode(Rs._R, mask.data, h, w, n); |
| const objs = _toString(Rs); |
| return objs; |
| } |
|
|
| |
| export function decode(rleObjs: RLEObject[]): DataArray { |
| const Rs = _frString(rleObjs); |
| const h = Rs._R[0].h; |
| const w = Rs._R[0].w; |
| const n = Rs._n; |
| const masks = new Masks(h, w, n); |
| rleDecode(Rs._R, masks._mask, n); |
| return masks.toDataArray(); |
| } |
|
|
| export function toBbox(rleObjs: RLEObject[]): BB { |
| const Rs = _frString(rleObjs); |
| const n = Rs._n; |
| const bb: BB = []; |
| rleToBbox(Rs._R, bb, n); |
| return bb; |
| } |
|
|
| function rleEncode(R: RLE[], M: Uint8Array, h: number, w: number, n: number) { |
| let i; |
| let j; |
| let k; |
| const a = w * h; |
| let c; |
| const cnts: number[] = []; |
| let p; |
| for (i = 0; i < n; i++) { |
| const from = a * i; |
| const to = a * (i + 1); |
| |
| const T = M.slice(from, to); |
| k = 0; |
| p = 0; |
| c = 0; |
| for (j = 0; j < a; j++) { |
| if (T[j] !== p) { |
| cnts[k++] = c; |
| c = 0; |
| p = T[j]; |
| } |
| c++; |
| } |
| cnts[k++] = c; |
| rleInit(R[i], h, w, k, [...cnts]); |
| } |
| } |
|
|
| function rleDecode(R: RLE[], M: Uint8Array, n: number): void { |
| let i; |
| let j; |
| let k; |
| let p = 0; |
| for (i = 0; i < n; i++) { |
| let v = false; |
| for (j = 0; j < R[i].m; j++) { |
| for (k = 0; k < R[i].cnts[j]; k++) { |
| M[p++] = v === false ? 0 : 1; |
| } |
| v = !v; |
| } |
| } |
| } |
|
|
| function rleToString(R: RLE): string { |
| |
| let i; |
| const m = R.m; |
| let p = 0; |
| let x: number; |
| let more; |
| const s: string[] = []; |
| for (i = 0; i < m; i++) { |
| x = R.cnts[i]; |
| if (i > 2) { |
| x -= R.cnts[i - 2]; |
| } |
| more = true; |
| while (more) { |
| let c = x & 0x1f; |
| x >>= 5; |
| more = c & 0x10 ? x != -1 : x != 0; |
| if (more) { |
| c |= 0x20; |
| } |
| c += 48; |
| s[p++] = String.fromCharCode(c); |
| } |
| } |
| return s.join(''); |
| } |
|
|
| |
| function _toString(Rs: RLEs): RLEObject[] { |
| const n = Rs._n; |
| let py_string; |
| let c_string; |
| const objs: RLEObject[] = []; |
| for (let i = 0; i < n; i++) { |
| c_string = rleToString(Rs._R[i]); |
| py_string = c_string; |
| objs.push({ |
| size: [Rs._R[i].h, Rs._R[i].w], |
| counts: py_string, |
| }); |
| } |
| return objs; |
| } |
|
|
| |
| function _frString(rleObjs: RLEObject[]): RLEs { |
| const n = rleObjs.length; |
| const Rs = new RLEs(n); |
| let py_string; |
| let c_string; |
| for (let i = 0; i < rleObjs.length; i++) { |
| const obj = rleObjs[i]; |
| py_string = obj.counts; |
| c_string = py_string; |
| rleFrString(Rs._R[i], c_string, obj.size[0], obj.size[1]); |
| } |
| return Rs; |
| } |
|
|
| function rleToBbox(R: RLE[], bb: BB, n: number) { |
| for (let i = 0; i < n; i++) { |
| const h = R[i].h; |
| const w = R[i].w; |
| let m = R[i].m; |
| |
| |
| |
| |
| |
| |
| |
| m = Math.floor(m / 2) * 2; |
| let xs = w; |
| let ys = h; |
| let xe = 0; |
| let ye = 0; |
| let cc = 0; |
| let t; |
| let y; |
| let x; |
| let xp = 0; |
| if (m === 0) { |
| bb[4 * i] = bb[4 * i + 1] = bb[4 * i + 2] = bb[4 * i + 3] = 0; |
| continue; |
| } |
| for (let j = 0; j < m; j++) { |
| cc += R[i].cnts[j]; |
| t = cc - (j % 2); |
| y = t % h; |
| x = Math.floor((t - y) / h); |
| if (j % 2 === 0) { |
| xp = x; |
| } else if (xp < x) { |
| ys = 0; |
| ye = h - 1; |
| } |
| xs = Math.min(xs, x); |
| xe = Math.max(xe, x); |
| ys = Math.min(ys, y); |
| ye = Math.max(ye, y); |
| } |
| bb[4 * i] = xs; |
| bb[4 * i + 2] = xe - xs + 1; |
| bb[4 * i + 1] = ys; |
| bb[4 * i + 3] = ye - ys + 1; |
| } |
| } |
|
|
| function rleFrString(R: RLE, s: string, h: number, w: number): void { |
| let m = 0; |
| let p = 0; |
| let k; |
| let x; |
| let more; |
| let cnts = []; |
| while (s[m]) { |
| m++; |
| } |
| cnts = []; |
| m = 0; |
| while (s[p]) { |
| x = 0; |
| k = 0; |
| more = 1; |
| while (more) { |
| const c = s.charCodeAt(p) - 48; |
| x |= (c & 0x1f) << (5 * k); |
| more = c & 0x20; |
| p++; |
| k++; |
| if (!more && c & 0x10) { |
| x |= -1 << (5 * k); |
| } |
| } |
| if (m > 2) { |
| x += cnts[m - 2]; |
| } |
| cnts[m++] = x; |
| } |
| rleInit(R, h, w, m, cnts); |
| } |
|
|