GPUImage(二):視頻濾鏡GPUImageFilter基礎(chǔ)篇

按照GPUImage(一):視頻采集GPUImageVideoCamera提到的示例demo FilterShowcase的路徑掂林,初始化videoCamera后設(shè)置GPUImageFilter臣缀。

GPUImageFilter

GPUImageFilter繼承自GPUImageOutput,遵循GPUImageInput協(xié)議泻帮,遵循這個(gè)協(xié)議的對(duì)象都可以從響應(yīng)鏈的上游接收處理過的紋理并繼續(xù)處理精置,下游的處理對(duì)象稱為上一步的target,響應(yīng)鏈的下游可以有多個(gè)target(或分支)锣杂。
所以脂倦,GPUImageFilter就是用來接收源圖像,通過自定義的頂點(diǎn)蹲堂、片元著色器來渲染新的圖像狼讨,并在繪制完成后通知響應(yīng)鏈的下一個(gè)對(duì)象,既可以流入數(shù)據(jù)柒竞,也可以流出數(shù)據(jù)政供,GPUImageView,GPUImageMovieWriter是最終輸出target,來顯示圖片或者視頻朽基。

GPUImageFilter.png

GPUImageSaturationFilter

直接看GPUImageFilter代碼有些抽象布隔,從GPUImageSaturationFilter入手更容易理解。當(dāng)從FilterShowcase demo列表中選中Saturation時(shí)稼虎,filter操作——

filter = [[GPUImageSaturationFilter alloc] init];//filter初始化
.
.
[videoCamera addTarget:filter];//GPUImageVideoCamera添加filter作為target
.
.
GPUImageView *filterView = (GPUImageView *)self.view;//設(shè)置當(dāng)前view為預(yù)覽view
.
.
[filter addTarget:filterView];//filter添加預(yù)覽view為最終target
.
.
[videoCamera startCameraCapture];//相機(jī)開始捕獲

如果需要更改強(qiáng)度
[(GPUImageSaturationFilter *)filter setSaturation:[(UISlider *)sender value]]; break;
簡(jiǎn)單幾步衅檀,即完成了調(diào)用和強(qiáng)度設(shè)置。
GPUImageSaturationFilter的.h文件只有一個(gè)saturation屬性用于修改霎俩,.m文件分為兩個(gè)部分哀军,第一部分是一個(gè)做飽和度調(diào)節(jié)的片段著色器,這個(gè)著色器出自《圖形著色器:理論和實(shí)踐》一書打却;第二部分是濾鏡的初始化方法和飽和度強(qiáng)度設(shè)置方法杉适。分別來說。

飽和度片段著色器

飽和度是用來表示顏色的亮度強(qiáng)度的術(shù)語柳击。一件亮紅色的毛衣的飽和度要遠(yuǎn)比北京霧霾時(shí)灰色的天空的飽和度高得多猿推。
在這個(gè)著色器上,參照人類對(duì)顏色和亮度的感知過程捌肴,有一些優(yōu)化可以使用蹬叭。一般而言藕咏,人類對(duì)亮度要比對(duì)顏色敏感的多。這么多年來秽五,壓縮軟件體積的一個(gè)優(yōu)化方式就是減少存儲(chǔ)顏色所用的內(nèi)存孽查。
人類不僅對(duì)亮度比顏色要敏感,同樣亮度下筝蚕,我們對(duì)某些特定的顏色反應(yīng)也更加靈敏卦碾,尤其是綠色。這意味著起宽,當(dāng)你尋找壓縮圖片的方式洲胖,或者以某種方式改變它們的亮度和顏色的時(shí)候,多放一些注意力在綠色光譜上是很重要的坯沪,因?yàn)槲覀儗?duì)它最為敏感绿映。

//飽和度片元著色器
NSString *const kGPUImageSaturationFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform lowp float saturation;
 
 // Values from "Graphics Shaders: Theory and Practice" by Bailey and Cunningham
 const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
 
 void main()
 {
    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
    lowp float luminance = dot(textureColor.rgb, luminanceWeighting);
    lowp vec3 greyScaleColor = vec3(luminance);
    
    gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w);
     
 }
);

在 GLSL 中,有三種標(biāo)簽可以賦值給我們的變量:

  • Uniforms
  • Attributes
  • Varyings

Uniforms 是一種外界和你的著色器交流的方式腐晾,在頂點(diǎn)著色器和片段著色器里都可以被訪問到叉弦。Uniforms 在一個(gè)渲染循環(huán)里作為不變的輸入值。如果你正在應(yīng)用茶色濾鏡藻糖,并且你已經(jīng)指定了濾鏡的強(qiáng)度淹冰,那么這些就是在渲染過程中不需要改變的事情,你可以把它作為 Uniform 輸入巨柒。
Attributes是隨頂點(diǎn)位置不同會(huì)變的輸入值
Varying 是用來在頂點(diǎn)著色器和片段著色器傳遞信息的樱拴,在頂點(diǎn)著色器和片段著色器都會(huì)出現(xiàn),并且在頂點(diǎn)著色器和片段著色器中必須有匹配的名字洋满。數(shù)值在頂點(diǎn)著色器被寫入到 varying 晶乔,然后在片段著色器被讀出。被寫入 varying 中的值牺勾,在片段著色器中會(huì)被以插值的形式插入到兩個(gè)頂點(diǎn)之間的各個(gè)像素中去正罢。
這里出現(xiàn)了兩種,逐行來看

varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform lowp float saturation;
  • textureCoordinate:因?yàn)轫旤c(diǎn)著色器負(fù)責(zé)和片段著色器交流驻民,所以需要?jiǎng)?chuàng)建一個(gè)變量和它共享相關(guān)的信息翻具。在圖像處理中,片段著色器需要的唯一相關(guān)信息就是頂點(diǎn)著色器現(xiàn)在正在處理哪個(gè)像素回还,它需要存儲(chǔ)像素的 X 和 Y 坐標(biāo)裆泳。片段著色器接收到的正是當(dāng)前在頂點(diǎn)著色器被設(shè)置好的紋理坐標(biāo)。所以為輸入紋理坐標(biāo)和輸入圖片紋理聲明一個(gè)varyings變量懦趋。
  • inputImageTexture:為了處理圖像晾虑,從應(yīng)用中接收一個(gè)圖片的引用疹味,把它當(dāng)做一個(gè) 2D 的紋理仅叫。這個(gè)數(shù)據(jù)類型被叫做 sampler2D 帜篇,這是因?yàn)橐獜倪@個(gè) 2D 紋理中采樣出一個(gè)點(diǎn)來進(jìn)行處理。
  • saturation :飽和度的數(shù)值是一個(gè)我們從用戶界面設(shè)置的參數(shù)诫咱。我們需要知道用戶需要多少飽和度笙隙,從而展示正確的顏色數(shù)量。
const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);

這就是設(shè)置三個(gè)元素的向量坎缭,為亮度來保存顏色比重的地方竟痰。這三個(gè)值加起來要為 1,這樣我們才能把亮度計(jì)算為 0.0 - 1.0 之間的值掏呼。注意中間的值坏快,就是表示綠色的值,用了 70% 的顏色比重憎夷,而藍(lán)色只用了它的 10%莽鸿。藍(lán)色對(duì)我們的展示不是很好,把更多權(quán)重放在綠色上是很有意義的拾给。

接下來是main()函數(shù)中的代碼:

lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
lowp float luminance = dot(textureColor.rgb, luminanceWeighting);
lowp vec3 greyScaleColor = vec3(luminance);

  • textureColor:texture2D()是GLSL 特有的方法祥得,顧名思義,創(chuàng)建一個(gè) 2D 的紋理蒋得。它采用之前聲明過的屬性作為參數(shù)來決定被處理的像素的顏色级及,取樣特定像素在圖片/紋理中的具體坐標(biāo)來獲取顏色信息。
  • luminance:dot()這是在使用 GLSL 中的點(diǎn)乘運(yùn)算额衙。點(diǎn)乘計(jì)算以包含紋理顏色信息的 vec4 為參數(shù)饮焦,舍棄 vec4 的最后一個(gè)不需要的元素,將它和相對(duì)應(yīng)的亮度權(quán)重相乘入偷。然后取出所有的三個(gè)值把它們加在一起追驴,計(jì)算出這個(gè)像素綜合的亮度值。
  • greyScaleColor:創(chuàng)建一個(gè)三個(gè)值都是亮度信息的 vec3疏之。如果只指定一個(gè)值殿雪,編譯器會(huì)幫你把該將向量中的每個(gè)分量都設(shè)成這個(gè)值。
gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w);

把所有的片段組合起來锋爪。為了確定每個(gè)新的顏色是什么丙曙,使用mix() 函數(shù)。mix 函數(shù)會(huì)把剛剛計(jì)算的灰度值初始的紋理顏色以及得到的飽和度信息相結(jié)合其骄。因?yàn)槠沃鞯奈ㄒ荒康木褪谴_定一個(gè)像素的顏色亏镰,gl_FragColor 本質(zhì)上就是片段著色器的返回語句。一旦這個(gè)片段的顏色被設(shè)置拯爽,接下來片段著色器就不需要再做其他任何事情了索抓,所以在這之后寫任何的語句,都不會(huì)被執(zhí)行。

幾個(gè)函數(shù):

mix(): mix 函數(shù)將兩個(gè)值 (例如顏色值) 混合為一個(gè)變量逼肯。如果我們有紅和綠兩個(gè)顏色耸黑,我們可以用 mix() 函數(shù)線性插值。這在圖像處理中很常用篮幢,比如在應(yīng)用程序中通過一組獨(dú)特的設(shè)定來控制效果的強(qiáng)度等大刊。

GPUImageSaturationFilter: @implementation

GPUImageSaturationFilter只有兩個(gè)方法,一個(gè)init方法和一個(gè)- (void)setSaturation:(CGFloat)newValue;方法三椿。

- (id)init {
    if (!(self = [super initWithFragmentShaderFromString:kGPUImageSaturationFragmentShaderString])) {
        return nil;
    }
    saturationUniform = [filterProgram uniformIndex:@"saturation"];
    self.saturation = 1.0;

    return self;
}
- (void)setSaturation:(CGFloat)newValue {
    _saturation = newValue;
    [self setFloat:_saturation forUniform:saturationUniform program:filterProgram];
}
  • init方法:把創(chuàng)建的片段著色器kGPUImageSaturationFragmentShaderString通過父類GPUImageFilter初始化缺菌。
    saturationUniform = [filterProgram uniformIndex:@"saturation"]// This does assume a name of "saturation" for the fragment shader//得到名字叫“ saturation”的片元著色器常量

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鸦列,隨后出現(xiàn)的幾起案子租冠,更是在濱河造成了極大的恐慌,老刑警劉巖薯嗤,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顽爹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡骆姐,警方通過查閱死者的電腦和手機(jī)镜粤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玻褪,“玉大人肉渴,你說我怎么就攤上這事〈洌” “怎么了同规?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窟社。 經(jīng)常有香客問我券勺,道長(zhǎng),這世上最難降的妖魔是什么灿里? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任关炼,我火速辦了婚禮,結(jié)果婚禮上匣吊,老公的妹妹穿的比我還像新娘儒拂。我一直安慰自己寸潦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布社痛。 她就那樣靜靜地躺著甸祭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪褥影。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天咏雌,我揣著相機(jī)與錄音凡怎,去河邊找鬼。 笑死赊抖,一個(gè)胖子當(dāng)著我的面吹牛统倒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氛雪,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼房匆,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了报亩?” 一聲冷哼從身側(cè)響起浴鸿,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弦追,沒想到半個(gè)月后岳链,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡劲件,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年掸哑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片零远。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苗分,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牵辣,到底是詐尸還是另有隱情摔癣,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布纬向,位于F島的核電站供填,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏罢猪。R本人自食惡果不足惜近她,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望膳帕。 院中可真熱鬧粘捎,春花似錦薇缅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至娩缰,卻和暖如春灸撰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拼坎。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工浮毯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泰鸡。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓债蓝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盛龄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饰迹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容