如何使用 WebGL 進行實時視頻處理

2020-09-04 閃念基因

這是我最近在 CodePen 上製作的 WebGL 演示案例。它可以捕獲網絡攝像頭的數據(或在無法訪問網絡攝像頭時,從 placekitten 獲取備用圖像),並將其實時轉換為 ASCII 圖像藝術。

為了獲得更多的復古性,我使用了 90 年代 DOS PC 中常見的 8x8 像素光柵字體(您可能會在某些 BIOS 中看到這種字體)。

要將圖像內容映射到特定字符,我通過使用亮度圖選擇最佳匹配。我計算每個 4x4 正方形的像素。在畫板內向下滾動以查看亮度圖:

我還為這些字體創建了一個編輯器: 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(&39;);const gl = canvas.getContext(&39;) || canvas.getContext(&39;);

一個 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 變量的類型

attributeuniformvarying

上傳圖像數據

您可以使用圖像數據訪問到著色器中的 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 webglfundamentalsgl.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(&39;, true); video.onloadedmetadata = (e) => { video.play(); resolve(video); } }).catch(err => { reject(err); }); } );}// 使用說明:// const video = await accessWebcam(document.querySelector(&39;));// or via promises:// accessWebcam(document.querySelector(&39;)).then(video => { ... });

要訪問網絡攝像頭,您可以使用 getUserMedia API 來訪問網絡攝像頭,如上所述。

提供後備圖像

如果用戶阻止了對網絡攝像頭的訪問,或者沒有可用的網絡攝像頭,則可以提供一個備用圖像供您使用。

我也將 new Image() 中的 onload 操作包裝成一個 promise 。

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

合併全部操作

為了使事情變得容易一些,我將常用的 WebGL 函數放入了我創建的一個小助手庫 GLea 中。

它初始化 WebGL 應用上下文,編譯 WebGL 著色器代碼,並為頂點著色器創建屬性和緩衝區:

默認情況下, position 為頂點著色器提供一個屬性,該屬性帶有一個緩衝區,該緩衝區包含 4 個 2D 坐標,覆蓋整個屏幕上的 2 個三角形。

import GLea from &39;;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(&39;, [width, height]); glea.uni(&39;, time * 1e-3); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); requestAnimationFrame(loop);}window.addEventListener(&39;, () => { glea.resize();});loop(0);

結論

基本上就是這樣。我希望您喜歡閱讀本文,並對自己探索 WebGL 感到好奇。我會在這裡放一些資源。

相關焦點

  • 如何使用視頻轉換器進行視頻轉gif處理
    如何使用視頻轉換器進行視頻轉gif處理?gif動態圖作為表情包的一種深受用戶的喜愛,gif動態表情包相比傳統靜態表情包的優勢在於,動態表情包能更深層次的表達出我們想要表述的內容。而gif通常是由視頻轉換而來的,那你知道如何使用視頻轉換器把視頻轉換成gif格式呢?
  • 圖形學基礎——WebGL 基礎(上)
    我們是通過對 GPU 進行編程,進行渲染圖形:對於 GPU 編程主要從下面兩個方面進行編程:webgl:API glTranslate/glRotatefGLSL:頂點著色器 - gl_Position 和 片元著色器 - gl_FragColor#webgl 渲染管線JavaScript通過顯存的Buffer來實現頂點著色器與片元著色器的數據傳遞
  • 使用WebGL 2.0更快地渲染 3D
    WebGL 2.0 目前可供擁有當代圖形硬體並運行 Windows、macOS 和 Linux 的 Chrome 用戶使用,很快還會推廣到 Android 平臺上。WebGL 2.0 轉換反饋演示:github.com/toji/webgl2
  • 騰訊2020開發者大會:web多媒體技術在視頻編輯場景的應用
    這是由於視頻的後期處理,需要使用到opengl強大的圖形渲染能力,便於添加特效、濾鏡及更多多媒體元素等。然後將opengl繪製內容進行編碼,最後與音頻一起封裝成媒體文件。這隻一個基礎原理,在實際應用中當然會複雜很多。
  • webgl 迷宮項目開發總結
    收穫webgl 三個js庫webgl-utils.jswebgl-debug.jscuon-utils.js圖片加載var img = new Image();img.src = '.這樣可以防止webgl在渲染的時候圖片還沒加載完而出現黑屏的問題。監聽鍵盤事件保證事件代碼只運行一次。否則會重複綁定多個事件,也就是按鍵一次會觸發多次事件處理。
  • 瀏覽器中禁用WebGL
    WebGL存在的漏洞已被公布,雖然該小組還未披露更多細節,但是WebGL可以被用來進行跨域名的非法圖片讀取已經被證實。可能受攻擊的目標有:各種登錄用的驗證碼圖片,涉及隱私的照片等。另外,黑客也可以檢測你對特定圖片的訪問結果,來判斷你在一個網站上的身份和權限。為了避免由WebGL帶來的安全隱患,最好是先將WebGL禁止。
  • 八大瘋狂的 HTML5 Canvas 及 WebGL 動畫效果
    在過去的幾年中,我們想要製作卓越的網頁動畫只能使用Flash和Java Applet。而現在,使用腳本語言和渲染器在瀏覽器中實現瘋狂的動畫效果已經成為可能。究其原因,大概有以下幾點: 處理器的性能越來越高。我們的電腦已經有足夠的強大的能力去渲染最為複雜的動畫效果。 現在瀏覽器和web技術的不斷發展。
  • 如何在Internet Explorer 11中開啟WebGL
    Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_WEBGL_HLSL_SHADERS]"iexplore.exe"=dword:00000000需要特別值得注意的是其中最後一個FEATURE_WEBGL_HLSL_SHADERS的鍵值,如果設置為1,那麼會讓Internet Explorer 11使用
  • 圖形學基礎——WebGL 基礎(下)
    設點p(x,y,z)旋轉β角度後變成p'(x',y',z'):首先旋轉是繞Z軸信息的,所以z坐標不會變化,可以直接忽略;然後x坐標和y坐標如下:上圖,r 是從圓點到點 p 的距離,而 α 是 X 軸旋轉到 p 的角度,用這兩個變量計算出點 p 的坐標,如下:x = r cos αy = r sin α類似地,可以使用 α 、r、β 來表示 p' 的坐標:
  • 如何對視頻進行處理?視頻處理快速上手工具推薦
    之前沒有接觸過視頻剪輯又想快速入門怎麼辦?下載下來的視頻素材發現有水印怎麼辦?覺得自己的視頻質感不夠,畫面色彩不夠完美,想對視頻進行調色但是又沒有色彩知識怎麼辦?別急,小編今天要為各位介紹三款視頻處理軟體,保證好用又簡單!
  • 如何使用iTools的實時桌面進行ipad截圖和錄像
    在iPad的使用中,有時我們需要對iPad的桌面進行截圖,或者想錄一段iPad操作的視頻,或者想在電腦上同步演示IPAD的操作,等等這些都可以使用iTools的實時桌面功能實現。下面我們來介紹上述功能的實現方法。在電腦上打開iTools軟體,將自己的IPAD連接到電腦。在【我的設備】頁面確認已經連接成功,在iTools軟體界面上可以看到自己的iPad設備。
  • 億級視頻內容如何實時更新?
    這個階段主要通過 Offline/Nearline 把實時實體、離線預處理、算法加工數據進行處理更新。這裡包含了算法對這些數據離線和在線的處理,不同業務域之間最終數據合併(召回、排序、相關性等)。在平臺能力方面採用傳統的數倉模式即圍繞有共性資源、有共性能力方面建設,形成分層策略,將面向業務上層的數據獨立出來,而這種模式在實現業務敏捷迭代、知識化、服務化特徵方面已不能很好滿足需求。
  • 如何製作配音視頻?利用視頻剪輯軟體進行製作
    配音也可以稱為bgm或背景音樂,不同類型的視頻所傳遞的情緒和主題是不一樣的,而同一個視頻使用不同的配音表達的效果也會不一樣。給視頻添加合適的配音可以為視頻增添色彩和烘託氣氛,當我們手中有一份視頻時,該如何製作配音視頻呢?
  • ...計算能力來獲取攝像頭採集的視頻並採用多個卷積神經網絡進行處理
    打開APP 如何使用硬體的計算能力來獲取攝像頭採集的視頻並採用多個卷積神經網絡進行處理 工程師5 發表於 2018-04-27 16:10:00
  • 聲音轉文字如何處理實現實時轉寫所講內容
    聲音轉文字實質上就是把一段語音或錄音識別出來以文字的形式呈現在眼前,現如今我們經常可以使用到這個功能,例如在寫文章時篇幅過長或辦公會議要記錄文字信息等諸多情況下都可以使用到。那麼你知道我們該如何去實時轉寫所講內容嗎?
  • 使用Spark進行微服務的實時性能分析
    在本文,IBM Research展示了如何用Spark對微服務性能進行分析和統計,由OneAPM工程師翻譯。以下為譯文作為一種靈活性極強的構架風格,時下微服務在各種開發項目中日益普及。在這種架構中,應用程式被按照功能分解成一組鬆耦合的服務,它們通過REST APIs相互協作。通過這個設計原則,開發團隊可以快速地不斷迭代各個獨立的微服務。
  • YouTube的挑戰者 JustinTV教你如何打造實時視頻網站
    2.100%可用時間和維護的矛盾實時視頻構建的系統既要保證100%的可用時間,又要保證機器可以進行維護。與一般網站不同,一般網站維護時出現的問題只有少數人會發現、關注,而實時視頻網站不同,用戶很快就會發現維護時帶來的任何問題,並且互相傳播的非常快。這就使得沒有什麼問題可以隱瞞用戶,面對現在用戶的挑剔,你必須避免維護時出問題。
  • 怎麼使用視頻格式轉換器進行flv轉mp4處理
    因此會出現一些兼容性問題而導致視頻不能正常播放的情況,所以很多小夥伴會使用視頻格式轉換器將視頻文件轉換成常用的mp4格式去避免這類情況,下面就來教你利用視頻格式轉換器把flv轉mp4的方法。轉換方法:藉助工具:迅捷視頻轉換器首先我們在電腦上安裝好能進行flv轉mp4處理的視頻格式轉換器,與此同時打開視頻格式轉換器看到主頁面有視頻轉換、視頻分割、視頻合併等諸多視頻編輯方式,而我們依據flv轉mp4的需要選擇對應的『視頻轉換』功能。
  • WebGL 入門-原生API介紹
    當前,大部分瀏覽器都使用語法 canvas.getContext("experimental-webgl") 來獲取 WebGLRenderingContext。//從Canvas中獲取上下文function initWebGL(canvas) {    var gl;    try {        gl = canvas.getContext("experimental-webgl") || canvas.getContext("webgl");    } catch (
  • 八大瘋狂的HTML5 Canvas及WebGL動畫效果
    在過去的幾年中,我們想要製作卓越的網頁動畫只能使用Flash和Java Applet。而現在,使用腳本語言和渲染器在瀏覽器中實現瘋狂的動畫效果已經成為可能。究其原因,大概有以下幾點: 處理器的性能越來越高。我們的電腦已經有足夠的強大的能力去渲染最為複雜的動畫效果。現在瀏覽器和web技術的不斷發展。