【问题标题】:Calling context.getImgData() causes canvas to "flicker"调用 context.getImgData() 会导致画布“闪烁”
【发布时间】:2017-06-22 22:20:12
【问题描述】:

我将网络摄像头馈送流式传输到 video 元素,然后将其绘制到 canvas 元素上。然后我在画布上运行人脸检测算法,在脸上画一个正方形。

问题是,要做到这一点,我需要调用context.getImgData() 方法。当调用该方法时,这会导致画布“闪烁”。它会在一瞬间完全变黑,然后恢复正常。看起来很可怕。我关注了一些其他人使用网络摄像头在画布上绘制的例子,他们也使用这种方法,所以我真的不知道有什么方法可以绕过它。

我在下面有一些在 JSfiddle 中工作的示例代码。我在使用 Firefox 的 Mac OS 上。有两个按钮。第一个将来自video 元素的流绘制到canvas,第二个简单地运行getImgData()。你可以清楚地看到我描述的问题。有什么想法吗?

<body>
    <div>
        <button onclick="paintCanvas()">paint</button>
        <button onclick="testFunc()">test</button>
    </div>
    <div>
        <canvas id="canvas" width="500" height="375"></canvas>
        <video autoplay loop="false" src="media/vid.mp4" type="video/mp4" id="videoElement">
    </div>
</body>
<script>
    var video = document.querySelector("#videoElement");
    var myCanvas = document.getElementById('canvas');
    var myContext = myCanvas.getContext('2d');

    navigator.mediaDevices.getUserMedia({ video: true })
        .then((stream) => {
            video.srcObject = stream;
            // vid2.srcObject = stream;
            // document.getElementById('controls').innerHTML = "Switch back to video for player controls";
            // document.getElementById('timing').innerHTML = '';
        })
        .catch(function (err) {
            media = 'video';
            console.log(err.name);
        });
    let ch, cw;
    function paintCanvas(e) {
        console.log('painting canvas')
        const v = document.getElementById('videoElement');
        const canvas = document.getElementById('canvas');
        const context = canvas.getContext('2d');
        cw = Math.floor(canvas.clientWidth);
        ch = Math.floor(canvas.clientHeight);
        canvas.width = cw;
        canvas.height = ch;

        draw(v, context, cw, ch);
    }
    function draw(v, c, w, h) {
        // console.log('drawing')
        videoRunning = true;
        if (v.paused || v.ended) return false;
        c.drawImage(v, 0, 0, w, h);
        myVar = setTimeout(draw, 60, v, c, w, h);
    }
    function testFunc() {       
        // setInterval(function () {
            console.log(video.videoWidth, video.videoHeight)
            x = myContext.getImageData(0, 0, video.videoWidth, video.videoHeight);
            console.log(x);
        // }, 200);
    }
</script>

【问题讨论】:

  • 我无法复制。您使用哪些浏览器和操作系统进行了测试?
  • 抱歉应该澄清一下 - mac os 和 firefox

标签: javascript html canvas html5-canvas


【解决方案1】:

好的,如果你想使用getImageData() 方法,它必须在与draw 相同的函数中调用。

function draw(v, c, w, h) {
    // console.log('drawing')
    videoRunning = true;
    if (v.paused || v.ended) return false;
    c.drawImage(v, 0, 0, w, h);
    myVar = setTimeout(draw, 60, v, c, w, h);
    x = myContext.getImageData(0, 0, video.videoWidth, video.videoHeight)

}

【讨论】:

  • 不,没有理由在同一个函数中调用它。您的问题与您的糟糕循环有关,请改用 rAF 。此外,您可能会通过保留较小的屏幕外画布来获胜,您可以在其上绘制视频帧的缩小版本以在较小的表面上进行检测。
猜你喜欢
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多