为什么我使用网络摄像头和 Tensorflow.js 时会出现奇怪的三重视频?

Why am I getting strange triplication of video using Webcam and Tensorflow.js?

我已经训练了一个 keras 模型,现在我想 运行 在网络上使用它。我认为这可能是尝试测试 Tensorflow.js 的好方法。我下载了 Tesnroflow.js "Webcam-transfer-learning" 教程,然后对其进行了修改以获取我当前拥有的内容。 working keras 模型在将图像尺寸缩小到 48x48 后进行情感分类。现在在 keras 模型中,我拍摄网络摄像头的快照,复制它,然后绘制我的框和标签。我试图在 tf.js 中做同样的事情,所以我设置了一个 canvas,获得了对它的引用,并在我转换为灰度后尝试绘制到 canvas。

我看到一个奇怪的行为,它正确显示了灰度图像,但显示了 3 次,我不确定我做错了什么。我已将我认为问题可能存在的区域包括在下面。如果需要更多信息,我可以分享更多。我希望已经尝试过执行类似操作的人可以立即看出我明显做错了什么。任何信息都会有帮助。谢谢!

通过添加函数

修改了 webcam.js
preProc() {
return tf.tidy(() => {
  // Reads the image as a Tensor from the webcam <video> element.
  const webcamImage = tf.fromPixels(this.webcamElement);

  //Resize to our image and get back single channel for greyscale
  const croppedImage = this.cropImage(webcamImage, 1);

  // Expand the outer most dimension so we have a batch size of 1.
  const batchedImage = croppedImage.expandDims(0);

  // Normalize the image between -1 and 1. The image comes in between 0-255,
  // so we divide by 127 and subtract 1.
  return batchedImage.toFloat().div(tf.scalar(127)).sub(tf.scalar(1));
});
}

/**
* Crops an image tensor so we get a square image with no white space.
* @param {Tensor4D} img An input image Tensor to crop.
*/
cropImage(img, dim=3) {
  const size = Math.min(img.shape[0], img.shape[1]);
  const centerHeight = img.shape[0] / 2;
  const beginHeight = centerHeight - (size / 2);
  const centerWidth = img.shape[1] / 2;
  const beginWidth = centerWidth - (size / 2);
  return img.slice([beginHeight, beginWidth, 0], [size, size, dim]);
}

来自 ui.js 我正在使用 drawFrame

export function drawFrame(image, canvas) {
  const [width, height] = [300, 165];
  const ctx = canvas.getContext('2d');
  const imageData = new ImageData(width, height);
  const data = image.dataSync();
  for (let i = 0; i < height * width; ++i) {
    const j = i * 4;
    imageData.data[j + 0] = (data[i * 3 + 0] + 1) * 127;
    imageData.data[j + 1] = (data[i * 3 + 1] + 1) * 127;
    imageData.data[j + 2] = (data[i * 3 + 2] + 1) * 127;
    imageData.data[j + 3] = 255;
  }
  ctx.putImageData(imageData, 0, 0);
}

最后在 index.js 中,当按下预测按钮时,下面的处理程序将执行

async function predict() {
while (isPredicting) {
  const predictedClass = tf.tidy(() => {
    // Capture the frame from the webcam.
    const imgmod = webcam.preProc();
    ui.drawFrame(imgmod, grayframe);


    // Returns the index with the maximum probability. This number corresponds
    // to the class the model thinks is the most probable given the input.
    //return predictions.as1D().argMax();
    return imgmod;
  });

  const classId = (await predictedClass.data())[0];
  predictedClass.dispose();

  //ui.predictClass(classId);
  await tf.nextFrame();
  }
  ui.donePredicting();
}

drawframe 正在绘制图像 3 次。 它与输入图像的形状以及 heightwidth 用于裁剪图像的方式有关。如果输入图像的形状为 [298, 160],则 canvas 将不会被渲染,因为在尝试访问不在 data 中的索引时会出现错误。例如 data 的大小是 298 * 160 而循环的最后一个元素将尝试访问元素 3 * 300 * 160。由于代码没有错误,这表明 data 的大小大于 [298, 160]。无论如何,数据维度不匹配。图像因为三个通道被绘制了3次,可能是因为之前没有去掉。

您可以考虑使用 tf.toPixel 方法

,而不是自己实现绘制图像数据的方式