Spaces:
Paused
Paused
| /** | |
| * Copyright (c) Meta Platforms, Inc. and affiliates. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| 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]); | |
| } | |
| } | |
| // encode mask to RLEs objects | |
| // list of RLE string can be generated by RLEs member function | |
| 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; | |
| } | |
| // decode mask from compressed list of RLE string or RLEs object | |
| 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); | |
| // Slice data for current RLE object | |
| 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 { | |
| /* Similar to LEB128 but using 6 bits/char and ascii chars 48-111. */ | |
| 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; // 1; | |
| 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(''); | |
| } | |
| // internal conversion from Python RLEs object to compressed RLE format | |
| 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; | |
| } | |
| // internal conversion from compressed RLE format to Python RLEs object | |
| 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; | |
| // The RLE structure likely contains run-length encoded data where each | |
| // element represents a count of consecutive pixels with the same value in | |
| // a binary image (black or white). Since the counts represent both black | |
| // and white pixels, this operation ((siz)(m/2)) * 2 is used to ensure that | |
| // m is always an even number. By doing so, the code can later check | |
| // whether the current pixel is black or white based on whether the index j | |
| // is even or odd. | |
| 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); | |
| } | |