zoukankan      html  css  js  c++  java
  • Swift OpenGL ES 自定义常用滤镜(一)

    前面几篇文章已经详细介绍了OpenGL以及OpenGL ES的基本使用、加载一张图片、加载三维立体图像等,学习使用OpenGL的最终主要目的就是处理图片滤镜,视频滤镜,

     常见的一些视频/图像的处理app基本上都是使用OpenGLES实现的,本篇介绍学习自定义一些常用滤镜以及实现原理,主要是顶点着色器程序和片元着色器程序,大部分色滤镜都是顶点着色器进行

    1.分屏滤镜,二三四六九分屏,分屏滤镜主要是改变像素的纹素,通过坐标显示对应映射坐标的纹素

    分屏滤镜就是处理像素点映射到想要显示的像素点的纹素值,可以从顶点着色器处理也可以在片元着色器中处理

    //二分屏顶点着色器代码:
             attribute vec4 Position;
             attribute vec2 TextureCoords;
             varying vec2 TextureCoordsVarying;
    
             void main (void) {
                 gl_Position = Position;
                 TextureCoordsVarying = TextureCoords;
             }
             //二分屏片元着色器代码:
             precision highp float;
             uniform sampler2D Texture;
             varying highp vec2 TextureCoordsVarying;
    
             void main() {
                 vec2 uv = TextureCoordsVarying.xy;
                 float y;
                 if (uv.y >= 0.0 && uv.y <= 0.5) {
                     y = uv.y + 0.25;
                 } else {
                     y = uv.y - 0.25;
                 }
                 gl_FragColor = texture2D(Texture, vec2(uv.x, y));
             }
    //三分屏顶点着色器代码
             attribute vec4 Position;
             attribute vec2 TextureCoords;
             varying vec2 TextureCoordsVarying;
    
             void main (void) {
                 gl_Position = Position;
                 TextureCoordsVarying = TextureCoords;
             }
             //三分屏片元着色器代码
             uniform sampler2D Texture;
             varying highp vec2 TextureCoordsVarying;
    
             void main() {
                 vec2 uv = TextureCoordsVarying.xy;
                 float y;
                 if (uv.y >= 0.0 && uv.y <= 0.33) {
                     y = uv.y + 0.33;
                 }else if (uv.y > 0.66 && uv.y <= 1.0){
                     y = uv.y - 0.33;
                 }else{
                     y = uv.y;
                 }
                 gl_FragColor = texture2D(Texture, vec2(uv.x, y));
             }
    
    //四分屏顶点着色器
            let verstr = """
                 attribute vec4 Position;
                 attribute vec2 TextureCoords;
                 varying vec2 TextureCoordsVarying;
                 void main (void) {
                 gl_Position = Position;
                 TextureCoordsVarying = TextureCoords;
                 }
             """
            //四分屏片元着色器程序代码
            let fragStr = """
                precision highp float;
                uniform sampler2D Texture;
                varying highp vec2 TextureCoordsVarying;
    
                void main() {
                vec2 uv = TextureCoordsVarying.xy;
                float y;
                float x;
                if (uv.y >= 0.0 && uv.y <= 0.5) {
                    y = uv.y * 2.0;
                } else {
                    y = (uv.y - 0.5) * 2.0;
                }
                if (uv.x >= 0.0 && uv.x <= 0.5) {
                    x = uv.x * 2.0;
                } else {
                    x = (uv.x - 0.5) * 2.0;
                }
                
                gl_FragColor = texture2D(Texture, vec2(x, y));
                }
           """
    //六分屏片元着色器代码,顶点着色器和前面的一样
            let fsh6 = """
              precision highp float;
              uniform sampler2D Texture;
              varying highp vec2 TextureCoordsVarying;
    
             void main(){
             vec2 uv = TextureCoordsVarying.xy;
              if (uv.x < 0.3333) {
              uv.x = uv.x * 3.0;
             }else if(uv.x > 0.6666){
              uv.x = (uv.x - 0.6666) * 3.0;
             }else{
              uv.x = (uv.x - 0.3333) * 3.0;
             }
    
             if (uv.y < 0.5){
    
                uv.y = uv.y * 2.0;
             }else{
                uv.y = (uv.y - 0.5) * 2.0;
             }
             gl_FragColor = texture2D(Texture, uv);
    
             }
    
    //九分屏片元着色器程序代码
            let fsh9 = """
             precision highp float;
             uniform sampler2D Texture;
             varying highp vec2 TextureCoordsVarying;
    
            void main(){
            vec2 uv = TextureCoordsVarying.xy;
             if (uv.x < 0.3333) {
             uv.x = uv.x * 3.0;
            }else if(uv.x > 0.6666){
             uv.x = (uv.x - 0.6666) * 3.0;
            }else{
             uv.x = (uv.x - 0.3333) * 3.0;
            }
    
            if (uv.y < 0.3333){
               uv.y = uv.y * 3.0;
            }else if(uv.y < 0.6666){
               uv.y = (uv.y - 0.3333) * 3.0;
            }else {
               uv.y = (uv.y - 0.6666) * 3.0;
            }
            gl_FragColor = texture2D(Texture, uv);
            }
            """

    2.灰度滤镜,就是使rgb三色的平衡,0.2125, 0.7154, 0.0721,人眼对绿色比较敏感,所以绿色值更大一些

             灰度滤镜有多种实现方法:

             1.浮点算法:Gray=R*0.3+G*0.59+B*0.11

             2.整数⽅方法:Gray=(R*30+G*59+B*11)/100

             3.移位⽅方法:Gray =(R*76+G*151+B*28)>>8;

             4.平均值法:Gray=(R+G+B)/3;

             5.仅取绿⾊色:Gray=G

    let maskFsh = """
            precision highp float;
            uniform sampler2D Texture;
            varying highp vec2 TextureCoordsVarying;
            const highp vec3 w = vec3(0.2125, 0.7154, 0.0721);
    
            void main(){
            vec4 color = texture2D(Texture,TextureCoordsVarying);
            float color1 = dot(color.rgb,w);
            gl_FragColor = vec4(vec3(color1),1.0);
            }
            """

    2.漩涡滤镜,给定中心点、半径,旋转角度,距离中心点约近旋转角度越大,坐标某点的颜色值等于旋转之后的纹素颜色值,图像漩涡主要是在某个半径范围里,把当前采样点旋转 ⼀定⻆角度,旋转以后当前点的颜色就被旋转后的点的颜色代替,因此整个半径范围里会有旋转的效果。如果旋 转的时候旋转⻆角度随着当前点离半径的距离递减,整个图像就会出现漩涡效果。这⾥使⽤了了抛物线递减因 子:(1.0-(r/Radius)*(r/Radius))。

    //漩涡滤镜片元着色器代码:
             precision mediump float; //PI
             const float PI = 3.14159265; //纹理理采样器器
             uniform sampler2D Texture; //旋转⻆角度
             const float uD = 80.0; //旋涡半径
             const float uR = 0.5;
             //纹理理坐标
             varying vec2 TextureCoordsVarying;
             void main() {
             //旋转正⽅方形范围:[512,512]
             ivec2 ires = ivec2(512, 512); //获取旋转的直径
             float Res = float(ires.s); //纹理理坐标[0,0],[1,0],[0,1],[1,1]...
             vec2 st = TextureCoordsVarying; //半径 = 直径 * 0.5;
             float Radius = Res * uR;
             //准备旋转处理理的纹理理坐标 = 纹理理坐标 * 直径 vec2 xy = Res * st;
             //纹理理坐标减去中点
             vec2 dxy = xy - vec2(Res/2., Res/2.);
             //r 半径 即跟中点的距离
             float r = length(dxy);
             //抛物线递减因⼦子:(1.0-(r/Radius)*(r/Radius) )  衰减因子为二次函数 
             float beta = atan(dxy.y, dxy.x) + radians(uD) * (1.0-(r/Radius)*(r/Radius));
             if(r<=Radius) {
             //获取的纹理理坐标旋转beta度.
             xy = Res/2.0 + r*vec2(cos(beta), sin(beta));
             }
             //st = 旋转后的纹理理坐标/旋转范围 st = xy/Res;
             //将旋转的纹理理坐标替换原始纹理理坐标TextureCoordsVarying 获取对应像素点的颜⾊色. vec3 irgb = texture2D(Texture, st).rgb;
             //将计算后的颜⾊色填充到像素点中 gl_FragColor
             gl_FragColor = vec4( irgb, 1.0 ); }

    3.马赛克滤镜,马赛克滤镜就是某一小半径大小的圆内的颜色值的相同,都取圆心的颜色值,

    马赛克效果就是把图片的一个相当⼤⼩的区域⽤同一个 点的颜色来表示.可以认为是大规模的降低图像的分辨 率,⽽而让图像的⼀一些细节隐藏起来。

     //马赛克滤镜片元着色器代码:
             on mediump float;
             //纹理理坐标
             varying vec2 TextureCoordsVarying; //纹理理采样器器
             uniform sampler2D Texture;
             //纹理理图⽚片size
             const vec2 TexSize = vec2(400.0, 400.0); //⻢马赛克Size
             const vec2 mosaicSize = vec2(16.0, 16.0);
             void main()
             {
             //计算实际图像位置
             vec2 intXY = vec2(TextureCoordsVarying.x*TexSize.x, TextureCoordsVarying.y*TexSize.y);
             // floor (x) 内建函数,返回⼩小于/等于X的最⼤大整数值.
             // 0123456789  假如m大小为3 ,floor(x/3)* 3,结果,012取0 345取3 678 取6,就形成了某一片是一个文素的颜色,形成马赛克
             // floor (intXY.x / mosaicSize.x) * mosaicSize.x 计算出⼀一个⼩小⻢马赛克的坐标.
             vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x, floor(intXY.y/
             mosaicSize.y)*mosaicSize.y);
             //换算回纹理理坐标
             vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize.y);
             //获取到⻢马赛克后的纹理理坐标的颜⾊色值
             vec4 color = texture2D(Texture, UVMosaic);
             //将⻢马赛克颜⾊色值赋值给gl_FragColor. gl_FragColor = color;
             }

    4.六边形马赛克

             滤镜实现思路: 我们要做的效果就是让一张图片,分割成由六边形组成,让每个六边形中的颜色相同(直接取六边形中⼼点像素RGB较⽅便,我们 这里采⽤的就是这种⽅方法)将它进⾏行行分割,取每个六边形的中⼼点画出⼀个六边形,如下图:

    如上图,画出很多长和宽比例为 2:√3 的的矩形阵。然后我们可以对每个点进行编号,如上图中,采⽤用坐标系标记.

    假如我们的屏幕的左上点为上图的(0,0)点,则屏幕上的任⼀点我们找到它所对应的那个矩形了了。 假定我们设定的矩阵⽐例例为 2*LEN : √3*LEN ,那么屏幕上的任意 点(x, y)所对应的矩阵坐标为(int(x/(2*LEN)), int(y/ (√3*LEN)))。

     //wx,wy -> 表示纹理坐标在所对应的矩阵坐标为 int wx = int(x /( 1.5 * length)); int wy = int(y /(TR * length));

    //六边形马赛克片元着色器代码
             precision highp float;
             uniform sampler2D Texture;
             varying vec2 TextureCoordsVarying;
    
             const float mosaicSize = 0.03;
    
             void main (void)
             {
                 float length = mosaicSize;
                 float TR = 0.866025;
                 
                 float x = TextureCoordsVarying.x;
                 float y = TextureCoordsVarying.y;
                 
                 int wx = int(x / 1.5 / length);
                 int wy = int(y / TR / length);
                 vec2 v1, v2, vn;
                 
                 if (wx/2 * 2 == wx) {
                     if (wy/2 * 2 == wy) {
                         //(0,0),(1,1)
                         v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
                         v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));
                     } else {
                         //(0,1),(1,0)
                         v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
                         v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
                     }
                 }else {
                     if (wy/2 * 2 == wy) {
                         //(0,1),(1,0)
                         v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
                         v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
                     } else {
                         //(0,0),(1,1)
                         v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
                         v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));
                     }
                 }
                 
                 float s1 = sqrt(pow(v1.x - x, 2.0) + pow(v1.y - y, 2.0));
                 float s2 = sqrt(pow(v2.x - x, 2.0) + pow(v2.y - y, 2.0));
                 if (s1 < s2) {
                     vn = v1;
                 } else {
                     vn = v2;
                 }
                 vec4 color = texture2D(Texture, vn);
                 
                 gl_FragColor = color;
                 
             }

     5.三角形马赛克

             三角形马赛克和六边形马赛克原理类是,理解了六边形马赛克实现原理,三角形就是把六边形分成了六个三角形,每个三角形内的颜色值取同一个。

    //三角形马赛克的片元着色器代码:
             precision highp float;
             uniform sampler2D Texture;
             varying vec2 TextureCoordsVarying;
    
             float mosaicSize = 0.03;
    
             void main (void){
                 const float TR = 0.866025;
                 const float PI6 = 0.523599;
                 
                 float x = TextureCoordsVarying.x;
                 float y = TextureCoordsVarying.y;
                 
              
                 int wx = int(x/(1.5 * mosaicSize));
                 int wy = int(y/(TR * mosaicSize));
                 
                 vec2 v1, v2, vn;
                 
                 if (wx / 2 * 2 == wx) {
                     if (wy/2 * 2 == wy) {
                         v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy));
                         v2 = vec2(mosaicSize * 1.5 * float(wx + 1), mosaicSize * TR * float(wy + 1));
                     } else {
                         v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy + 1));
                         v2 = vec2(mosaicSize * 1.5 * float(wx + 1), mosaicSize * TR * float(wy));
                     }
                 } else {
                     if (wy/2 * 2 == wy) {
                         v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy + 1));
                         v2 = vec2(mosaicSize * 1.5 * float(wx+1), mosaicSize * TR * float(wy));
                     } else {
                         v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy));
                         v2 = vec2(mosaicSize * 1.5 * float(wx + 1), mosaicSize * TR * float(wy+1));
                     }
                 }
    
                 float s1 = sqrt(pow(v1.x - x, 2.0) + pow(v1.y - y, 2.0));
                 float s2 = sqrt(pow(v2.x - x, 2.0) + pow(v2.y - y, 2.0));
    
                 if (s1 < s2) {
                     vn = v1;
                 } else {
                     vn = v2;
                 }
                 
                 vec4 mid = texture2D(Texture, vn);
                 float a = atan((x - vn.x)/(y - vn.y));
    
                 vec2 area1 = vec2(vn.x, vn.y - mosaicSize * TR / 2.0);
                 vec2 area2 = vec2(vn.x + mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);
                 vec2 area3 = vec2(vn.x + mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);
                 vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0);
                 vec2 area5 = vec2(vn.x - mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);
                 vec2 area6 = vec2(vn.x - mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);
                 
    
                 if (a >= PI6 && a < PI6 * 3.0) {
                     vn = area1;
                 } else if (a >= PI6 * 3.0 && a < PI6 * 5.0) {
                     vn = area2;
                 } else if ((a >= PI6 * 5.0 && a <= PI6 * 6.0) || (a < -PI6 * 5.0 && a > -PI6 * 6.0)) {
                     vn = area3;
                 } else if (a < -PI6 * 3.0 && a >= -PI6 * 5.0) {
                     vn = area4;
                 } else if(a <= -PI6 && a> -PI6 * 3.0) {
                     vn = area5;
                 } else if (a > -PI6 && a < PI6) {
                     vn = area6;
                 }
                 
                 vec4 color = texture2D(Texture, vn);
                 gl_FragColor = color;
             }

    由于篇幅过长还有一部分滤镜效果见下一篇,所有滤镜效果以及加载方法等详细代码github地址:https://github.com/duzhaoquan/ImagesVideoFilters.git

  • 相关阅读:
    spring 事务管理
    snmp4j 异步获取节点信息
    snmp4j 过滤错误的节点
    国际化支持
    通过Java反射机制获取对象的方法
    jdk中有哪些包不用自动导入
    位运算符
    spring 从入门到精通 (一)
    命令行工具nslookup查域名DNS服务器
    java/php DES/CBC/PKCS5Padding加密解密算法实现过程
  • 原文地址:https://www.cnblogs.com/duzhaoquan/p/13181709.html
Copyright © 2011-2022 走看看