你知道微視背後的視訊特效技術是怎樣做出來的嗎?

騰訊雲加社群發表於2018-08-27

歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~

本文由騰訊視訊雲終端團隊 發表於雲+社群專欄

常青, 2008 年畢業加入騰訊,一直從事客戶端研發相關工作,先後參與過 PC QQ、手機QQ、QQ物聯 等產品專案,目前在騰訊視訊雲團隊負責音視訊終端解決方案的優化和落地工作,幫助客戶在可控的研發成本投入之下,獲得業內一流的音視訊解決方案,目前我們的產品線包括:互動直播、點播、短視訊、實時視訊通話,影象處理,AI 等等。

從眼睛的進化說起

大約在5億4千萬年前的寒武紀,地球上一部分生物體開始進化出了感光細胞,這種細胞可以感應光線的強弱,並且直接驅動本體的運動細胞採取必要的規避動作,以確保脆弱的細胞不被紫外線所傷。

後來單個的感光細胞開始扎堆聚集並且形成了凹陷,隨著凹陷程度的逐步加深,這些感光細胞也就漸漸地匯聚成了一個前部有孔隙的球狀結構,“眼球”的雛形也就由此形成了。

img

隨著球形的眼睛結構漸漸成型,中學物理課本中的“小孔成像”原理也就越來越能發揮作用:只要開孔足夠小,光線就能準確地到達這些聚集的感光細胞進而成像,眼前的物體也就開始變得邊界清晰。代表騰訊文化吉祥物之一的鸚鵡螺,就是採用了這種“以小為美”的進化策略,而且一直堅持到現在。

但是這種越來越小的策略也會導致光線進入量越來越小,所以鸚鵡螺們的世界想必是很昏暗的。我們的祖先可不希望放棄一個光明的世界,所以,我們給自己的眼睛安裝了一個足夠高階的光學部件 —— 晶狀體,以期擁有一個光明而清晰地世界。

然而,當大家都能把世界看得很清楚的時候,色彩分辨能力也就演變成了新一輪的軍備競賽。

當我們的祖先踩著那些堅稱“我就想健健康康地當個素食主義者”的同類屍體艱難前行的時候,他們並不知道,讓自己活得更久的原因,竟然是因為那雙能區分樹葉是嫩葉還是成熟葉片的眼睛。因為成熟的葉片常常包含大量的植物性毒素,會讓進食者身體遭受很大的傷害。所以,我們都是那一波“好色的”猴子的後代。

而眼睛對色彩的分辨能力,不僅在遠古時代讓我們活了下來,也讓今天衣食無憂的我們,能看到更多色彩斑斕的效果。比如短視訊的移形換影特效,其本質原理就是一個充分利用色彩的小把戲。

視訊內容

三原色的修改和組合

人體有三種視覺錐細胞,所以我們看到的顏色都是由三原色組成的,並不是說世界上就只有這些顏色,而是更加絢麗的色彩空間我們也感知不到。

因此,液晶顯示器的成像原理上也就是基於 R(紅)G(綠)B(藍) 三原色的組合而實現的,騰訊雲短視訊(UGSV)的移形換影特效,就是在這三種顏色空間上做了一些文章:

先以一幅靜態的圖片來舉例:

img
Doloris

現在把圖片中紅色的分量去掉,放大10%,再移動一些距離

img
Doloris-strip-red

再把藍色的分量去掉,放大10%,並移動一些距離

img
Doloris-strip-blue

再把綠色的分量去掉,放大10%,並移動一些距離

img
Doloris-strip-green

然後將這三副圖片以33%的透明度和源圖疊加到一起,形成一種移形幻影的效果

img
Doloris-blend

交給計算機來實現

上面這些圖片是我用圖片處理軟體簡單處理後得到的,但如果是視訊檔案,顯然要交給計算機自動解決,如何做到呢?

首先我們先給這幅圖片定義座標,為了方便處理我們將圖片的中心點定義為 (0,0),圖片的XY軸最大值為 1,如下圖所示:

img
座標定義

然後開始處理上面提到的兩個變換,一個是放大,一個是移動。

  • 放大 如果定義圖片上的任意象素座標是(x,y),放大 s倍後的座標就是 (x',y') = s(x,y) = (sx, sy)
  • 移動 如果定義圖片上的任意象素座標是(x,y),將其移動(?x,?y),移動後的座標就是(x',y') = (x+?x, y+?y)
  • 合併 將上面兩個公式進行合併,得到的新座標點就是 (x',y') = (s(x+?x), s(y+?y))
  • 疊加 然後我們要將修改過的圖片疊加到原圖上,alpha疊加的公式是 src * (1 - alpha) + overlay * alpha

基於OpenGL的版本

短視訊的特效處理,每秒鐘要處理幾十張甚至更多的視訊畫面,所以簡單的 C 語言處理演算法並不能滿足效能上的要求,我們需要使用手機的硬體加速能力,目前除了常見的 OpenGL 等 API 之外,還有如 Vulkan, DirectX, Metal 等可選方案。就目前而言,OpenGL 在各平臺上通用性最好,網上的資料也比較豐富,不論是桌面平臺還是移動平臺都有支援,本文就以 OpenGL 來講講特效的實現。

實現移形換影特效的時候,我們會用到 OpenGL 的 Fragment Shader, Fragment Shader 作用就是返回影象各點的色值,Fragment Shader也有一套自己的程式語言,叫 Shading Language 簡稱GLSL, GLSL 和 C 很像,增加了一些向量的資料型別,和一些影象相關的處理函式。Shading 和 C 比起來有一個比較特殊的地方是不支援隱含的型別轉換,比如浮點點整型的轉換(在使用浮點數時,一定要加上小數點,如 1.0)。

篇幅原因,我不在這裡把所有的特效程式碼都一一列舉了,僅附上放大和位移的部分實現:

varying vec2 textureCoordinate;
uniform sampler2D inputImageTexture;

void main() {
	vec2 offset = vec2(0.05, 0.05);
	float scale = 1.1;
	vec2 coordinate;
	coordinate.x = (textureCoordinate.x - offset.x) / scale;
	coordinate.y = (textureCoordinate.y - offset.y) / scale;
	gl_FragColor = texture2D(inputImageTexture, coordinate);
}
複製程式碼

考慮到不是所有讀者都學過 Shading Language,這裡做一個簡單的解讀:

  • 我們在這裡定義了一個變數 coordinate,這個就是前面提到的(x,y),它的值就是 ((x - ?x)/s, (y-?y)/s)
  • 函式 texture2D 的作用就是從圖片中獲取某個座標的顏色。這裡從 inputImageTexture 中的 coodinate 座標點獲取了顏色。
  • gl_FragColor, 這是 Fragment Shader 的輸出的值, gl_FragColor是一個GLSL預定義的全域性變數, 型別是vec4既 (r,g,b,a) 這四個量,也就是一個 RGBA 顏色。
  • 程式執行後在textureCoordinate這個座標就會顯示gl_FragColor這個顏色。

上面講了單幅圖的處理,對於視訊我們可以做些更有意思的效果,比如我們可以把當前幀和上一幀的圖片進行疊加,這樣就可以作出一些更有意思的效果。

img

更多特效

本文介紹了騰訊雲短視訊(UGSV)眾多視訊特效中的一種,如果要實現更加複雜的特效,還是需要繼續深入研究 OpenGL 和人臉識別等相關領域的知識,這需要一段時間的學習和努力,也不可避免的需要踩很多坑。

那有沒有隻需幾分鐘,就能一馬平川地搭快速搭建建帶有各種神奇特效的短視訊應用速成方案呢?

此文已由作者授權騰訊雲+社群釋出,更多原文請點選

問答

文字識別在格式上有什麼要求?

相關閱讀

教你1天搭建自己的“微視”

教你從0到1搭建小程式音視訊

教你快速搭建一場釋出會直播方案

雲學院 · 課程推薦 | 知乎KOL,與你分享機器學習中如何做選擇

搜尋關注公眾號「雲加社群」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!

海量技術實踐經驗,盡在雲加社群

相關文章