使用Alpha-Channeled视频来屏蔽HTML内容

时间:2015-03-27 18:25:06

标签: html html5 css3 canvas html5-video

我正在努力实现目前可能在效果之后的效果,效果是关于剪辑屏幕(luma matte)一个视频与另一个视频,所以最终的输出将是一个透明的视频。但我正在尝试制作动态透明的HTML内容。

视频看起来像这样:https://www.youtube.com/watch?v=jfzcrO4694E

基本上通过改变透明度来揭示HTML内容。

这必须是关于+的东西,但是在谷歌搜索大约一个小时后,找不到任何可以改变HTML内容透明度的黑白影片的描述和效果。

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

HTML5不支持alpha通道视频(例如MOV 32位等)。

唯一的选择是使用matte合成,就像你的视频结合了canvas元素一样。但是,canvas仅复合已存在的Alpha通道,并且作为matte是固体图层而不是alpha,您必须将其转换为alpha。

这意味着您必须绘制每个帧并将其迭代到画布,并将灰度转换为透明度级别。但是,这非常占用CPU,会影响计算机性能/资源。视频还必须满足CORS要求,以免污染画布(在这种情况下,您无法提取像素)。

以下是

对于每一帧:

  • 从每个像素的任意通道获取一个级别,我们将在这里使用红色
  • 从255中减去该值,因为此处的哑光白色将是目标(反转,将显示)
  • 清除图像数据,这是遮罩本身,否则您将获得白色遮罩泄漏到数据中
  • 将计算值设置为新的Alpha通道值

示例循环(假设视频是动态创建的,设置了源代码并触发了启动事件 - 画布放置在您要屏蔽的位置,并初始化上下文ctx ):

ctx.globalCompositeOperation = "copy";       // will clear previous alpha

function unmask() {
    ctx.drawImage(video, 0, 0);              // draw current video frame

    var idata = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height),
        data = idata.data,
        len = data.length, i = 0;            // ..image data from canvas

    while(i < len) {
        var alpha = 255 - data[i];           // in this matte, white = fully transparent
        data[i] = data[i+1] = data[i+2] = 0; // clear matte to black
        data[i+3] = alpha;                   // set alpha
        i += 4;                              // next pixel
    }

    ctx.putImageData(idata, 0, 0);           // update canvas
    requestAnimationFrame(unmask);           // todo: add criteria to stop this
}

加速提示:使用黑色(或预先反转遮罩视频),然后对数据使用Uint32Array视图,右移一个像素长字(&lt;&lt; 24)到位。


您可以使用新的CSS custom filters(也就是CSS着色器)执行此操作,但在撰写本文时,这并未得到广泛支持。它还需要使用着色器语言(GLSL)。但我发现它至少值得一提。

答案 1 :(得分:1)

示例视频的白色区域越来越多地被后退的黑色区域显示出来。

您可以使用现有的视频+画布来展示基础HTML内容。

制作包含您已制作视频的视频元素。

使用计时器抓取播放视频的帧。强烈建议使用requestAnimationFrame,因为它会与您的显示刷新同步。

在每个动画循环中,在画布上绘制视频帧。您可以在画布上绘制视频,因为画布可以使用视频元素作为其图像源。

一旦你的黑雾框架在画布上,你可以通过以下方式使画布的任何白色区域透明:

  • 使用context.getImageData获取画布上每个像素的颜色数据

  • 如果任何像素的颜色为“white-ish”,您可以将该像素的alpha值更改为0(表示透明)。

  • 使用context.putImageData

  • 将修改过的像素数据放回到画布上

总的来说:

  • 隐藏播放的视频元素

  • 使用CSS将canvas元素放在您想要显示的html内容上。

  • 创建一个动画循环,在画布上绘制视频帧并将白色像素转换为透明。

  • html内容将通过播放视频的画布显示,白色像素被完全透明化。

答案 2 :(得分:0)

到目前为止,其他答案假定为2D画布上下文。您可以使用WebGL更有效地完成此任务。这样,所有实际工作都在GPU中完成。

你需要一个片段着色器,它基本上完成了Ken Fyrstenberg的答案中的循环:找到每个像素的亮度,从最大值中减去它(一个,在GLSL中,而不是255),并使用作为阿尔法值。我将在(a)中仅使用绿色通道作为亮度,并且(b)将输出颜色通道设置为黑色。以下是我的表现:

precision lowp float;
uniform sampler2D sampler0;
varying vec2 v_texCoord;
void main(void) {
  vec4 color = texture2D(sampler0, v_texCoord);
  float alpha = 1.0 - color.g;
  gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);
}

对于每个帧,然后,将一个矩形渲染到WebGL画布,将视频作为纹理源,以及上面的片段着色器。 我已经开始编写一个如何执行此操作的示例,但它会采取一些工作。有多大兴趣?请告诉我,如果有足够的需求,我会尽力完成。

编辑:你可以避免使用glfx.js来学习太多关于WebGL的知识。我没有深入研究它,但我认为它可以用视频作为图像源。