drawImage in canvas from a video frame change the hue
Asked Answered
I

1

11

I wrote a simple script that take a frame from a video and draw it to a canvas. My problem is that the colors are changing between the video and the drawn image.

I put here the result next to the original to make it easier to see. The original one is on the left. It's seems to be way more visible on chrome browser btw. All the test I made where on OSX.

Here a snippet, canvas on left, video on right:

 // Get our mask image
var canvas = document.querySelector(".canvas");
var video = document.querySelector(".video");

var ctx = canvas.getContext('2d');
function drawMaskedVideo() {
  ctx.drawImage(video, 0, 0, video.videoWidth/2, video.videoHeight, 0,0, video.videoWidth/2,  video.videoHeight);
}

requestAnimationFrame(function loop() {
  drawMaskedVideo();
  requestAnimationFrame(loop.bind(this));
});
html, body {
  margin: 0 auto;
}
.video, .canvas {
  width: 100%;
}

.canvas {
  position: absolute;
  top: 0;
  left: 0;
}
<video class="video" autoplay="autoplay" muted="muted" preload="auto" loop="loop">
    <source src="http://mazwai.com/system/posts/videos/000/000/214/original/finn-karstens_winter-wonderland-kiel.mp4" type="video/mp4">
</video>
<canvas class='canvas' width='1280' height='720'></canvas>

I'd like to know why this thing happen, and if it possible to get rid of it in a cross browser way ?

enter image description here

Here the simple script I wrote:

let video = document.querySelector('#my-video') // .mp4 file used
let w = video.videoWidth;
let h = video.videoHeight;
let canvas = document.createElement('canvas');
    canvas.width  = w;
    canvas.height = h;
let ctx = canvas.getContext('2d');

ctx.drawImage(video, 0, 0, w, h)

document.querySelector('.canvas-container').appendChild(canvas);
Insincere answered 25/8, 2017 at 14:48 Comment(9)
What OS are you on, and do you have separate settings (color correction) for the video layer (in hardware/system)? To find workarounds could explain the purpose (you can f.ex. draw the entire video frame into a canvas and process just a part of it).Saprophagous
@K3N I'm on OSX, I have never set a specific color correction. The purpose was to make a frame of video blurry. I can't use CSS3 solution because of IE compatibility. I could play my video trough a canvas than video but it seems a bit heavy for CPU and the color in canvas change the original colors.Insincere
Have you checked if this is a problem with the alpha handling of the canvas? let ctx = canvas.getContext('2d', {alpha: true}); vs let ctx = canvas.getContext('2d', {alpha: false});Merrymaking
@Merrymaking Yes, got the same result with both valueInsincere
I don't have access to a Mac to confirm, but I suspect that on Mac the video hardware layer has rec.709 (or rec.2020) applied, while the canvas, via the browser, has sRGB and standard gamma - if so it's limited what you can do about it. In IE performance will be a problem regardless as blurring (box, gaussian etc.) will require a lot of resources and with a HD sized video frame (you could skip every other frame via rAF so only 1/30 frames per second are updated, or even 1/15, and for blurring you could exploit sub-pixeling/resampling via drawImage).Saprophagous
This might not be applicable, but are you sure the software you are using to view the image in the left side of the sample isn't correcting/altering it at all?Transference
@Transference That's probably part of the answer as K3N highlight, I can just say that they both were rendering through Chrome (osx) (one with video tag and the other with canvas), the same mechanism appears on safari (osx) but seems to be well handled in firefox (osx).Insincere
It sounds more like that the video has a different color across browsers instead of the canvas having different colors across browsers. See if these 2 threads help: #28027476 #35215462Psaltery
See this: #27768414Snowcap
F
-1

The solution might be as simple as setting a css filter to the video element:

.video {
    -webkit-filter: contrast(100%);
}

I can't reason about this since it was discovered accident (playing with your demo and reading related answers), so I leave the technical explanation for someone else and leave you with some magic for now.

Any sufficiently advanced technology is indistinguishable from magic.

— Arthur C. Clarke

 // Get our mask image
var canvas = document.querySelector(".canvas");
var video = document.querySelector(".video");

var ctx = canvas.getContext('2d');
function drawMaskedVideo() {
  ctx.drawImage(video, 0, 0, video.videoWidth/2, video.videoHeight, 0,0, video.videoWidth/2,  video.videoHeight);
}

requestAnimationFrame(function loop() {
  drawMaskedVideo();
  requestAnimationFrame(loop.bind(this));
});
html, body {
  margin: 0 auto;
}
.video, .canvas {
  width: 100%;
}
.video {
  -webkit-filter: contrast(100%);
}

.canvas {
  position: absolute;
  top: 0;
  left: 0;
}
<video class="video" autoplay="autoplay" muted="muted" preload="auto" loop="loop">
    <source src="http://mazwai.com/system/posts/videos/000/000/214/original/finn-karstens_winter-wonderland-kiel.mp4" type="video/mp4">
</video>
<canvas class='canvas' width='1280' height='720'></canvas>

Note: Running this on a Macbook Pro (2,3 GHz Intel Core i5) I could see no difference performance wise. Tracked CPU during the video playback and both demos idle at around 28%.

Fieldstone answered 12/12, 2017 at 14:4 Comment(3)
Filed this as a chrome bug issues.chromium.org/issues/343093083Antoniaantonie
@Antoniaantonie thank you for that. Haven't notice that my answer is not working any more. Looks like the magic trick is over =PFieldstone
Looking further, the issue is about the original video file that is no longer available.Fieldstone

© 2022 - 2024 — McMap. All rights reserved.