* @license * Copyright 2022 Google LLC. All Rights Reserved. * 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 * * Unles
()
| 16 | */ |
| 17 | |
| 18 | async function init() { |
| 19 | const customBackendName = 'custom-webgl'; |
| 20 | |
| 21 | const kernels = tf.getKernelsForBackend('webgl'); |
| 22 | kernels.forEach(kernelConfig => { |
| 23 | const newKernelConfig = { ...kernelConfig, backendName: customBackendName }; |
| 24 | tf.registerKernel(newKernelConfig); |
| 25 | }); |
| 26 | const gl = getWebGLRenderingContext(canvasEl); |
| 27 | tf.registerBackend(customBackendName, () => { |
| 28 | return new tf.MathBackendWebGL( |
| 29 | new tf.GPGPUContext(gl)); |
| 30 | }); |
| 31 | await tf.setBackend(customBackendName); |
| 32 | |
| 33 | const applyMask = new MaskStep(gl); |
| 34 | let inputTextureFrameBuffer = createTextureFrameBuffer(gl, gl.LINEAR, videoWidth, videoHeight); |
| 35 | |
| 36 | const predict = async () => { |
| 37 | beginEstimateSegmentationStats(); |
| 38 | |
| 39 | // Put original video content on the input texture. |
| 40 | inputTextureFrameBuffer.bindTexture(); |
| 41 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB8, gl.RGB, gl.UNSIGNED_BYTE, video); |
| 42 | |
| 43 | // Run segmentation model inference. |
| 44 | const segmentationConfig = {flipHorizontal: false, multiSegmentation: false, segmentBodyParts: true, |
| 45 | segmentationThreshold: 0.5}; |
| 46 | segmentation = await model.segmentPeople(video, segmentationConfig); |
| 47 | |
| 48 | // Get the tensor result and the texture that holds the data. |
| 49 | // We tell the system to use the video width and height as the tex shape, |
| 50 | // this allows the densely packed data to have the same layout as the |
| 51 | // original video content, which simplifies the shader logic. This only |
| 52 | // works if the data shape is [1, height, width, 4]. |
| 53 | const tensor = await segmentation[0].mask.toTensor(); |
| 54 | const data = |
| 55 | tensor.dataToGPU({customTexShape: [videoHeight, videoWidth]}); |
| 56 | |
| 57 | // Combine the input texture and tensor texture with additional shader logic. |
| 58 | // In this case, we just pass through foreground pixels and make background |
| 59 | // pixels more transparent. |
| 60 | const result = applyMask.process(inputTextureFrameBuffer, createTexture( |
| 61 | gl, data.texture, videoWidth, videoHeight)); |
| 62 | |
| 63 | // Other processing steps can go here. |
| 64 | |
| 65 | // Once we're done with all the processing, we can draw the texture on the canvas. |
| 66 | |
| 67 | // Making gl.DRAW_FRAMEBUFFER to be null sets rendering back to default framebuffer. |
| 68 | gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| 69 | // Caching the data of the result texture to be drawn in the gl.READ_FRAMEBUFFER. |
| 70 | gl.bindFramebuffer(gl.READ_FRAMEBUFFER, result.framebuffer_); |
| 71 | // Transfer the data from read framebuffer to the default framebuffer to make it show |
| 72 | // on canvas. |
| 73 | gl.blitFramebuffer( |
| 74 | 0, 0, videoWidth, videoHeight, 0, videoHeight, videoWidth, 0, gl.COLOR_BUFFER_BIT, |
| 75 | gl.LINEAR); |
no test coverage detected