前一篇文章中,實(shí)現(xiàn)了 opengles 進(jìn)行相機(jī)預(yù)覽的功能株茶,基本的流程如下:
- 把相機(jī)的預(yù)覽數(shù)據(jù)做成紋理来涨,綁定到opengles對應(yīng)的紋理單元上
- 然后通過opengles 的內(nèi)置函數(shù) texture(),在片段著色器中根據(jù)紋理和紋理坐標(biāo)進(jìn)行插值計(jì)算
- 直接將計(jì)算結(jié)果輸出到顏色緩沖區(qū)启盛,顯示到屏幕的像素上蹦掐。
給圖像添加濾鏡本質(zhì)上就是圖片處理,也就是對圖片的像素進(jìn)行計(jì)算僵闯,簡單來說卧抗,圖像處理的方法可以分為三類:
- 點(diǎn)算子:當(dāng)前像素的處理只和自身的像素值有關(guān),和其他像素?zé)o關(guān)鳖粟,比如灰度處理社裆。
- 鄰域算子:當(dāng)前像素的處理需要和相鄰的一定范圍內(nèi)的像素有關(guān),比如高斯模糊向图。
- 全局算子:在全局上對所有像素進(jìn)行統(tǒng)一變換泳秀,比如幾何變換标沪。
實(shí)現(xiàn)濾鏡的思路
濾鏡本質(zhì)上就是對每個位置的顏色值進(jìn)行調(diào)整,比如灰度效果嗜傅,就是將彩色圖像的各個顏色分量的值變成一樣的金句。
對顏色值進(jìn)行調(diào)整的時機(jī)應(yīng)該是再上面步驟的2、3之間吕嘀,這個時候已經(jīng)拿到了顏色值违寞,還沒有輸出到顏色緩沖區(qū),這個時候我們對顏色值進(jìn)行處理就可以實(shí)現(xiàn)濾鏡效果偶房。
用上一篇的片段著色器代碼做個說明:
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;
in vec2 v_texCoord;
out vec4 outColor;
uniform samplerExternalOES s_texture;
void main(){
//拿到顏色值
vec4 tmpColor = texture(s_texture, v_texCoord);
//對顏色值進(jìn)行處理
process(tmpColor);
//將處理后的顏色值輸出到顏色緩沖區(qū)
outColor = tmpColor;
}
點(diǎn)算子實(shí)現(xiàn)的濾鏡
灰度濾鏡
灰度濾鏡通過圖像的灰度化算法進(jìn)行實(shí)現(xiàn)坞靶。
在 RBG顏色模型中,讓 R=G=B=grey蝴悉, 即可將彩色圖像轉(zhuǎn)為灰度圖像彰阴,其中 grey 叫做灰度值。
grey的計(jì)算方法有四種:分量法拍冠,最大值法尿这,平均值法、加權(quán)平均法庆杜。
分量法
使用彩色圖像的某個顏色分量的值作為灰度值射众。
- grey=R:R分量灰度圖
- grey=G:G分量灰度圖
- grey=B:B分量灰度圖
最大值法
將彩色圖像三個顏色分量中值最大的作為灰度值。
grey = max(R,G,B)
平均值法
將彩色圖像的三個顏色分量值的平均值作為灰度值
grey = (R+G+B)/3
加權(quán)平均法
在 RGB 顏色模型中晃财,人眼對G(綠色)的敏感度最高叨橱,對B(藍(lán)色)的敏感的最低,所以對彩色圖像的三個顏色分量做加權(quán)平均計(jì)算灰度值效果比較好断盛。
grey = 0.3R + 0.59G + 0.11*B
下面在片段著色器中用加權(quán)平均法實(shí)現(xiàn)灰度濾鏡罗洗。
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;
in vec2 v_texCoord;
out vec4 outColor;
uniform samplerExternalOES s_texture;
//灰度濾鏡
void grey(inout vec4 color){
float weightMean = color.r * 0.3 + color.g * 0.59 + color.b * 0.11;
color.r = color.g = color.b = weightMean;
}
void main(){
//拿到顏色值
vec4 tmpColor = texture(s_texture, v_texCoord);
//對顏色值進(jìn)行處理
grey(tmpColor);
//將處理后的顏色值輸出到顏色緩沖區(qū)
outColor = tmpColor;
}
效果圖
原圖 | 灰度濾鏡 |
---|---|
image
|
image
|
黑白濾鏡
黑白濾鏡就是將圖像進(jìn)行二值化處理,彩色圖像的顏色值經(jīng)過處理之后钢猛,要么是 0(黑色)伙菜,要么是255(白色)。
實(shí)際應(yīng)用中使用的不多命迈,從各大直播贩绕、美顏相機(jī)、短視頻app上就能發(fā)現(xiàn)壶愤,基本上沒有用黑白濾鏡淑倾,因?yàn)椴缓每础?/p>
二值化方法主要有:全局二值化,局部二值化征椒,局部自適應(yīng)二值化娇哆。最影響效果的就是閾值的選取。
- 全局二值化是選定一個閾值,然后將大于該閾值的顏色值置為255迂尝,小于該閾值的顏色置為0脱茉。因?yàn)槭褂玫娜珠撝担詴适Ш芏嗉?xì)節(jié)垄开。
- 局部二值化:為了彌補(bǔ)全局閾值化的缺陷琴许,將圖像分為N個窗口,每個窗口設(shè)定一個閾值溉躲,進(jìn)行二值化操作榜田,一般取該窗口顏色值的平均值。
- 局部自適應(yīng)二值化:局部二值化的閾值選取方法仍然不能很好的將對應(yīng)窗口的圖像進(jìn)行二值化锻梳,在此基礎(chǔ)上箭券,通過窗口顏色的平均值E、像素之間的差平方P疑枯、像素之間的均方根Q等能夠表示窗口內(nèi)局部特征的參數(shù)辩块,設(shè)定計(jì)算公式計(jì)算閾值。
這里使用最簡單的全局二值化做個示例
//黑白濾鏡
void blackAndWhite(inout vec4 color){
float threshold = 0.5;
float mean = (color.r + color.g + color.b) / 3.0;
color.r = color.g = color.b = mean >= threshold ? 1.0 : 0.0;
}
效果圖
原圖 | 黑白濾鏡 |
---|---|
image
|
image
|
反色濾鏡
RGB 顏色值的范圍是 [0,255]荆永,反色濾鏡的的原理就是將 255 與當(dāng)前顏色的每個分量Rs,Gs,Bs值做差運(yùn)算废亭。
結(jié)果顏色為 (R,G,B) = (255 - Rs, 255 - Gs, 255 - Bs);
//反向?yàn)V鏡
void reverse(inout vec4 color){
color.r = 1.0 - color.r;
color.g = 1.0 - color.g;
color.b = 1.0 - color.b;
}
效果圖
原圖 | 反色濾鏡 |
---|---|
image
|
image
|
亮度濾鏡
增加亮度有兩種方法:
- 再 rgb 顏色空間下,將各個顏色分量都加上一個值具钥,可以達(dá)到圖像亮度增加的目的豆村,但是這種方式會導(dǎo)致圖像一定程度上偏白。
- 將顏色值從 rgb 顏色空間轉(zhuǎn)換到 hsl 顏色空間上骂删,因?yàn)?hsl 更適合視覺上的描述掌动,色相、飽和度宁玫、亮度粗恢,調(diào)整 l(亮度分量),即可實(shí)現(xiàn)圖像的亮度處理撬统,然后將調(diào)整后的 hsl 值再轉(zhuǎn)換到 rgb 顏色空間上進(jìn)行輸出适滓。
下面以第2中方式為例:
//rgb轉(zhuǎn)hsl
vec3 rgb2hsl(vec3 color){
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(color.bg, K.wz), vec4(color.gb, K.xy), step(color.b, color.g));
vec4 q = mix(vec4(p.xyw, color.r), vec4(color.r, p.yzx), step(p.x, color.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
//hsla轉(zhuǎn)rgb
vec3 hsl2rgb(vec3 color){
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(color.xxx + K.xyz) * 6.0 - K.www);
return color.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), color.y);
}
//亮度
void light(inout vec4 color){
vec3 hslColor = vec3(rgb2hsl(color.rgb));
hslColor.z += 0.15;
color = vec4(hsl2rgb(hslColor), color.a);
}
原圖 | 亮度濾鏡 |
---|---|
image
|
image
|