美文网首页
OpenGL ES 灰度、马赛克滤镜

OpenGL ES 灰度、马赛克滤镜

作者: 张墩墩 | 来源:发表于2020-08-15 19:40 被阅读0次
未命名.gif
demo

1、灰度滤镜

实现原理

  • 灰度滤镜主要是让RGB值保持一个平衡并填充
  • 只保留一个亮度值--绿色。绿色的亮度最显眼,绿色越深肉眼观察到越暗淡,这是人的生理现象。

灰度滤镜5中算法

  • 权值算法
    • 浮点算法:Gray = R*0.3 + G*0.59 + B*0.11 (权重和为1)
    • 整数算法:Gray = R*30 + G*59 + B*11)/100(权重总和为100)
    • 移位算法:Gray = (R*76 + G*151 + B*28)>>8(权重总和为255)
  • 平均值:Gray = (R+G+B)/3
  • 仅取绿色: Gray = G

案例:在片元着色器中采用修改纹理颜色实现灰度滤镜

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

//RGB颜色权重分配,值取自GPUImage
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);

void main (void) {
    //获取纹素(对应坐标的像素点颜色)
    vec4 mask = texture2D(Texture, TextureCoordsVarying);

    //将纹素颜色与权重分配值相乘的到灰度值
    float luminance = dot(mask.rgb, W);
   //将灰度值转换为(luminance,luminance,luminance,mask.a)。并填充到像素中
    gl_FragColor = vec4(vec3(luminance), 1.0);
}
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main (void) {
    //获取纹素(对应坐标的像素点颜色)
    vec4 mask = texture2D(Texture, TextureCoordsVarying);

    //仅取绿色
    float luminance = mask.g;
   //将灰度值转换为(luminance,luminance,luminance,mask.a)。并填充到像素中
    gl_FragColor = vec4(vec3(luminance), 1.0);
}

2、正方形马赛克

实现原理:把图片的一个相当大小的区域用同一个颜色值来表示,可以认为是大规模的降低图像的分辨率,从而让图像的一些细节隐藏起来。

正方形马赛克
片元着色器中实现
precision 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的整数
   // 计算实际纹理图像中马赛克坐标
    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 = color;
}

3、六边形马赛克

实现原理:将一张图分割成六边形组成,让每个六边形中颜色相同(直接去六边形中心点像素RGB值)图2

图2
计算矩形阵的长宽比值TB、TR(TB:TR = 3:√3) 矩形阵长宽比TB:TR
根据纹理坐标(x,y)计算对应在矩形阵中坐标(wx,xy)
计算像素点对应在矩形阵中坐标
根据行列的奇偶情况计算对应中心点的纹理坐标(V1,V2)
以相邻接触的正六边形的中心点构成矩形阵来计算中心点的纹理坐标图3
图3
偶行偶列:左上(0,0),右下(1,1)
奇行奇列:左上(0,0),右下(1,1)
偶行奇列:左下(0,1),右上(1,0)
奇行偶列:左下(0,1),右上(1,0)
根据图形最终顶点的取值可分为两种情况左上(0,0),右下(1,1) 和左下(0,1),右上(1,0)

中心点顶点(V1、V2)的纹理坐标计算方式

中心点纹理坐标计算

计算矩形阵中像素点距离两个中心点的距离,距离哪个顶点近取哪个顶点的颜色值

像素点距离中心点距离
s1 = √((v1.x-x)² + (v1.y-y)²)
s2 = √((v2.x-x)² + (v2.y-y)²)

片元着色器中代码实现

六边形马赛克
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

const float mosaicSize = 0.03;//马赛克长度

void main (void)
{
    float length = mosaicSize;//六边形边长(小矩阵长度)
    
    float TR = 0.866025;//TB:TR = 3:√3
    float TB = 1.5;
    
   //纹理坐标
    float x = TextureCoordsVarying.x;
    float y = TextureCoordsVarying.y;
    
   //根据纹理坐标转换至矩形阵中坐标
  // wx  = x/矩形阵长,矩形阵长 = TB * lenght
  // wy = y/矩形阵宽,矩形阵宽 = TR * lenght
    int wx = int(x / TB / length);
    int wy = int(y / TR / length);

  //V1,V2 矩形阵对角的顶点坐标(六边形的中心点)
    vec2 v1, v2, vn;
   //判断wx的奇偶性
    if (wx/2 * 2 == wx) {//wx为偶数
        if (wy/2 * 2 == wy) {//wy为偶数
            //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 {
            // 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 {//wx为奇数
        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;
    
}

4、三角形马赛克

实现原理

  • 三角形马赛克是由六边形马赛克演变而来,将正六边形6等分得到需要的三角形(正三角形将360度分成6份)图5

    图5
  • 设置选取每个三角形中点作为三角形内颜色填充的像素点图6
    这里为了方便计算三角形内的点x值取三角形高度线上的点。y值取高度的一半。

    图6
  • 计算纹理坐标与中心点的夹角,判断该点所属的三角形区域图7
    点A(x,y),中心点V(Vx,Vy)夹角 𝞪 = atan((x - Vx)/(y - Vy))
    atan的值域范围从 (-π/2,π/2) --- (-1.57079 到 1.57079)

图7

PI6 = 0.523599 = PI/6
将六边形内角360度照图8划分成30度的区域。方便计算对比像素点所属三角形

图8 三角形马赛克

片元着色器实现代码

     //纹理坐标(x,y)与六边形中心点夹角
      float a = atan((x - vn.x)/(y - vn.y));

      // TR = 0.866025 = cos30 = √3/2

      //按照图6三角形颜色填充像素点的选取,计算填充的像素点坐标
     //对应图6的第1点
       vec2 area1 = vec2(vn.x, vn.y - mosaicSize * TR / 2.0);

      //对应图6的第2点
       vec2 area2 = vec2(vn.x + mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);

       //对应图6的第3点
       vec2 area3 = vec2(vn.x + mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);

       //对应图6的第4点
       vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0);

      //对应图6的第5点
       vec2 area5 = vec2(vn.x - mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);

        //对应图6的第6点
       vec2 area6 = vec2(vn.x - mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);
     
     const float PI6 = 0.523599;
     // PI6 = 0.523599  =  PI/6
      //根据角度判读纹理坐标(x,y)属于哪个三角形中
       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);

相关文章

网友评论

      本文标题:OpenGL ES 灰度、马赛克滤镜

      本文链接:https://www.haomeiwen.com/subject/dtcidktx.html