@pilio/gemini-watermark-remover 1.0.22 → 1.0.24
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pilio/gemini-watermark-remover",
|
|
3
3
|
"description": "Automatically removes watermarks from Gemini AI generated images",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.24",
|
|
5
5
|
"author": "GargantuaX",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"files": [
|
|
@@ -112,6 +112,9 @@
|
|
|
112
112
|
"render:skipped-crops": "node scripts/render-skipped-candidate-crops.js",
|
|
113
113
|
"render:video-crops": "node scripts/render-video-crop-sheet.js",
|
|
114
114
|
"analyze:video-residual": "node scripts/analyze-video-residual.js",
|
|
115
|
+
"score:video-candidates": "node scripts/score-video-watermark-candidates.js",
|
|
116
|
+
"sweep:veo-text-cleanup": "node scripts/sweep-veo-text-cleanup.js",
|
|
117
|
+
"score:video-output-residual": "node scripts/score-video-output-residual.js",
|
|
115
118
|
"benchmark:video-crops": "node scripts/video-crop-benchmark.js",
|
|
116
119
|
"report:video-crops": "node scripts/report-video-crop-benchmark.js",
|
|
117
120
|
"diagnose:video-lowbody": "node scripts/diagnose-video-lowbody-regression.js",
|
|
@@ -144,7 +147,12 @@
|
|
|
144
147
|
"export:allenk-fdncnn-onnx-video": "node scripts/export-allenk-fdncnn-onnx-video.js",
|
|
145
148
|
"export:allenk-fdncnn-onnx-frame-video": "node scripts/export-allenk-fdncnn-onnx-frame-video.js",
|
|
146
149
|
"report:allenk-fdncnn-onnx-video-evidence": "node scripts/create-allenk-fdncnn-onnx-video-evidence.js",
|
|
150
|
+
"report:allenk-catalog-audit": "node scripts/create-allenk-catalog-audit.js",
|
|
151
|
+
"report:allenk-video-binary-analysis": "node scripts/create-allenk-video-binary-analysis.js",
|
|
147
152
|
"export:video-ui-preset": "node scripts/export-video-ui-preset.js",
|
|
153
|
+
"verify:video-ui-preset-output": "node scripts/verify-video-ui-preset-output.js",
|
|
154
|
+
"verify:video-ui-preset-batch": "node scripts/verify-video-ui-preset-batch.js",
|
|
155
|
+
"verify:video-regression-samples": "pnpm verify:video-ui-preset-batch -- --manifest tests/fixtures/video-regression-samples/gemini-video-regression-samples.json --output-dir .artifacts/video-regression-samples --no-screenshots --fail-on-residual",
|
|
148
156
|
"render:video-comparison-grid": "node scripts/render-video-comparison-grid.js",
|
|
149
157
|
"package:extension": "node scripts/package-extension-release.js",
|
|
150
158
|
"cli:smoke": "node bin/gwr.mjs --help",
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createAlphaGradientMask } from './alphaGradientMask.js';
|
|
2
|
-
|
|
3
1
|
const ALLENK_FDNCNN_MODEL = Object.freeze({
|
|
4
2
|
name: 'FDnCNN Color FP16',
|
|
5
3
|
upstream: 'allenk/GeminiWatermarkTool',
|
|
@@ -20,6 +18,15 @@ function clamp(value, min, max) {
|
|
|
20
18
|
return Math.max(min, Math.min(max, value));
|
|
21
19
|
}
|
|
22
20
|
|
|
21
|
+
function reflect101(index, length) {
|
|
22
|
+
if (length <= 1) return 0;
|
|
23
|
+
let value = Math.round(index);
|
|
24
|
+
while (value < 0 || value >= length) {
|
|
25
|
+
value = value < 0 ? -value : (length * 2 - value - 2);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
function createGaussianKernel(sigma, radius = Math.ceil(sigma * 3)) {
|
|
24
31
|
const safeSigma = Math.max(0.01, sigma);
|
|
25
32
|
const safeRadius = Math.max(1, Math.round(radius));
|
|
@@ -52,7 +59,7 @@ function gaussianBlurFloatMap(source, width, height, sigma, radius = Math.ceil(s
|
|
|
52
59
|
for (let x = 0; x < width; x++) {
|
|
53
60
|
let sum = 0;
|
|
54
61
|
for (let dx = -r; dx <= r; dx++) {
|
|
55
|
-
const xx =
|
|
62
|
+
const xx = reflect101(x + dx, width);
|
|
56
63
|
sum += source[y * width + xx] * kernel[dx + r];
|
|
57
64
|
}
|
|
58
65
|
temp[y * width + x] = sum;
|
|
@@ -63,7 +70,7 @@ function gaussianBlurFloatMap(source, width, height, sigma, radius = Math.ceil(s
|
|
|
63
70
|
for (let x = 0; x < width; x++) {
|
|
64
71
|
let sum = 0;
|
|
65
72
|
for (let dy = -r; dy <= r; dy++) {
|
|
66
|
-
const yy =
|
|
73
|
+
const yy = reflect101(y + dy, height);
|
|
67
74
|
sum += temp[yy * width + x] * kernel[dy + r];
|
|
68
75
|
}
|
|
69
76
|
output[y * width + x] = sum;
|
|
@@ -123,6 +130,139 @@ function resizeSquareAlphaMapArea(sourceAlpha, sourceSize, targetWidth, targetHe
|
|
|
123
130
|
return output;
|
|
124
131
|
}
|
|
125
132
|
|
|
133
|
+
function resizeSquareAlphaMapLinear(sourceAlpha, sourceSize, targetWidth, targetHeight = targetWidth) {
|
|
134
|
+
if (!sourceAlpha || sourceSize <= 0 || targetWidth <= 0 || targetHeight <= 0) {
|
|
135
|
+
return new Float32Array(0);
|
|
136
|
+
}
|
|
137
|
+
if (sourceSize === targetWidth && sourceSize === targetHeight) {
|
|
138
|
+
return new Float32Array(sourceAlpha);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const output = new Float32Array(targetWidth * targetHeight);
|
|
142
|
+
const scaleX = sourceSize / targetWidth;
|
|
143
|
+
const scaleY = sourceSize / targetHeight;
|
|
144
|
+
|
|
145
|
+
for (let y = 0; y < targetHeight; y++) {
|
|
146
|
+
const sourceY = (y + 0.5) * scaleY - 0.5;
|
|
147
|
+
const y0 = Math.floor(sourceY);
|
|
148
|
+
const y1 = y0 + 1;
|
|
149
|
+
const wy = sourceY - y0;
|
|
150
|
+
|
|
151
|
+
for (let x = 0; x < targetWidth; x++) {
|
|
152
|
+
const sourceX = (x + 0.5) * scaleX - 0.5;
|
|
153
|
+
const x0 = Math.floor(sourceX);
|
|
154
|
+
const x1 = x0 + 1;
|
|
155
|
+
const wx = sourceX - x0;
|
|
156
|
+
|
|
157
|
+
const topLeft = sourceAlpha[clamp(y0, 0, sourceSize - 1) * sourceSize + clamp(x0, 0, sourceSize - 1)] || 0;
|
|
158
|
+
const topRight = sourceAlpha[clamp(y0, 0, sourceSize - 1) * sourceSize + clamp(x1, 0, sourceSize - 1)] || 0;
|
|
159
|
+
const bottomLeft = sourceAlpha[clamp(y1, 0, sourceSize - 1) * sourceSize + clamp(x0, 0, sourceSize - 1)] || 0;
|
|
160
|
+
const bottomRight = sourceAlpha[clamp(y1, 0, sourceSize - 1) * sourceSize + clamp(x1, 0, sourceSize - 1)] || 0;
|
|
161
|
+
const top = topLeft * (1 - wx) + topRight * wx;
|
|
162
|
+
const bottom = bottomLeft * (1 - wx) + bottomRight * wx;
|
|
163
|
+
|
|
164
|
+
output[y * targetWidth + x] = top * (1 - wy) + bottom * wy;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return output;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function resizeSquareAlphaMapOpenCv(sourceAlpha, sourceSize, targetWidth, targetHeight = targetWidth) {
|
|
172
|
+
return targetWidth > sourceSize
|
|
173
|
+
? resizeSquareAlphaMapLinear(sourceAlpha, sourceSize, targetWidth, targetHeight)
|
|
174
|
+
: resizeSquareAlphaMapArea(sourceAlpha, sourceSize, targetWidth, targetHeight);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const ALLENK_ELLIPSE_5X5 = Object.freeze([
|
|
178
|
+
[0, 0, 1, 0, 0],
|
|
179
|
+
[1, 1, 1, 1, 1],
|
|
180
|
+
[1, 1, 1, 1, 1],
|
|
181
|
+
[1, 1, 1, 1, 1],
|
|
182
|
+
[0, 0, 1, 0, 0]
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
function dilateAllenkEllipse5x5(values, width, height) {
|
|
186
|
+
const output = new Float32Array(values.length);
|
|
187
|
+
|
|
188
|
+
for (let y = 0; y < height; y++) {
|
|
189
|
+
for (let x = 0; x < width; x++) {
|
|
190
|
+
let maxValue = 0;
|
|
191
|
+
for (let ky = 0; ky < 5; ky++) {
|
|
192
|
+
for (let kx = 0; kx < 5; kx++) {
|
|
193
|
+
if (!ALLENK_ELLIPSE_5X5[ky][kx]) continue;
|
|
194
|
+
const sx = x + kx - 2;
|
|
195
|
+
const sy = y + ky - 2;
|
|
196
|
+
if (sx < 0 || sy < 0 || sx >= width || sy >= height) continue;
|
|
197
|
+
maxValue = Math.max(maxValue, values[sy * width + sx] || 0);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
output[y * width + x] = maxValue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return output;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function createAllenkOpenCvGradientMask({ alphaMap, width, height, strength }) {
|
|
208
|
+
if (!alphaMap || width <= 0 || height <= 0 || alphaMap.length < width * height) {
|
|
209
|
+
return new Float32Array(0);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const gradient = new Float32Array(width * height);
|
|
213
|
+
let minGradient = Number.POSITIVE_INFINITY;
|
|
214
|
+
let maxGradient = Number.NEGATIVE_INFINITY;
|
|
215
|
+
|
|
216
|
+
for (let y = 0; y < height; y++) {
|
|
217
|
+
for (let x = 0; x < width; x++) {
|
|
218
|
+
const top = reflect101(y - 1, height);
|
|
219
|
+
const bottom = reflect101(y + 1, height);
|
|
220
|
+
const left = reflect101(x - 1, width);
|
|
221
|
+
const right = reflect101(x + 1, width);
|
|
222
|
+
const gx = (
|
|
223
|
+
-alphaMap[top * width + left] -
|
|
224
|
+
2 * alphaMap[y * width + left] -
|
|
225
|
+
alphaMap[bottom * width + left] +
|
|
226
|
+
alphaMap[top * width + right] +
|
|
227
|
+
2 * alphaMap[y * width + right] +
|
|
228
|
+
alphaMap[bottom * width + right]
|
|
229
|
+
);
|
|
230
|
+
const gy = (
|
|
231
|
+
-alphaMap[top * width + left] -
|
|
232
|
+
2 * alphaMap[top * width + x] -
|
|
233
|
+
alphaMap[top * width + right] +
|
|
234
|
+
alphaMap[bottom * width + left] +
|
|
235
|
+
2 * alphaMap[bottom * width + x] +
|
|
236
|
+
alphaMap[bottom * width + right]
|
|
237
|
+
);
|
|
238
|
+
const value = Math.sqrt(gx * gx + gy * gy);
|
|
239
|
+
gradient[y * width + x] = value;
|
|
240
|
+
minGradient = Math.min(minGradient, value);
|
|
241
|
+
maxGradient = Math.max(maxGradient, value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!Number.isFinite(minGradient) || maxGradient <= minGradient) {
|
|
246
|
+
return new Float32Array(width * height);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const normalized = new Float32Array(width * height);
|
|
250
|
+
const scale = 1 / (maxGradient - minGradient);
|
|
251
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
252
|
+
normalized[i] = Math.sqrt(clamp((gradient[i] - minGradient) * scale, 0, 1));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const expanded = dilateAllenkEllipse5x5(normalized, width, height);
|
|
256
|
+
const blurred = gaussianBlurFloatMap(expanded, width, height, 2);
|
|
257
|
+
const safeStrength = Number.isFinite(strength) ? Math.max(0, strength) : 1;
|
|
258
|
+
|
|
259
|
+
for (let i = 0; i < blurred.length; i++) {
|
|
260
|
+
blurred[i] = clamp(blurred[i] * safeStrength, 0, 1);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return blurred;
|
|
264
|
+
}
|
|
265
|
+
|
|
126
266
|
function normalizeAllenkFdncnnOptions(options = {}) {
|
|
127
267
|
const sigma = Number.isFinite(options.sigma)
|
|
128
268
|
? clamp(options.sigma, 0, ALLENK_FDNCNN_MODEL.maxSigma)
|
|
@@ -145,17 +285,14 @@ function createAllenkGradientMask({
|
|
|
145
285
|
} = {}) {
|
|
146
286
|
const sourceSize = inferSquareSize(alphaMap);
|
|
147
287
|
const resizedAlphaMap = sourceSize > 0
|
|
148
|
-
?
|
|
288
|
+
? resizeSquareAlphaMapOpenCv(alphaMap, sourceSize, width, height)
|
|
149
289
|
: alphaMap;
|
|
150
290
|
|
|
151
|
-
return
|
|
291
|
+
return createAllenkOpenCvGradientMask({
|
|
152
292
|
alphaMap: resizedAlphaMap,
|
|
153
293
|
width,
|
|
154
294
|
height,
|
|
155
|
-
strength
|
|
156
|
-
gamma: 0.5,
|
|
157
|
-
dilateRadius: 2,
|
|
158
|
-
blurSigma: 2
|
|
295
|
+
strength
|
|
159
296
|
});
|
|
160
297
|
}
|
|
161
298
|
|
|
@@ -188,6 +325,154 @@ function calculateAllenkPaddedRoi({ imageWidth, imageHeight, region, padding = A
|
|
|
188
325
|
};
|
|
189
326
|
}
|
|
190
327
|
|
|
328
|
+
function calculateAllenkVirtualPaddedRoi({
|
|
329
|
+
imageWidth,
|
|
330
|
+
imageHeight,
|
|
331
|
+
region,
|
|
332
|
+
padding = ALLENK_FDNCNN_MODEL.defaultPadding,
|
|
333
|
+
targetWidth = null,
|
|
334
|
+
targetHeight = null
|
|
335
|
+
} = {}) {
|
|
336
|
+
if (!region || imageWidth <= 0 || imageHeight <= 0 || region.width <= 0 || region.height <= 0) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const safePadding = Math.max(0, Math.round(padding));
|
|
341
|
+
const x = Math.round(region.x - safePadding);
|
|
342
|
+
const y = Math.round(region.y - safePadding);
|
|
343
|
+
const defaultWidth = Math.round(region.width + safePadding * 2);
|
|
344
|
+
const defaultHeight = Math.round(region.height + safePadding * 2);
|
|
345
|
+
const width = Number.isInteger(targetWidth) && targetWidth > 0 ? targetWidth : defaultWidth;
|
|
346
|
+
const height = Number.isInteger(targetHeight) && targetHeight > 0 ? targetHeight : defaultHeight;
|
|
347
|
+
|
|
348
|
+
if (width < 4 || height < 4) return null;
|
|
349
|
+
|
|
350
|
+
const visibleX = clamp(x, 0, imageWidth);
|
|
351
|
+
const visibleY = clamp(y, 0, imageHeight);
|
|
352
|
+
const visibleRight = clamp(x + width, 0, imageWidth);
|
|
353
|
+
const visibleBottom = clamp(y + height, 0, imageHeight);
|
|
354
|
+
const visibleWidth = visibleRight - visibleX;
|
|
355
|
+
const visibleHeight = visibleBottom - visibleY;
|
|
356
|
+
if (visibleWidth <= 0 || visibleHeight <= 0) return null;
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
x,
|
|
360
|
+
y,
|
|
361
|
+
width,
|
|
362
|
+
height,
|
|
363
|
+
inner: {
|
|
364
|
+
x: clamp(Math.round(region.x - x), 0, width),
|
|
365
|
+
y: clamp(Math.round(region.y - y), 0, height),
|
|
366
|
+
width: clamp(Math.round(region.width), 0, width),
|
|
367
|
+
height: clamp(Math.round(region.height), 0, height)
|
|
368
|
+
},
|
|
369
|
+
visible: {
|
|
370
|
+
x: visibleX,
|
|
371
|
+
y: visibleY,
|
|
372
|
+
width: visibleWidth,
|
|
373
|
+
height: visibleHeight,
|
|
374
|
+
offsetX: visibleX - x,
|
|
375
|
+
offsetY: visibleY - y
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function calculateAllenkRuntimeRoi({
|
|
381
|
+
imageWidth,
|
|
382
|
+
imageHeight,
|
|
383
|
+
region,
|
|
384
|
+
padding = ALLENK_FDNCNN_MODEL.defaultPadding,
|
|
385
|
+
targetWidth = null,
|
|
386
|
+
targetHeight = null
|
|
387
|
+
} = {}) {
|
|
388
|
+
const padded = calculateAllenkPaddedRoi({ imageWidth, imageHeight, region, padding });
|
|
389
|
+
if (!padded) return null;
|
|
390
|
+
|
|
391
|
+
const safeTargetWidth = Number.isInteger(targetWidth) && targetWidth > 0 ? targetWidth : null;
|
|
392
|
+
const safeTargetHeight = Number.isInteger(targetHeight) && targetHeight > 0 ? targetHeight : null;
|
|
393
|
+
if (
|
|
394
|
+
!safeTargetWidth ||
|
|
395
|
+
!safeTargetHeight ||
|
|
396
|
+
imageWidth < safeTargetWidth ||
|
|
397
|
+
imageHeight < safeTargetHeight ||
|
|
398
|
+
padded.width > safeTargetWidth ||
|
|
399
|
+
padded.height > safeTargetHeight
|
|
400
|
+
) {
|
|
401
|
+
return padded;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const centerX = region.x + region.width / 2;
|
|
405
|
+
const centerY = region.y + region.height / 2;
|
|
406
|
+
const x = clamp(Math.round(centerX - safeTargetWidth / 2), 0, imageWidth - safeTargetWidth);
|
|
407
|
+
const y = clamp(Math.round(centerY - safeTargetHeight / 2), 0, imageHeight - safeTargetHeight);
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
x,
|
|
411
|
+
y,
|
|
412
|
+
width: safeTargetWidth,
|
|
413
|
+
height: safeTargetHeight,
|
|
414
|
+
inner: {
|
|
415
|
+
x: clamp(Math.round(region.x - x), 0, safeTargetWidth),
|
|
416
|
+
y: clamp(Math.round(region.y - y), 0, safeTargetHeight),
|
|
417
|
+
width: clamp(Math.round(region.width), 0, safeTargetWidth),
|
|
418
|
+
height: clamp(Math.round(region.height), 0, safeTargetHeight)
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function extractAllenkVirtualImageData({
|
|
424
|
+
imageData,
|
|
425
|
+
roi,
|
|
426
|
+
imageX = 0,
|
|
427
|
+
imageY = 0,
|
|
428
|
+
canvasWidth = imageData?.width || 0,
|
|
429
|
+
canvasHeight = imageData?.height || 0
|
|
430
|
+
} = {}) {
|
|
431
|
+
if (
|
|
432
|
+
!imageData?.data ||
|
|
433
|
+
!roi ||
|
|
434
|
+
imageData.width <= 0 ||
|
|
435
|
+
imageData.height <= 0 ||
|
|
436
|
+
roi.width <= 0 ||
|
|
437
|
+
roi.height <= 0 ||
|
|
438
|
+
canvasWidth <= 0 ||
|
|
439
|
+
canvasHeight <= 0
|
|
440
|
+
) {
|
|
441
|
+
return { width: 0, height: 0, data: new Uint8ClampedArray(0) };
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const width = Math.max(1, Math.round(roi.width));
|
|
445
|
+
const height = Math.max(1, Math.round(roi.height));
|
|
446
|
+
const output = new Uint8ClampedArray(width * height * 4);
|
|
447
|
+
const sourceStride = imageData.data.length >= imageData.width * imageData.height * 4 ? 4 : 3;
|
|
448
|
+
|
|
449
|
+
for (let y = 0; y < height; y++) {
|
|
450
|
+
const globalY = clamp(Math.round(roi.y + y), 0, canvasHeight - 1);
|
|
451
|
+
const localY = clamp(globalY - Math.round(imageY), 0, imageData.height - 1);
|
|
452
|
+
for (let x = 0; x < width; x++) {
|
|
453
|
+
const globalX = clamp(Math.round(roi.x + x), 0, canvasWidth - 1);
|
|
454
|
+
const localX = clamp(globalX - Math.round(imageX), 0, imageData.width - 1);
|
|
455
|
+
const src = (localY * imageData.width + localX) * sourceStride;
|
|
456
|
+
const dst = (y * width + x) * 4;
|
|
457
|
+
output[dst] = imageData.data[src] || 0;
|
|
458
|
+
output[dst + 1] = imageData.data[src + 1] || 0;
|
|
459
|
+
output[dst + 2] = imageData.data[src + 2] || 0;
|
|
460
|
+
output[dst + 3] = sourceStride >= 4 ? (imageData.data[src + 3] ?? 255) : 255;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const ImageDataCtor = typeof imageData.constructor === 'function' && imageData.constructor !== Object
|
|
465
|
+
? imageData.constructor
|
|
466
|
+
: typeof ImageData === 'function'
|
|
467
|
+
? ImageData
|
|
468
|
+
: null;
|
|
469
|
+
if (ImageDataCtor) {
|
|
470
|
+
return new ImageDataCtor(output, width, height);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return { width, height, data: output };
|
|
474
|
+
}
|
|
475
|
+
|
|
191
476
|
function embedAllenkRoiWeights({ roiWeights, roiWidth, roiHeight, paddedRoi, blurSigma = 1 } = {}) {
|
|
192
477
|
if (!roiWeights || !paddedRoi?.inner || roiWidth <= 0 || roiHeight <= 0) {
|
|
193
478
|
return new Float32Array(0);
|
|
@@ -319,8 +604,11 @@ export {
|
|
|
319
604
|
blendAllenkDenoisedRoi,
|
|
320
605
|
buildAllenkFdncnnInput,
|
|
321
606
|
calculateAllenkPaddedRoi,
|
|
607
|
+
calculateAllenkRuntimeRoi,
|
|
608
|
+
calculateAllenkVirtualPaddedRoi,
|
|
322
609
|
convertAllenkFdncnnOutputToRgba,
|
|
323
610
|
createAllenkGradientMask,
|
|
324
611
|
embedAllenkRoiWeights,
|
|
612
|
+
extractAllenkVirtualImageData,
|
|
325
613
|
normalizeAllenkFdncnnOptions
|
|
326
614
|
};
|
|
@@ -231,12 +231,13 @@ function createGraphProto({
|
|
|
231
231
|
segments,
|
|
232
232
|
inputName,
|
|
233
233
|
outputName,
|
|
234
|
-
|
|
234
|
+
roiWidth,
|
|
235
|
+
roiHeight
|
|
235
236
|
}) {
|
|
236
237
|
const initializers = createInitializers({ bin, segments });
|
|
237
238
|
const nodes = createNodes({ segments, inputName, outputName });
|
|
238
|
-
const inputShape = [1, segments[0].inputChannels,
|
|
239
|
-
const outputShape = [1, segments[segments.length - 1].outputChannels,
|
|
239
|
+
const inputShape = [1, segments[0].inputChannels, roiHeight, roiWidth];
|
|
240
|
+
const outputShape = [1, segments[segments.length - 1].outputChannels, roiHeight, roiWidth];
|
|
240
241
|
|
|
241
242
|
return {
|
|
242
243
|
nodeCount: nodes.length,
|
|
@@ -275,6 +276,8 @@ function exportAllenkFdncnnOnnx({
|
|
|
275
276
|
bin,
|
|
276
277
|
weightLayout,
|
|
277
278
|
roiSize = 72,
|
|
279
|
+
roiWidth = roiSize,
|
|
280
|
+
roiHeight = roiSize,
|
|
278
281
|
inputName = 'fdncnn_input',
|
|
279
282
|
outputName = 'fdncnn_output',
|
|
280
283
|
graphName = 'allenk_fdncnn_color',
|
|
@@ -285,8 +288,11 @@ function exportAllenkFdncnnOnnx({
|
|
|
285
288
|
if (!segments.length) {
|
|
286
289
|
throw new Error('allenk FDnCNN ONNX export requires weightLayout.segments');
|
|
287
290
|
}
|
|
288
|
-
if (!Number.isInteger(
|
|
289
|
-
throw new Error(`Invalid ONNX ROI
|
|
291
|
+
if (!Number.isInteger(roiWidth) || roiWidth <= 0) {
|
|
292
|
+
throw new Error(`Invalid ONNX ROI width: ${roiWidth}`);
|
|
293
|
+
}
|
|
294
|
+
if (!Number.isInteger(roiHeight) || roiHeight <= 0) {
|
|
295
|
+
throw new Error(`Invalid ONNX ROI height: ${roiHeight}`);
|
|
290
296
|
}
|
|
291
297
|
|
|
292
298
|
const graph = createGraphProto({
|
|
@@ -295,7 +301,8 @@ function exportAllenkFdncnnOnnx({
|
|
|
295
301
|
segments,
|
|
296
302
|
inputName,
|
|
297
303
|
outputName,
|
|
298
|
-
|
|
304
|
+
roiWidth,
|
|
305
|
+
roiHeight
|
|
299
306
|
});
|
|
300
307
|
const model = createModelProto({
|
|
301
308
|
graph: graph.bytes,
|
|
@@ -313,13 +320,15 @@ function exportAllenkFdncnnOnnx({
|
|
|
313
320
|
graphName,
|
|
314
321
|
inputName,
|
|
315
322
|
outputName,
|
|
316
|
-
inputShape: [1, segments[0].inputChannels,
|
|
317
|
-
outputShape: [1, segments[segments.length - 1].outputChannels,
|
|
323
|
+
inputShape: [1, segments[0].inputChannels, roiHeight, roiWidth],
|
|
324
|
+
outputShape: [1, segments[segments.length - 1].outputChannels, roiHeight, roiWidth],
|
|
318
325
|
nodeCount: graph.nodeCount,
|
|
319
326
|
convolutionNodeCount: segments.length,
|
|
320
327
|
reluNodeCount: segments.filter((segment, index) => index < segments.length - 1 && segment.activationType === 1).length,
|
|
321
328
|
initializerCount: graph.initializerCount,
|
|
322
|
-
roiSize
|
|
329
|
+
roiSize: roiWidth === roiHeight ? roiWidth : null,
|
|
330
|
+
roiWidth,
|
|
331
|
+
roiHeight
|
|
323
332
|
}
|
|
324
333
|
};
|
|
325
334
|
}
|