您当前的位置:首页 > 电脑百科 > 软件技术 > 音/视频编辑

如何使用 WebGL 进行实时视频处理

时间:2020-09-02 12:09:09  来源:  作者:

这是我最近在 CodePen 上制作的 WebGL 演示案例。它可以捕获网络摄像头的数据(或在无法访问网络摄像头时,从 placekitten 获取备用图像),并将其实时转换为 ASCII 图像艺术。

如何使用 WebGL 进行实时视频处理

 

为了获得更多的复古性,我使用了 90 年代 DOS PC 中常见的 8x8 像素光栅字体(您可能会在某些 BIOS 中看到这种字体)。

要将图像内容映射到特定字符,我通过使用亮度图选择最佳匹配。我计算每个 4x4 正方形的像素。在画板内向下滚动以查看亮度图:

如何使用 WebGL 进行实时视频处理

 

我还为这些字体创建了一个编辑器: https://terabaud.github.io/pi...

若干 WebGL 基础知识

我将介绍 WebGL 的一些基础知识,但这里仅涉及部分问题。获取有关详细指导,建议您访问 https://webglfundamentals.org

对于 WebGL,一个常见误解是把它当作浏览器中的 3D 引擎。尽管 WebGL 技术能使我们在浏览器中提供 GPU 加速的 3D 内容,但 WebGL 本身不是 3D 引擎。在 WebGL 之上,有专门用于 GPU 加速的 2D 或 3D 内容的图形库(例如用于 2D 的 Pixi,用于 3D 的 ThreeJS)。

WebGL 本身是很基础的绘图标准库,并且是一个以 GPU 加速的方式,将点、线和三角形绘制到 html <canvas> 元素上的库。

可以通过 getContext (类似于 2D canvas API )检索 WebGL 渲染上下文:

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

一个 WebGL 程序包含多个着色器组件,着色器是运行在 GPU 上的代码,它们不是用 JAVAScript 编写的,而是具有自己的语言,称为 GLSL(GL 着色器语言)。

GLSL 快速概览

  • 类似 C语言,着色器程序包含 void main()
  • 变量声明也像在 C 语言中一样
  • 原始数据类型: int , float , double
  • 向量: vec2 , vec3 , vec4 , ...
  • 矩阵: mat2 , mat3 , mat4 , ...
  • 访问纹理数据的类型: sampler2D
  • 内置向量、矩阵运算
  • 大量内置功能 , 例如,求取向量的长度( length(v) )

着色器的类型

WebGL 程序中有两种类型的着色器。

  • 顶点着色器计算位置。
  • 片段着色器处理栅格化。

如果您的 WebGL 程序想要在屏幕上绘制一个三角形,它会把三角形的 3 个坐标传递给顶点着色器。然后,片段着色器的任务是用像素填充该三角形,这种逐像素处理过程非常快,因为它是针对 GPU 上的每个像素并行运行处理的。

在我的演示案例中,我使用 4 个矢量坐标来覆盖适合整个屏幕的矩形,所有工作都在片段着色器中完成。

顶点着色器

顾名思义,顶点着色器存在于顶点。它从 JavaScript 代码提供的缓冲区中获取一堆数据,并根据这些数据计算在画布中的相应位置。

以下代码段将数据从缓冲区拉入一个 attribute 变量,并将其传递给该 gl_Position 变量:

attribute vec3 position;
void main() {
  gl_Position = vec4(position, 1.0);
}

片段着色器

precision highp float;
void main() {
  vec2 p = gl_FragCoord.xy;  gl_FragColor = vec4(1.0, .5 + .5 * sin(p.y), .5 + .5 * sin(p.x), 1.0);
}

片段着色器针对每个片段(像素)并行运行。在上面的示例中,片段着色器从 gl_FragCoord 变量读取当前像素坐标,并通过 gl_FragColor 中的 sin() 计算运行并输出颜色。

gl_FragColor 是一个 vec4 向量,其中包含(红色,绿色,蓝色,alpha),取值各为 0 .. 1。

GLSL 变量的类型

attribute
uniformvarying

上传图像数据

您可以使用图像数据访问到着色器中的 WebGLRenderingContext,并将其上传到 纹理 中。(另请参见: WebGL 基础知识:图像处理 )

您可以使用 texImage2D 内部方法 WebGLRenderingContext 将图像数据上传到纹理中。

// gl is the WebGLRenderingContext 
const texture = gl.createTexture()
gl.activeTexture(gl.TEXTURE0 + textureIndex);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
// more info about these parameters in the webglfundamentals
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

您传递给 texImage2D 的图像数据,可以是 img 元素、视频元素、ImageData 等。

由于视频的图像数据不断变化,因此您必须在 requestAnimationFrame 动画循环内更新纹理。以下是获取完成的 texSubImage2D 。

gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, video);

在着色器代码中读取纹理数据

您可以通过 texture 的 2Dglsl 函数访问纹理的像素数据。

当纹理坐标从(0,0)变为(1,1)时,图像会上下颠倒。同时,我正处于水平镜像图像中(就像用相机自拍一样)。

uniform sampler2D texture0;
void main() {
  vec2 coord = 1.0 - gl_FragCoord.xy / vec2(width, height);
  gl_FragColor = texture2D(texture1, coord);
}

访问网络摄像头

要从网络摄像头获取图像数据,我们可以使用 video 标签,并使用 getUserMediaAPI :

function accessWebcam(video) {
  return new Promise((resolve, reject) => {
    const mediaConstraints = { audio: false, video: { 
        width: 1280, 
        height: 720,
        brightness: {ideal: 2} 
      }    };    navigator.mediaDevices.getUserMedia(      mediaConstraints).then(mediaStream => {
        video.srcObject = mediaStream;        video.setAttribute('playsinline', true);
        video.onloadedmetadata = (e) => {
          video.play();          resolve(video);        }      }).catch(err => {
        reject(err);      });    }  );}// 使用说明:
// const video = await accessWebcam(document.querySelector('video'));
// or via promises:
// accessWebcam(document.querySelector('video')).then(video => { ... });

要访问网络摄像头,您可以使用 getUserMedia API 来访问网络摄像头,如上所述。

提供后备图像

如果用户阻止了对网络摄像头的访问,或者没有可用的网络摄像头,则可以提供一个备用图像供您使用。

我也将 new Image() 中的 onload 操作包装成一个 promise 。

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'Anonymous';
    img.src = url;    img.onload = () => {
      resolve(img);    };    img.onerror = () => {
      reject(img);    };  });}

合并全部操作

为了使事情变得容易一些,我将常用的 WebGL 函数放入了我创建的一个小助手库 GLea 中。

它初始化 WebGL 应用上下文,编译 WebGL 着色器代码,并为顶点着色器创建属性和缓冲区:

默认情况下, position 为顶点着色器提供一个属性,该属性带有一个缓冲区,该缓冲区包含 4 个 2D 坐标,覆盖整个屏幕上的 2 个三角形。

import GLea from 'glea.js';
const frag = ` ... `; // 片段着色器代码
const vert = ` ... `; // 顶点着色器代码
const glea = new GLea({
  shaders: [    GLea.fragmentShader(frag),    GLea.vertexShader(vert)  ]}).create();function loop(time = 0) {
  const { gl, width, height } = glea;  glea.clear();  glea.uniV('resolution', [width, height]);
  glea.uni('time', time * 1e-3);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  requestAnimationFrame(loop);
}window.addEventListener('resize', () => {
  glea.resize();});loop(0);

结论

基本上就是这样。我希望您喜欢阅读本文,并对自己探索 WebGL 感到好奇。我会在这里放一些资源。



Tags:视频处理   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
一、FFmpeg视频解码器1.视频解码知识1).纯净的视频解码流程压缩编码数据->像素数据。例如解码H.264,就是“H.264码流->YUV”。2).一般的视频解码流程视频码流一般存储在一定...【详细内容】
2021-05-19  Tags: 视频处理  点击:(163)  评论:(0)  加入收藏
近些年,在线教育行业飞速发展,为整个社会的知识传播提供了前所未有的便利性。通过多种形式的在线教育平台,学员与教师即使相隔万里也可以开展教学活动。借助丰富的网络课件,学员...【详细内容】
2020-09-15  Tags: 视频处理  点击:(68)  评论:(0)  加入收藏
这是我最近在 CodePen 上制作的 WebGL 演示案例。它可以捕获网络摄像头的数据(或在无法访问网络摄像头时,从 placekitten 获取备用图像),并将其实时转换为 ASCII 图像艺术。 为...【详细内容】
2020-09-02  Tags: 视频处理  点击:(163)  评论:(0)  加入收藏
▌简易百科推荐
今天还真是有点小激动啊,B站看来要和抖音杠上了,之前抖音推出网页端要对标B站,不过似乎大家没有用网页刷抖音的习惯。但是这次B站竟然推出了“必剪”电脑客户端,激动的我赶紧下...【详细内容】
2021-12-14  最佳应用    Tags:剪辑   点击:(20)  评论:(0)  加入收藏
做短视频的话我们需不需要跟着热点走呢?答案当然是肯定的!而且还是一定要的!为什么呢?因为热点是最大的流量池,比如最近的大S离婚事件就是热点,这是最大的流量池。所有人的目光都...【详细内容】
2021-12-01  易撰    Tags:短视频   点击:(24)  评论:(0)  加入收藏
平时工作的时候想必大家都有听音乐(摸鱼)的视频,音乐给我们的生活带来了很大的乐趣,但是很多时候我们会发现一些格式的限制,无法播放我们用各种工具录制的音乐,我们现在就来对音频...【详细内容】
2021-11-16  下科技小助手    Tags:MP3   点击:(26)  评论:(0)  加入收藏
游戏视频录制,用什么软件录屏好?小关这几周在某鱼看到了好多的游戏主播,这些游戏主播有的比技术,有的比能说会道,有的比样貌。都在各自得直播间里面玩得热火朝天,有自己的一处小天...【详细内容】
2021-11-11  杨姐爱智能    Tags:录屏   点击:(35)  评论:(0)  加入收藏
怎么在电脑上录制高清视频?小米最近在学校有点闲,因为这个学期的课程较少,自己也提前完成了许多的学习任务,想着怎么有效的把这些空闲的时间好好利用起来,不能白白浪费这些时间吧...【详细内容】
2021-11-11  张哥聊科技    Tags:高清视频   点击:(22)  评论:(0)  加入收藏
时长:4h 14m | 32节| 视频:1280&times;720,44 KHz | 2.6 GB语言:英语+中英文字幕(根据原英文字幕机译更准确)成为Adobe Premiere Pro专业版视频编辑专家的唯一要求你会学到什么a...【详细内容】
2021-11-03  CG达人  搜狐号  Tags:Premiere   点击:(23)  评论:(0)  加入收藏
我们在制作短视频的时候,需要自己给视频配音,然后与拍摄内容合成还是很难的,所以少不了后期配音的环节。今天小编给大家推荐几款,超好用的短视频配音软件。1、剪映小伙伴是不是...【详细内容】
2021-11-03  语音dub爱好者  搜狐号  Tags:视频配音   点击:(65)  评论:(0)  加入收藏
视频怎么压缩变小?视频的出现虽然说给我们的日常生活带来了极大的消遣与事业发展,但是不得不说视频格式非常占用内存,如果想要进行视频的拍摄、剪辑、放映对工具都需要较高的要...【详细内容】
2021-11-03  娱乐情怀    Tags:视频   点击:(44)  评论:(0)  加入收藏
如何把m4v转换成mp4格式?M4V是一种应用于网络视频点播网站和移动手持设备的视频格式,是MP4格式的一种特殊类型。由苹果公司创造,此种格式为 iPod 、iPhone 和 PlayStation Port...【详细内容】
2021-11-03  纸折兔    Tags:m4v   点击:(38)  评论:(0)  加入收藏
FFmpeg的作用: FFmpeg是一个优秀的多媒体框架; FFmpeg可以运行在Linux,Mac,Windows等平台; FFmpeg可以解码,编码,转码,复用,解复用,过滤音视频数据。播放器基本架构:image.pngSDL视频渲...【详细内容】
2021-10-27  linux音视频    Tags:FFmpeg   点击:(30)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条