Domanda

I'm trying to play with a webcam delay per channel in JavaScript and my current code runs a bit slow. You can see a demo here

My approach to the delay is creating an array of 12 elements to store pixels(Canvas elements) then shift content from one frame to another by copying pixels (using getImageData and putImageData calls). Since I'm splitting colour channels, my update function looks like this:

function update() {
    if (localMediaStream) {
        // Update history
        for (var i = hs - 1; i > 0; i--) {
            var ctxCurr = history[i].getContext('2d');
            var ctxPrev = history[i - 1].getContext('2d');
            try {
                ctxCurr.putImageData(ctxPrev.getImageData(0, 0, w, h), 0, 0);
            } catch (err) {
                console.log(err);
            }
        }
        // Write the most recent webcam frame
        var ctx0 = history[0].getContext('2d');
        ctx0.drawImage(video, 0, 0, w, h);
        // Get pixel data for most recent,halfway and last frames in history
        var r = history[0].getContext('2d').getImageData(0, 0, w, h).data;
        var g = history[hs / 2].getContext('2d').getImageData(0, 0, w, h).data;
        var b = history[hs - 1].getContext('2d').getImageData(0, 0, w, h).data;
        // Get a frame and it's pixels
        var imageData = ctx0.getImageData(0, 0, w, h);
        var data = imageData.data;
        // Write the r,g,b channels using the offset frames for green and blue channels
        for (var i = 0; i < data.length; i += 4) {
            data[i] = r[i];
            data[i + 1] = g[i + 1];
            data[i + 2] = b[i + 2];
        }

        rgb.putImageData(imageData, 0, 0);
    }
}

I guess I could skip using the red channel since the most recent frame already has that information. Is there a faster way to manipulate/write pixel data (other than getImageData() and putImageData()) or faster approaches to what I'm trying to achieve?

È stato utile?

Soluzione

It looks like there are a couple of ways to speed up what you're trying to do. getImageData is pretty slow, and putImageData is frustratingly slow so eliminating those calls will always serve you well. You're right to forget about the red channel. I'd also get rid of this line:

var r = history[0].getContext('2d').getImageData(0, 0, w, h).data;

Also, you should be able to draw the canvas to the appropriate context, so long as you clear the context. I believe your try statement should look like:

try {
    ctxCurr.clearRect(0, 0, w, h);
    ctxCurr.drawImage(history[i-1], 0, 0);
}

Removing all of those redundant calls to putImageData should help a lot.

Altri suggerimenti

To hand-code it, I think put and getImageData are the only ways to do it through a canvas. There's a javascript library out there you could use. Perhaps you could manipulate the source. I tried the demo and it seems considerably more fluid than yours (although I like the trippy color effects on yours). You can find the library here.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top