gpt4 book ai didi

node.js - 是否可以使用 puppeteer 将 Javascript 对象传递给 nodejs?

转载 作者:搜寻专家 更新时间:2023-10-31 22:33:14 28 4
gpt4 key购买 nike

背景

我正在使用 Posenet (请参阅浏览器演示 here )进行关键点检测。我已将其设置为在 WebRTC MediaStream 上运行,例如:

客户:在机器上的 chrome 选项卡中运行 A .初始化 WebRTC 连接并将 MediaStream 发送到 服务器 .接收来自 的实时关键点数据服务器 通过 WebRTC 的 DataChannel。

服务器:在机器上的 chrome 选项卡中运行 B , 接收一个 WebRTC 流并将相应的 MediaStream 传递给 Posenet。 Posenet 做它的事情并计算关键点。然后将此关键点数据发送回 客户通过 WebRTC 的 DataChannel(如果您有更好的主意,我会全力以赴)。

问题:我想让服务器从各个客户端接收多个流并在每个流上运行 Posenet,将实时关键点数据发送到所有客户端。虽然我对使用 Chrome 的服务器并不感到兴奋,但我很乐意使用 puppeteer和 Chrome 目前的 headless 模式,主要是为了抽象出 WebRTC 的复杂性。

方法

我尝试了两种方法,非常赞成方法 #2 :

方法#1

运行 @tensorflow/tfjspuppeteer上下文(即在 headless Chrome 标签内)。但是,我似乎无法获得 PoseNet Browser Demo由于一些 WebGL 错误,在 headless 模式下工作(尽管它确实在非 headless 模式下工作)。我尝试了以下操作(将 args 传递给 puppeteer.launch() 以启用 WebGL,但我没有运气 - 请参阅 herehere 以供引用):

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();


在 headless 模式下,我收到此错误消息。

0: JSHandle:Initialization of backend webgl failed
0: JSHandle:Error: WebGL is not supported on this device

这给我留下了 question #1 : 如何在 puppeteer 中启用 WebGL ?

方法#2

最好,我想运行 posenet使用 @tensorflow/tfjs-node后端,加速计算。因此,我想链接 puppeteer@tensorflow/tfjs-node , 英石。:
  • puppeteer-chrome-tab 讨论 WebRTC客户 .它使 Mediastream 对象可用于 node .
  • node获取此 MediaStream 并将其传递给 posenet , (因此 @tensorflow/tfjs-node ),机器学习魔法发生的地方。 node然后将检测到的关键点传回 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)

    记录 pixels传递给 NodeJSKernelBackend.prototype.fromPixels = function (pixels, numChannels) {..} 的参数,它的计算结果为 ElementHandle .我知道我可以使用 puppeteer 访问 Javascript 对象的可序列化属性。的 page.evaluate .但是,如果我要通过 CanvasRenderingContext2DimageData (使用方法 getImageData()node 通过调用 puppeteer.evaluate(..) ,这意味着将整个原始图像字符串化,然后在 node 的上下文中重建它。

    这给我留下了 question #2 : 有什么办法可以从 puppeteer 做一个对象吗?的上下文可直接在 node 内访问(只读) ,而无需通过例如 puppeteer.evaluate(..) ?

    最佳答案

    我推荐的另一种方法是放弃在服务器端使用 puppeteer 的想法,而是在 Node.js 中实现一个实际的 WebRTC 客户端,然后通过 @tensorflow/tfjs-node 直接使用 PoseNet。 .

    为什么不在服务器端使用 puppeteer

    在服务器端使用 puppeteer 会带来很多复杂性。除了与多个客户端的事件 WebRTC 连接之外,您现在还必须为每个连接管理一个浏览器(或至少一个选项卡)。因此,您不仅要考虑与客户端的连接失败时会发生什么,而且还必须为其他情况做好准备,例如浏览器崩溃、页面崩溃、WebGL 支持(每页)、浏览器中的文档未加载,浏览器实例的内存/CPU 使用率,...

    也就是说,让我们回顾一下你的方法。

    方法 1:在 puppeteer 中运行 Tensorflow.js

    您应该能够仅使用 cpu 来运行它。 backend .在使用任何其他代码之前,您可以像这样设置后端:

    tf.setBackend('cpu');

    您也许还可以让 WebGL 运行(就像您 not the only one 遇到 WebGL 和 puppeteer 问题一样)。但即使你让它运行,你现在正在运行一个 Node.js 脚本来启动一个 Chrome 浏览器,该浏览器启动 WebRTC session 和 Tensorflow.js 训练在网站内。在复杂性方面,如果出现任何问题,这将很难调试......

    方法二:在 puppeteer 和 Node.js 之间传输数据

    如果没有大幅减速(关于帧的发送和接收),这种方法几乎是不可能的。 puppeteer 需要序列化任何交换的数据。 Node.js 和浏览器环境之间没有共享内存或共享数据对象之类的东西。这意味着您必须序列化每个帧(所有像素...)才能将它们从浏览器环境传输到 Node.js。在性能方面,这对于小图像可能没问题,但图像越大,情况会变得越糟。

    总而言之,如果您想采用两种方法中的一种,则会引入很多复杂性。因此,让我们看看替代方案。

    替代方法:将您的视频流直接发送到您的服务器

    您可以直接实现 WebRTC peer,而不是使用 puppeteer 建立 WebRTC 连接。我从你的问题中读到你害怕复杂性,但这可能值得麻烦。

    要实现 WebRTC 服务器,您可以使用库 node-webrtc ,它允许在服务器端实现 WebRTC 对等点。有多个示例,其中一个对您的用例非常有趣。这是 video-compositing 例如,它在客户端(浏览器)和服务器(Node.js)之间建立连接以流式传输视频。然后服务器将修改发送的帧并在它们上面放置一个“水印”。

    代码示例

    以下代码显示了 video-compositing 中最相关的行例子。该代码从输入流中读取一个帧并创建一个 node-canvas 从它的对象。

    const lastFrameCanvas = createCanvas(lastFrame.width,  lastFrame.height);
    const lastFrameContext = lastFrameCanvas.getContext('2d', { pixelFormat: 'RGBA24' });

    const rgba = new Uint8ClampedArray(lastFrame.width * lastFrame.height * 4);
    const rgbaFrame = createImageData(rgba, lastFrame.width, lastFrame.height);
    i420ToRgba(lastFrame, rgbaFrame);

    lastFrameContext.putImageData(rgbaFrame, 0, 0);
    context.drawImage(lastFrameCanvas, 0, 0);

    你现在有一个 Canvas 对象,你可以像这样使用 PoseNet 的提要:

    const net = await posenet.load();

    // ...
    const input = tf.browser.fromPixels(lastFrameCanvas);
    const pose = await net.estimateSinglePose(input, /* ... */);

    现在需要将结果数据传输回客户端,这可以通过使用数据 channel 来完成。存储库中还有一个示例( ping-pong ),它比视频示例简单得多。

    尽管您可能会担心使用 node-webrtc 的复杂性,我建议给出这种方法和 node-webrtc-examples 一试。您可以先 check out 存储库。所有示例都已准备好尝试使用。

    关于node.js - 是否可以使用 puppeteer 将 Javascript 对象传递给 nodejs?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57733537/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com