【发布时间】:2020-01-04 02:37:27
【问题描述】:
背景
我正在使用Posenet(请参阅浏览器中的演示here)进行关键点检测。我已将其设置为在 WebRTC MediaStream 上运行,s.t.:
客户端:在机器 A 上的 chrome 选项卡中运行。初始化 WebRTC 连接并将 MediaStream 发送到 Server。通过 WebRTC 的 DataChannel 从 Server 接收实时关键点数据。
服务器:在机器 B 的 chrome 选项卡中运行,接收 WebRTC 流并将相应的 MediaStream 传递给 Posenet。 Posenet 做它的事情并计算关键点。然后,此关键点数据通过 WebRTC 的 DataChannel 发送回客户端(如果您有更好的想法,我会全力以赴)。
问题:我想让服务器接收来自不同客户端的多个流并在每个流上运行 Posenet,向所有客户端发送实时关键点数据。虽然我对使用 Chrome 的服务器并不感到兴奋,但我现在可以使用 puppeteer 和 Chrome 的无头模式,主要是为了抽象出 WebRTC 的复杂性。
方法
我尝试了两种方法,非常赞成方法#2:
方法#1
在puppeteer 上下文中运行@tensorflow/tfjs(即在无头镀铬标签中)。但是,由于一些 WebGL 错误,我似乎无法让 PoseNet Browser Demo 在无头模式下工作(尽管它确实在非无头模式下工作)。我尝试了以下方法(将 args 传递给 puppeteer.launch() 以启用 WebGL,虽然我没有运气 - 请参阅 here 和 here 以供参考):
const puppeteer = require('puppeteer');
async function main() {
const browser = await puppeteer.launch({
headless: true,
args: ['--enable-webgl-draft-extensions', '--enable-webgl-image-chromium', '--enable-webgl-swap-chain', '--enable-webgl2-compute-context']
});
const page = await browser.newPage();
await page.goto('https://storage.googleapis.com/tfjs-models/demos/posenet/camera.html', {
waitUntil: 'networkidle2'
});
// Make chromium console calls available to nodejs console
page.on('console', msg => {
for (let i = 0; i < msg.args().length; ++i)
console.log(`${i}: ${msg.args()[i]}`);
});
}
main();
在无头模式下,我收到此错误消息。
0: JSHandle:Initialization of backend webgl failed
0: JSHandle:Error: WebGL is not supported on this device
这给我留下了question #1:如何在puppeteer 中启用WebGL?
方法#2
我最好使用@tensorflow/tfjs-node 后端运行posenet,以加速计算。因此,我想链接puppeteer和@tensorflow/tfjs-node,s.t.:
-
puppeteer-chrome-tab与 客户端 对话 WebRTC。它使node可以使用 Mediastream 对象。 -
node获取此 MediaStream 并将其传递给posenet(因此是@tensorflow/tfjs-node),机器学习的魔力在此发生。node然后将检测到的关键点传回给puppeteer-chrome-tab,puppeteer-chrome-tab使用它的RTCDataChannel将它们传回给客户端。
问题
问题是我似乎无法访问puppeteer 的MediaStream 对象在 node,将此对象传递给posenet。我只能访问JSHandles 和ElementHandles。是否可以将与句柄关联的 javascript 对象 传递给node?
具体来说,抛出这个错误:
UnhandledPromiseRejectionWarning: Error: When running in node, pixels must be an HTMLCanvasElement like the one returned by the `canvas` npm package
at NodeJSKernelBackend.fromPixels (/home/work/code/node_modules/@tensorflow/tfjs-node/dist/nodejs_kernel_backend.js:1464:19)
at Engine.fromPixels (/home/work/code/node_modules/@tensorflow/tfjs-core/dist/engine.js:749:29)
at fromPixels_ (/home/work/code/node_modules/@tensorflow/tfjs-core/dist/ops/browser.js:85:28)
at Object.fromPixels (/home/work/code/node_modules/@tensorflow/tfjs-core/dist/ops/operation.js:46:29)
at toInputTensor (/home/work/code/node_modules/@tensorflow-models/posenet/dist/util.js:164:60)
at /home/work/code/node_modules/@tensorflow-models/posenet/dist/util.js:198:27
at /home/work/code/node_modules/@tensorflow/tfjs-core/dist/engine.js:349:22
at Engine.scopedRun (/home/work/code/node_modules/@tensorflow/tfjs-core/dist/engine.js:359:23)
at Engine.tidy (/home/work/code/node_modules/@tensorflow/tfjs-core/dist/engine.js:348:21)
at Object.tidy (/home/work/code/node_modules/@tensorflow/tfjs-core/dist/globals.js:164:28)
记录传递给NodeJSKernelBackend.prototype.fromPixels = function (pixels, numChannels) {..} 的pixels 参数,它的计算结果为ElementHandle。我知道我可以使用puppeteer 的page.evaluate 访问Javascript 对象的serializable 属性。但是,如果我要传递CanvasRenderingContext2D 的imageData(使用方法getImageData() 到node,通过调用puppeteer.evaluate(..),这意味着将整个原始图像字符串化,然后在node 中重建它上下文。
这给我留下了question #2:有没有办法让puppeteer 的上下文中的对象可以直接在node 内部访问(只读),而无需通过例如puppeteer.evaluate(..)?
【问题讨论】:
-
由于执行环境的差异,您在节点和浏览器上下文之间传递的任何内容都将被序列化。自创建 puppeteer 以来,我没有找到这样的方法。
-
感谢您的洞察力。如果我要在 puppeteer 上下文中运行 tensorflowjs,您是否知道如何解决 WebGL 错误?
标签: node.js google-chrome puppeteer tensorflow.js