@pexip/media-processor 20.3.5 → 21.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/CHANGELOG.md +39 -0
- package/api-docs/README.mdx +33 -6
- package/api-docs/functions/createBenchmark.mdx +17 -5
- package/api-docs/functions/createWindowedStats.mdx +23 -0
- package/api-docs/functions/iou.mdx +19 -0
- package/api-docs/functions/labelComponents.mdx +20 -0
- package/api-docs/functions/nearestPowerOfTwo.mdx +21 -0
- package/api-docs/functions/playVideo.mdx +16 -0
- package/api-docs/functions/scoreComponent.mdx +22 -0
- package/api-docs/functions/setVideoElementSrc.mdx +14 -0
- package/api-docs/interfaces/Benchmark.mdx +12 -0
- package/api-docs/interfaces/RendererOptions.mdx +26 -9
- package/api-docs/interfaces/SegmentationParams.mdx +29 -12
- package/api-docs/interfaces/SelectionOptions.mdx +15 -0
- package/api-docs/interfaces/Stats.mdx +11 -0
- package/api-docs/interfaces/Weights.mdx +12 -0
- package/api-docs/type-aliases/OptionalKeys.mdx +10 -0
- package/api-docs/variables/BACKGROUND_THRESHOLD.mdx +3 -0
- package/api-docs/variables/DOWN_SAMPLE_FACTOR.mdx +3 -0
- package/api-docs/variables/EDGE_BLUR_AMOUNT.mdx +1 -1
- package/api-docs/variables/EXCLUDE_BYSTANDERS.mdx +3 -0
- package/api-docs/variables/FOREGROUND_THRESHOLD.mdx +1 -1
- package/api-docs/variables/LIGHT_WRAP_BLUR_AMOUNT.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_EDGE_BAND.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_INTENSITY.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_TIGHTNESS.mdx +3 -0
- package/api-docs/variables/MASK_COMBINE_RATIO.mdx +1 -1
- package/api-docs/variables/MORPH_DILATE_RADIUS_PX.mdx +3 -0
- package/api-docs/variables/MORPH_ERODE_RADIUS_PX.mdx +3 -0
- package/api-docs/variables/MORPH_PASS.mdx +3 -0
- package/api-docs/variables/PERSON_CENTER.mdx +3 -0
- package/api-docs/variables/SIGMA_RANGE.mdx +3 -0
- package/api-docs/variables/SIGMA_SPACE.mdx +3 -0
- package/api-docs/variables/STRONG_EDGE_BLUR_AMOUNT.mdx +3 -0
- package/api-docs/variables/getCanvasRenderingContext2D.mdx +14 -0
- package/api-docs/variables/getImageSize.mdx +13 -0
- package/dist/common/backends/webgl/binaryMask.d.ts +8 -0
- package/dist/common/backends/webgl/binaryMask.js +95 -0
- package/dist/common/backends/webgl/blender.d.ts +2 -1
- package/dist/common/backends/webgl/blender.js +18 -15
- package/dist/common/backends/webgl/blur.d.ts +1 -1
- package/dist/common/backends/webgl/blur.js +23 -16
- package/dist/common/backends/webgl/canvas.js +9 -4
- package/dist/common/backends/webgl/diffAbsMask.d.ts +10 -0
- package/dist/common/backends/webgl/diffAbsMask.js +103 -0
- package/dist/common/backends/webgl/geodesicReconstruction.d.ts +13 -0
- package/dist/common/backends/webgl/geodesicReconstruction.js +176 -0
- package/dist/common/backends/webgl/jointBilateralFilter.d.ts +12 -0
- package/dist/common/backends/webgl/jointBilateralFilter.js +108 -0
- package/dist/common/backends/webgl/morphErode.d.ts +13 -0
- package/dist/common/backends/webgl/morphErode.js +121 -0
- package/dist/common/backends/webgl/renderer.js +194 -34
- package/dist/common/backends/webgl/replace.d.ts +17 -0
- package/dist/common/backends/webgl/replace.js +126 -0
- package/dist/common/backends/webgl/selectComponent.d.ts +15 -0
- package/dist/common/backends/webgl/selectComponent.js +102 -0
- package/dist/common/backends/webgl/smoothingMask.d.ts +3 -3
- package/dist/common/backends/webgl/smoothingMask.js +22 -21
- package/dist/common/backends/webgl/tentBlur.d.ts +9 -0
- package/dist/common/backends/webgl/tentBlur.js +118 -0
- package/dist/common/backends/webgl/texture.d.ts +1 -1
- package/dist/common/backends/webgl/texture.js +19 -17
- package/dist/common/backends/webgl/textureToTexture.d.ts +1 -1
- package/dist/common/backends/webgl/textureToTexture.js +19 -16
- package/dist/common/backends/webgl/webglUtils.d.ts +7 -1
- package/dist/common/backends/webgl/webglUtils.js +64 -6
- package/dist/common/backends/webgpu/blender.d.ts +6 -1
- package/dist/common/backends/webgpu/blender.js +96 -51
- package/dist/common/backends/webgpu/constants.js +1 -1
- package/dist/common/backends/webgpu/dualFilterBlur.d.ts +2 -3
- package/dist/common/backends/webgpu/dualFilterBlur.js +146 -140
- package/dist/common/backends/webgpu/jointBilateralFilter.d.ts +7 -0
- package/dist/common/backends/webgpu/jointBilateralFilter.js +162 -0
- package/dist/common/backends/webgpu/renderer.js +211 -39
- package/dist/common/backends/webgpu/replace.d.ts +11 -0
- package/dist/common/backends/webgpu/replace.js +175 -0
- package/dist/common/backends/webgpu/resize.d.ts +4 -0
- package/dist/common/backends/webgpu/resize.js +76 -0
- package/dist/common/backends/webgpu/smoothingMask.d.ts +2 -2
- package/dist/common/backends/webgpu/smoothingMask.js +74 -40
- package/dist/common/backends/webgpu/tentBlur.d.ts +5 -0
- package/dist/common/backends/webgpu/tentBlur.js +131 -0
- package/dist/common/backends/webgpu/texture.d.ts +2 -2
- package/dist/common/backends/webgpu/texture.js +24 -19
- package/dist/common/backends/webgpu/textureToTexture.d.ts +1 -1
- package/dist/common/backends/webgpu/textureToTexture.js +28 -15
- package/dist/common/backends/webgpu/types.d.ts +2 -0
- package/dist/common/backends/webgpu/webgpuUtils.d.ts +24 -4
- package/dist/common/backends/webgpu/webgpuUtils.js +60 -11
- package/dist/common/constants.d.ts +19 -5
- package/dist/common/constants.js +19 -5
- package/dist/common/index.d.ts +1 -0
- package/dist/common/index.js +1 -0
- package/dist/common/tsconfig.tsbuildinfo +1 -1
- package/dist/common/types/render.d.ts +142 -13
- package/dist/common/types/utils.d.ts +21 -0
- package/dist/common/utils.d.ts +16 -0
- package/dist/common/utils.js +152 -0
- package/dist/main/benchUtils.d.ts +33 -1
- package/dist/main/benchUtils.js +145 -11
- package/dist/main/tsconfig.tsbuildinfo +1 -1
- package/dist/main/video/canvasTransform.d.ts +1 -1
- package/dist/main/video/canvasTransform.js +135 -47
- package/dist/main/video/index.d.ts +1 -1
- package/dist/main/video/index.js +1 -1
- package/dist/workers/mediaWorker.js +35 -162
- package/dist/workers/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/dist/common/backends/webgl/shaders/blendFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/blendFragmentShader.js +0 -21
- package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.js +0 -45
- package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.js +0 -57
- package/dist/common/backends/webgl/shaders/textureFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/textureFragmentShader.js +0 -16
- package/dist/common/backends/webgl/shaders/vertexShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/vertexShader.js +0 -19
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TextureInfo } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Create a binary mask renderer based on the provided threshold
|
|
4
|
+
*/
|
|
5
|
+
export declare const createBinaryMaskRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
|
|
6
|
+
render: (mask: TextureInfo, threshold: number) => TextureInfo;
|
|
7
|
+
release: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { assert } from '@pexip/utils';
|
|
2
|
+
import { m3 } from '../../m3';
|
|
3
|
+
import { RENDERING_EVENTS } from '../../constants';
|
|
4
|
+
import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
|
|
5
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
6
|
+
import fragmentSrc from './shaders/binaryMask.frag';
|
|
7
|
+
/**
|
|
8
|
+
* Create a binary mask renderer based on the provided threshold
|
|
9
|
+
*/
|
|
10
|
+
export const createBinaryMaskRenderer = (processor, width, height) => {
|
|
11
|
+
const { gl, program, attribLocations, uniformLocations, floatFullChannelSupported, floatSingleChannelSupported, release, } = createGLProgram(processor, {
|
|
12
|
+
attribs: {
|
|
13
|
+
position: 'a_position',
|
|
14
|
+
texCoord: 'a_texCoord',
|
|
15
|
+
},
|
|
16
|
+
uniforms: {
|
|
17
|
+
matrix: 'u_matrix',
|
|
18
|
+
mask: 'u_mask',
|
|
19
|
+
size: 'u_size',
|
|
20
|
+
threshold: 'u_threshold',
|
|
21
|
+
},
|
|
22
|
+
vertexSrc,
|
|
23
|
+
fragmentSrc,
|
|
24
|
+
});
|
|
25
|
+
const vao = gl.createVertexArray();
|
|
26
|
+
gl.bindVertexArray(vao);
|
|
27
|
+
// Position
|
|
28
|
+
const positionBuffer = gl.createBuffer();
|
|
29
|
+
gl.enableVertexAttribArray(attribLocations.position);
|
|
30
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
31
|
+
gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
|
|
32
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
33
|
+
// prettier-ignore
|
|
34
|
+
new Float32Array([
|
|
35
|
+
0, 0,
|
|
36
|
+
0, 1,
|
|
37
|
+
1, 0,
|
|
38
|
+
1, 0,
|
|
39
|
+
0, 1,
|
|
40
|
+
1, 1,
|
|
41
|
+
]), gl.STATIC_DRAW);
|
|
42
|
+
// Texture coordinates for the rectangle
|
|
43
|
+
const texCoordBuffer = gl.createBuffer();
|
|
44
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
45
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
46
|
+
// prettier-ignore
|
|
47
|
+
new Float32Array([
|
|
48
|
+
0, 0,
|
|
49
|
+
0, 1,
|
|
50
|
+
1, 0,
|
|
51
|
+
1, 0,
|
|
52
|
+
0, 1,
|
|
53
|
+
1, 1,
|
|
54
|
+
]), gl.STATIC_DRAW);
|
|
55
|
+
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
56
|
+
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
57
|
+
const outputTexture = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
|
|
58
|
+
const frameBuffer = createFrameBuffer(gl, outputTexture);
|
|
59
|
+
return {
|
|
60
|
+
render: (mask, threshold) => {
|
|
61
|
+
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
62
|
+
gl.clearColor(0, 0, 0, 0);
|
|
63
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
64
|
+
gl.useProgram(program);
|
|
65
|
+
gl.bindVertexArray(vao);
|
|
66
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
67
|
+
gl.viewport(0, 0, width, height);
|
|
68
|
+
// Textures
|
|
69
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
70
|
+
gl.uniform1i(uniformLocations.mask, 0);
|
|
71
|
+
gl.bindTexture(gl.TEXTURE_2D, mask.texture);
|
|
72
|
+
gl.uniform2i(uniformLocations.size, mask.width, mask.height);
|
|
73
|
+
gl.uniform1f(uniformLocations.threshold, threshold);
|
|
74
|
+
// No Flip Y Coordinate for drawing on the frame buffer
|
|
75
|
+
// Project, position and scale to full-size of the canvas
|
|
76
|
+
const matrix = m3.projection(1, 1, 1);
|
|
77
|
+
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
78
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
79
|
+
// Cleanup
|
|
80
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
81
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
82
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
83
|
+
gl.bindVertexArray(null);
|
|
84
|
+
return { texture: outputTexture, width, height };
|
|
85
|
+
},
|
|
86
|
+
release: () => {
|
|
87
|
+
gl.deleteBuffer(positionBuffer);
|
|
88
|
+
gl.deleteBuffer(texCoordBuffer);
|
|
89
|
+
gl.deleteTexture(outputTexture);
|
|
90
|
+
gl.deleteFramebuffer(frameBuffer);
|
|
91
|
+
gl.deleteVertexArray(vao);
|
|
92
|
+
release();
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RendererOptions } from '../../types/render';
|
|
1
2
|
import type { TextureInfo } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* Blend foreground and background according to the mask
|
|
@@ -7,6 +8,6 @@ export declare const createBlendRenderer: (processor: OffscreenCanvas) => {
|
|
|
7
8
|
mask: TextureInfo;
|
|
8
9
|
foreground: TextureInfo;
|
|
9
10
|
background: TextureInfo;
|
|
10
|
-
}) => TextureInfo;
|
|
11
|
+
}, options: RendererOptions) => TextureInfo;
|
|
11
12
|
release: () => void;
|
|
12
13
|
};
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import { assert } from '@pexip/utils';
|
|
2
2
|
import { RENDERING_EVENTS } from '../../constants';
|
|
3
3
|
import { m3 } from '../../m3';
|
|
4
|
-
import { createGLProgram,
|
|
5
|
-
import
|
|
6
|
-
import
|
|
4
|
+
import { createFrameBuffer, createGLProgram, createRGBAFrameTexture, } from './webglUtils';
|
|
5
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
6
|
+
import fragmentSrc from './shaders/blend.frag';
|
|
7
7
|
/**
|
|
8
8
|
* Blend foreground and background according to the mask
|
|
9
9
|
*/
|
|
10
10
|
export const createBlendRenderer = (processor) => {
|
|
11
|
-
const { gl, program, attribLocations, uniformLocations, release } = createGLProgram(processor, {
|
|
11
|
+
const { gl, program, attribLocations, floatFullChannelSupported, uniformLocations, release, } = createGLProgram(processor, {
|
|
12
12
|
attribs: {
|
|
13
13
|
position: 'a_position',
|
|
14
14
|
texCoord: 'a_texCoord',
|
|
15
15
|
},
|
|
16
16
|
uniforms: {
|
|
17
17
|
matrix: 'u_matrix',
|
|
18
|
+
mask: 'u_mask',
|
|
18
19
|
frameBackground: 'u_frame_background',
|
|
19
20
|
frameForeground: 'u_frame_foreground',
|
|
20
|
-
|
|
21
|
+
confidenceThresholds: 'u_confidence_thresholds',
|
|
21
22
|
},
|
|
22
|
-
vertexSrc
|
|
23
|
-
fragmentSrc
|
|
23
|
+
vertexSrc,
|
|
24
|
+
fragmentSrc,
|
|
24
25
|
});
|
|
25
26
|
gl.enable(gl.BLEND);
|
|
26
27
|
const vao = gl.createVertexArray();
|
|
@@ -55,18 +56,16 @@ export const createBlendRenderer = (processor) => {
|
|
|
55
56
|
]), gl.STATIC_DRAW);
|
|
56
57
|
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
57
58
|
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
58
|
-
const outputTexture =
|
|
59
|
-
|
|
60
|
-
const frameBuffer = gl.createFramebuffer();
|
|
61
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
62
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, outputTexture, 0);
|
|
59
|
+
const outputTexture = createRGBAFrameTexture(gl, processor.width, processor.height, true, floatFullChannelSupported);
|
|
60
|
+
const frameBuffer = createFrameBuffer(gl, outputTexture);
|
|
63
61
|
return {
|
|
64
|
-
render: ({ mask, foreground, background, }) => {
|
|
62
|
+
render: ({ mask, foreground, background, }, options) => {
|
|
65
63
|
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
64
|
+
gl.useProgram(program);
|
|
66
65
|
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
67
66
|
gl.viewport(0, 0, processor.width, processor.height);
|
|
68
|
-
gl.useProgram(program);
|
|
69
67
|
gl.bindVertexArray(vao);
|
|
68
|
+
gl.uniform2f(uniformLocations.confidenceThresholds, options.backgroundThreshold, options.foregroundThreshold);
|
|
70
69
|
// Textures
|
|
71
70
|
gl.activeTexture(gl.TEXTURE0);
|
|
72
71
|
gl.uniform1i(uniformLocations.frameForeground, 0);
|
|
@@ -82,7 +81,11 @@ export const createBlendRenderer = (processor) => {
|
|
|
82
81
|
const matrix = m3.projection(1, 1, 1);
|
|
83
82
|
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
84
83
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
85
|
-
|
|
84
|
+
// Cleanup
|
|
85
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
86
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
87
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
88
|
+
gl.bindVertexArray(null);
|
|
86
89
|
return {
|
|
87
90
|
texture: outputTexture,
|
|
88
91
|
width: processor.width,
|
|
@@ -2,7 +2,7 @@ import type { TextureInfo } from './types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Blur provided frame
|
|
4
4
|
*/
|
|
5
|
-
export declare const createBlurRenderer: (processor: OffscreenCanvas, pass: number) => {
|
|
5
|
+
export declare const createBlurRenderer: (processor: OffscreenCanvas, pass: number, redOnly?: boolean) => {
|
|
6
6
|
render: (frame: TextureInfo, pass: number) => TextureInfo;
|
|
7
7
|
release: () => void;
|
|
8
8
|
};
|
|
@@ -2,15 +2,15 @@ import { assert } from '@pexip/utils';
|
|
|
2
2
|
import { clamping } from '../../utils';
|
|
3
3
|
import { RENDERING_EVENTS } from '../../constants';
|
|
4
4
|
import { m3 } from '../../m3';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
5
|
+
import { createFrameBuffer, createGLProgram, createMaskTexture, createRGBAFrameTexture, } from './webglUtils';
|
|
6
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
7
|
+
import fragmentSrc from './shaders/dualFilterBlur.frag';
|
|
8
8
|
const clampBlurAmount = clamping(1, 9);
|
|
9
9
|
/**
|
|
10
10
|
* Blur provided frame
|
|
11
11
|
*/
|
|
12
|
-
export const createBlurRenderer = (processor, pass) => {
|
|
13
|
-
const { gl, program, attribLocations, uniformLocations, release } = createGLProgram(processor, {
|
|
12
|
+
export const createBlurRenderer = (processor, pass, redOnly = false) => {
|
|
13
|
+
const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
|
|
14
14
|
attribs: {
|
|
15
15
|
position: 'a_position',
|
|
16
16
|
texCoord: 'a_texCoord',
|
|
@@ -20,8 +20,8 @@ export const createBlurRenderer = (processor, pass) => {
|
|
|
20
20
|
downsampling: 'u_downsampling',
|
|
21
21
|
frame: 'u_frame',
|
|
22
22
|
},
|
|
23
|
-
vertexSrc
|
|
24
|
-
fragmentSrc
|
|
23
|
+
vertexSrc,
|
|
24
|
+
fragmentSrc,
|
|
25
25
|
});
|
|
26
26
|
const vao = gl.createVertexArray();
|
|
27
27
|
gl.bindVertexArray(vao);
|
|
@@ -61,18 +61,13 @@ export const createBlurRenderer = (processor, pass) => {
|
|
|
61
61
|
gl.viewport(0, 0, width, height);
|
|
62
62
|
};
|
|
63
63
|
const createFramebufferAndTexture = (idx) => {
|
|
64
|
-
const texture = createAndSetupTexture(gl);
|
|
65
|
-
assert(texture);
|
|
66
64
|
// Avoid fractional value
|
|
67
65
|
const width = Math.trunc(processor.width / 2 ** idx);
|
|
68
66
|
const height = Math.trunc(processor.height / 2 ** idx);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Attach a texture to it.
|
|
74
|
-
const attachmentPoint = gl.COLOR_ATTACHMENT0;
|
|
75
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, texture, 0);
|
|
67
|
+
const texture = redOnly
|
|
68
|
+
? createMaskTexture(gl, width, height, true, floatSingleChannelSupported, floatFullChannelSupported)
|
|
69
|
+
: createRGBAFrameTexture(gl, width, height, true, floatFullChannelSupported);
|
|
70
|
+
const frameBuffer = createFrameBuffer(gl, texture);
|
|
76
71
|
return { texture, frameBuffer, width, height };
|
|
77
72
|
};
|
|
78
73
|
const generateBlurBuffers = (pass, offset = 0) => {
|
|
@@ -87,6 +82,13 @@ export const createBlurRenderer = (processor, pass) => {
|
|
|
87
82
|
return {
|
|
88
83
|
render: (frame, pass) => {
|
|
89
84
|
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
85
|
+
if (!pass) {
|
|
86
|
+
return {
|
|
87
|
+
texture: frame.texture,
|
|
88
|
+
width: frame.width,
|
|
89
|
+
height: frame.height,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
90
92
|
gl.useProgram(program);
|
|
91
93
|
gl.bindVertexArray(vao);
|
|
92
94
|
// Frame texture
|
|
@@ -153,6 +155,11 @@ export const createBlurRenderer = (processor, pass) => {
|
|
|
153
155
|
// for the next draw, use the texture we just rendered to.
|
|
154
156
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
155
157
|
}
|
|
158
|
+
// Cleanup
|
|
159
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
160
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
161
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
162
|
+
gl.bindVertexArray(null);
|
|
156
163
|
return {
|
|
157
164
|
texture: blurBuffers[0]?.texture ?? frame.texture,
|
|
158
165
|
width: blurBuffers[0]?.width ?? frame.width,
|
|
@@ -2,8 +2,8 @@ import { assert } from '@pexip/utils';
|
|
|
2
2
|
import { m3 } from '../../m3';
|
|
3
3
|
import { RENDERING_EVENTS } from '../../constants';
|
|
4
4
|
import { createGLProgram } from './webglUtils';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
6
|
+
import fragmentSrc from './shaders/texture.frag';
|
|
7
7
|
/**
|
|
8
8
|
* Render texture to the processing canvas framebuffer
|
|
9
9
|
*/
|
|
@@ -17,8 +17,8 @@ export const createCanvasRenderer = (processor) => {
|
|
|
17
17
|
matrix: 'u_matrix',
|
|
18
18
|
texture: 'u_texture',
|
|
19
19
|
},
|
|
20
|
-
vertexSrc
|
|
21
|
-
fragmentSrc
|
|
20
|
+
vertexSrc,
|
|
21
|
+
fragmentSrc,
|
|
22
22
|
});
|
|
23
23
|
const vao = gl.createVertexArray();
|
|
24
24
|
gl.bindVertexArray(vao);
|
|
@@ -72,6 +72,11 @@ export const createCanvasRenderer = (processor) => {
|
|
|
72
72
|
gl.activeTexture(gl.TEXTURE0);
|
|
73
73
|
gl.bindTexture(gl.TEXTURE_2D, texture.texture);
|
|
74
74
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
75
|
+
// Cleanup
|
|
76
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
77
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
78
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
79
|
+
gl.bindVertexArray(null);
|
|
75
80
|
},
|
|
76
81
|
release: () => {
|
|
77
82
|
gl.deleteBuffer(positionBuffer);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TextureInfo } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Create absulute difference renderer to caculate the difference between 2 textures
|
|
4
|
+
*/
|
|
5
|
+
export declare const createDiffAbsRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
|
|
6
|
+
render: (textureA: TextureInfo, textureB: TextureInfo) => TextureInfo & {
|
|
7
|
+
frameBuffer: WebGLFramebuffer;
|
|
8
|
+
};
|
|
9
|
+
release: () => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { assert } from '@pexip/utils';
|
|
2
|
+
import { m3 } from '../../m3';
|
|
3
|
+
import { RENDERING_EVENTS } from '../../constants';
|
|
4
|
+
import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
|
|
5
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
6
|
+
import fragmentSrc from './shaders/diffAbs.frag';
|
|
7
|
+
/**
|
|
8
|
+
* Create absulute difference renderer to caculate the difference between 2 textures
|
|
9
|
+
*/
|
|
10
|
+
export const createDiffAbsRenderer = (processor, width, height) => {
|
|
11
|
+
const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
|
|
12
|
+
attribs: {
|
|
13
|
+
position: 'a_position',
|
|
14
|
+
texCoord: 'a_texCoord',
|
|
15
|
+
},
|
|
16
|
+
uniforms: {
|
|
17
|
+
matrix: 'u_matrix',
|
|
18
|
+
texA: 'u_tex_a',
|
|
19
|
+
texB: 'u_tex_b',
|
|
20
|
+
size: 'u_size',
|
|
21
|
+
},
|
|
22
|
+
vertexSrc,
|
|
23
|
+
fragmentSrc,
|
|
24
|
+
});
|
|
25
|
+
const vao = gl.createVertexArray();
|
|
26
|
+
gl.bindVertexArray(vao);
|
|
27
|
+
// Position
|
|
28
|
+
const positionBuffer = gl.createBuffer();
|
|
29
|
+
gl.enableVertexAttribArray(attribLocations.position);
|
|
30
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
31
|
+
gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
|
|
32
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
33
|
+
// prettier-ignore
|
|
34
|
+
new Float32Array([
|
|
35
|
+
0, 0,
|
|
36
|
+
0, 1,
|
|
37
|
+
1, 0,
|
|
38
|
+
1, 0,
|
|
39
|
+
0, 1,
|
|
40
|
+
1, 1,
|
|
41
|
+
]), gl.STATIC_DRAW);
|
|
42
|
+
// Texture coordinates for the rectangle
|
|
43
|
+
const texCoordBuffer = gl.createBuffer();
|
|
44
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
45
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
46
|
+
// prettier-ignore
|
|
47
|
+
new Float32Array([
|
|
48
|
+
0, 0,
|
|
49
|
+
0, 1,
|
|
50
|
+
1, 0,
|
|
51
|
+
1, 0,
|
|
52
|
+
0, 1,
|
|
53
|
+
1, 1,
|
|
54
|
+
]), gl.STATIC_DRAW);
|
|
55
|
+
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
56
|
+
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
57
|
+
const outputTexturePing = createMaskTexture(gl, width, height, true, floatSingleChannelSupported, floatFullChannelSupported);
|
|
58
|
+
const frameBufferPing = createFrameBuffer(gl, outputTexturePing);
|
|
59
|
+
return {
|
|
60
|
+
render: (textureA, textureB) => {
|
|
61
|
+
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
62
|
+
assert(textureA.width === textureB.width &&
|
|
63
|
+
textureA.height === textureB.height);
|
|
64
|
+
gl.useProgram(program);
|
|
65
|
+
gl.bindVertexArray(vao);
|
|
66
|
+
gl.uniform2i(uniformLocations.size, textureA.width, textureA.height);
|
|
67
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
68
|
+
gl.uniform1i(uniformLocations.texA, 0);
|
|
69
|
+
gl.bindTexture(gl.TEXTURE_2D, textureA.texture);
|
|
70
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
71
|
+
gl.uniform1i(uniformLocations.texB, 1);
|
|
72
|
+
gl.bindTexture(gl.TEXTURE_2D, textureB.texture);
|
|
73
|
+
// No Flip Y Coordinate for drawing on the frame buffer
|
|
74
|
+
// Project, position and scale to full-size of the canvas
|
|
75
|
+
const matrix = m3.projection(1, 1, 1);
|
|
76
|
+
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
77
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBufferPing);
|
|
78
|
+
gl.viewport(0, 0, width, height);
|
|
79
|
+
gl.clearColor(0, 0, 0, 0);
|
|
80
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
81
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
82
|
+
// Cleanup
|
|
83
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
84
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
85
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
86
|
+
gl.bindVertexArray(null);
|
|
87
|
+
return {
|
|
88
|
+
texture: outputTexturePing,
|
|
89
|
+
frameBuffer: frameBufferPing,
|
|
90
|
+
width,
|
|
91
|
+
height,
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
release: () => {
|
|
95
|
+
gl.deleteBuffer(positionBuffer);
|
|
96
|
+
gl.deleteBuffer(texCoordBuffer);
|
|
97
|
+
gl.deleteTexture(outputTexturePing);
|
|
98
|
+
gl.deleteFramebuffer(frameBufferPing);
|
|
99
|
+
gl.deleteVertexArray(vao);
|
|
100
|
+
release();
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RendererOptions } from '../../types/render';
|
|
2
|
+
import type { TextureInfo } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* A Geodesic Reconstruction Renderer that performs geodesic dilation of
|
|
5
|
+
* a mask constrained by a reference mask.
|
|
6
|
+
*/
|
|
7
|
+
export declare const createGeodesicReconstructionRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
|
|
8
|
+
render: ({ mask, maskRef }: {
|
|
9
|
+
mask: TextureInfo;
|
|
10
|
+
maskRef: TextureInfo;
|
|
11
|
+
}, options: Pick<RendererOptions, "morphDilateRadiusPx" | "morphPass">) => TextureInfo;
|
|
12
|
+
release: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { assert } from '@pexip/utils';
|
|
2
|
+
import { m3 } from '../../m3';
|
|
3
|
+
import { RENDERING_EVENTS } from '../../constants';
|
|
4
|
+
import { clamping } from '../../utils';
|
|
5
|
+
import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
|
|
6
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
7
|
+
import fragmentSrc from './shaders/dilateClipToMask.frag';
|
|
8
|
+
import { createDiffAbsRenderer } from './diffAbsMask';
|
|
9
|
+
// Convergence threshold used when testing for geodesic reconstruction stability.
|
|
10
|
+
const CONVERGENCE_MAX_ITERATIONS = 64;
|
|
11
|
+
const MAX_RADIUS_PX = 64;
|
|
12
|
+
const clampRadiusPx = clamping(0, MAX_RADIUS_PX);
|
|
13
|
+
/**
|
|
14
|
+
* A Geodesic Reconstruction Renderer that performs geodesic dilation of
|
|
15
|
+
* a mask constrained by a reference mask.
|
|
16
|
+
*/
|
|
17
|
+
export const createGeodesicReconstructionRenderer = (processor, width, height) => {
|
|
18
|
+
const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
|
|
19
|
+
attribs: {
|
|
20
|
+
position: 'a_position',
|
|
21
|
+
texCoord: 'a_texCoord',
|
|
22
|
+
},
|
|
23
|
+
uniforms: {
|
|
24
|
+
matrix: 'u_matrix',
|
|
25
|
+
mask: 'u_mask',
|
|
26
|
+
maskRef: 'u_ref_mask',
|
|
27
|
+
texelSize: 'u_texel_size',
|
|
28
|
+
radiusPx: 'u_radius_px',
|
|
29
|
+
direction: 'u_direction',
|
|
30
|
+
},
|
|
31
|
+
vertexSrc,
|
|
32
|
+
fragmentSrc,
|
|
33
|
+
});
|
|
34
|
+
const vao = gl.createVertexArray();
|
|
35
|
+
gl.bindVertexArray(vao);
|
|
36
|
+
// Position
|
|
37
|
+
const positionBuffer = gl.createBuffer();
|
|
38
|
+
gl.enableVertexAttribArray(attribLocations.position);
|
|
39
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
40
|
+
gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
|
|
41
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
42
|
+
// prettier-ignore
|
|
43
|
+
new Float32Array([
|
|
44
|
+
0, 0,
|
|
45
|
+
0, 1,
|
|
46
|
+
1, 0,
|
|
47
|
+
1, 0,
|
|
48
|
+
0, 1,
|
|
49
|
+
1, 1,
|
|
50
|
+
]), gl.STATIC_DRAW);
|
|
51
|
+
// Texture coordinates for the rectangle
|
|
52
|
+
const texCoordBuffer = gl.createBuffer();
|
|
53
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
54
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
55
|
+
// prettier-ignore
|
|
56
|
+
new Float32Array([
|
|
57
|
+
0, 0,
|
|
58
|
+
0, 1,
|
|
59
|
+
1, 0,
|
|
60
|
+
1, 0,
|
|
61
|
+
0, 1,
|
|
62
|
+
1, 1,
|
|
63
|
+
]), gl.STATIC_DRAW);
|
|
64
|
+
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
65
|
+
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
66
|
+
const scaleFactor = processor.width / width;
|
|
67
|
+
const MIN_CCL_WIDTH = 32;
|
|
68
|
+
const MIN_CCL_HEIGHT = 18;
|
|
69
|
+
const convergenceWidth = Math.max(Math.floor(width / 4), MIN_CCL_WIDTH);
|
|
70
|
+
const convergenceHeight = Math.max(Math.floor(height / 4), MIN_CCL_HEIGHT);
|
|
71
|
+
const CONVERGENCE_EPSILON = convergenceWidth === MIN_CCL_WIDTH ? 1e-8 : 1e-4;
|
|
72
|
+
const convergenceSize = convergenceWidth * convergenceHeight;
|
|
73
|
+
const diffRenderer = createDiffAbsRenderer(processor, convergenceWidth, convergenceHeight);
|
|
74
|
+
const supportFloat = floatSingleChannelSupported || floatFullChannelSupported;
|
|
75
|
+
const readPixelsFormat = supportFloat ? gl.RGBA : gl.RED;
|
|
76
|
+
const readPixelsType = supportFloat ? gl.FLOAT : gl.UNSIGNED_BYTE;
|
|
77
|
+
const convergenceDiff = supportFloat
|
|
78
|
+
? new Float32Array(convergenceSize * 4)
|
|
79
|
+
: new Uint8Array(convergenceSize);
|
|
80
|
+
const outputTexturePing = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
|
|
81
|
+
const outputTexturePong = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
|
|
82
|
+
const frameBufferPing = createFrameBuffer(gl, outputTexturePing);
|
|
83
|
+
const frameBufferPong = createFrameBuffer(gl, outputTexturePong);
|
|
84
|
+
return {
|
|
85
|
+
render: ({ mask, maskRef }, options) => {
|
|
86
|
+
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
87
|
+
let write = frameBufferPing;
|
|
88
|
+
let read = mask.texture;
|
|
89
|
+
const dilate = () => {
|
|
90
|
+
gl.useProgram(program);
|
|
91
|
+
gl.bindVertexArray(vao);
|
|
92
|
+
gl.uniform1i(uniformLocations.radiusPx, clampRadiusPx(Math.floor(options.morphDilateRadiusPx / scaleFactor)));
|
|
93
|
+
gl.uniform2f(uniformLocations.texelSize, 1 / mask.width, 1 / mask.height);
|
|
94
|
+
// Reference Mask
|
|
95
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
96
|
+
gl.uniform1i(uniformLocations.maskRef, 1);
|
|
97
|
+
gl.bindTexture(gl.TEXTURE_2D, maskRef.texture);
|
|
98
|
+
// No Flip Y Coordinate for drawing on the frame buffer
|
|
99
|
+
// Project, position and scale to full-size of the canvas
|
|
100
|
+
const matrix = m3.projection(1, 1, 1);
|
|
101
|
+
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
102
|
+
// Separable
|
|
103
|
+
for (let j = 0; j < 2; j++) {
|
|
104
|
+
// Textures
|
|
105
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
106
|
+
gl.uniform1i(uniformLocations.mask, 0);
|
|
107
|
+
gl.bindTexture(gl.TEXTURE_2D, read);
|
|
108
|
+
// Horizontal then Vertical
|
|
109
|
+
gl.uniform2f(uniformLocations.direction, 1.0 - j, 0.0 + j);
|
|
110
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, write);
|
|
111
|
+
gl.viewport(0, 0, width, height);
|
|
112
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
113
|
+
// Swap
|
|
114
|
+
[read, write] =
|
|
115
|
+
write === frameBufferPing
|
|
116
|
+
? [outputTexturePing, frameBufferPong]
|
|
117
|
+
: [outputTexturePong, frameBufferPing];
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
for (let i = 0; i < options.morphPass; i++) {
|
|
121
|
+
dilate();
|
|
122
|
+
}
|
|
123
|
+
let convergent = false;
|
|
124
|
+
let count = 0;
|
|
125
|
+
while (!convergent) {
|
|
126
|
+
dilate();
|
|
127
|
+
const diff = diffRenderer.render({ texture: outputTexturePing, width, height }, { texture: outputTexturePong, width, height });
|
|
128
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, diff.frameBuffer);
|
|
129
|
+
gl.readPixels(0, 0, convergenceWidth, convergenceHeight, readPixelsFormat, readPixelsType, convergenceDiff);
|
|
130
|
+
let sum = 0;
|
|
131
|
+
let meanDiff = 0;
|
|
132
|
+
if (supportFloat) {
|
|
133
|
+
for (let i = 0, j = 0; i < convergenceSize; ++i, j += 4) {
|
|
134
|
+
//@ts-expect-error will not be undefined
|
|
135
|
+
sum += convergenceDiff[j];
|
|
136
|
+
}
|
|
137
|
+
meanDiff = sum / convergenceSize;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
for (let i = 0; i < convergenceSize; ++i) {
|
|
141
|
+
//@ts-expect-error will not be undefined
|
|
142
|
+
sum += convergenceDiff[i];
|
|
143
|
+
}
|
|
144
|
+
meanDiff = sum / convergenceSize / 255.0;
|
|
145
|
+
}
|
|
146
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
147
|
+
if (meanDiff < CONVERGENCE_EPSILON ||
|
|
148
|
+
count >= CONVERGENCE_MAX_ITERATIONS) {
|
|
149
|
+
// console.log(
|
|
150
|
+
// `Geodesic reconstruction converged in ${count} iterations with ${meanDiff}`,
|
|
151
|
+
// {convergenceWidth, convergenceHeight, width, height},
|
|
152
|
+
// );
|
|
153
|
+
convergent = true;
|
|
154
|
+
}
|
|
155
|
+
count++;
|
|
156
|
+
}
|
|
157
|
+
// Cleanup
|
|
158
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
159
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
160
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
161
|
+
gl.bindVertexArray(null);
|
|
162
|
+
return { texture: read, width, height };
|
|
163
|
+
},
|
|
164
|
+
release: () => {
|
|
165
|
+
gl.deleteBuffer(positionBuffer);
|
|
166
|
+
gl.deleteBuffer(texCoordBuffer);
|
|
167
|
+
gl.deleteTexture(outputTexturePing);
|
|
168
|
+
gl.deleteTexture(outputTexturePong);
|
|
169
|
+
gl.deleteFramebuffer(frameBufferPing);
|
|
170
|
+
gl.deleteFramebuffer(frameBufferPong);
|
|
171
|
+
gl.deleteVertexArray(vao);
|
|
172
|
+
diffRenderer.release();
|
|
173
|
+
release();
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RendererOptions } from '../../types/render';
|
|
2
|
+
import type { TextureInfo } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Joint Bilateral Filter
|
|
5
|
+
*/
|
|
6
|
+
export declare const createJointBilateralFilterRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
|
|
7
|
+
render: ({ input, guide }: {
|
|
8
|
+
input: TextureInfo;
|
|
9
|
+
guide: TextureInfo;
|
|
10
|
+
}, options: RendererOptions) => TextureInfo;
|
|
11
|
+
release: () => void;
|
|
12
|
+
};
|