此博客只为记录滤镜的算法,所以修改的只是片元着色器代码
注:具体代码请查看上一篇博客:https://blog.csdn.net/weixin_40918107/article/details/107748865

1. 准备工作

  • 创建顶点着色器和片元着色器
  • 加载着色器,并链接
  • 创建图层和上下文
  • 清空缓冲区,并设置渲染缓冲区与帧缓冲区
  • 开始绘制

2.滤镜的实现

图片无滤镜正常显示的顶点着色器和片元着色器代码。
注:以下代码中的中文注释在复制代码时,请删除,否则会有未知的错误
顶点着色器:

//顶点坐标
attribute vec4 Position;
//纹理坐标
attribute vec2 TextureCoords;
//需要传入片元着色器的纹理坐标
varying vec2 TextureCoordsVarying;void main (void) {gl_Position = Position;TextureCoordsVarying = TextureCoords;
}

片元着色器:

//声明高精度float
precision highp float;
//纹理
uniform sampler2D Texture;
//纹理坐标
varying vec2 TextureCoordsVarying;void main (void) {vec4 mask = texture2D(Texture, TextureCoordsVarying);gl_FragColor = vec4(mask.rgb, 1.0);
}

2.1灰度滤镜

灰度滤镜实现的方案:

  • 浮点算法:Gray=R0.3+G0.59+B*0.11
  • 整数⽅法:Gray=(R30+G59+B*11)/100
  • 移位⽅法:Gray =(R76+G151+B*28)>>8;
  • 平均值法:Gray=(R+G+B)/3;
  • 只取绿色:Gray=G;

一般使用第一个方案:浮点算法。
实现灰度滤镜只需要修改片元着色器即可,顶点着色器不变。

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//变换因子,即上方的浮点算法,此值取自GPUImage源码
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);void main (void) {//获取对于纹理坐标下的颜⾊值vec4 mask = texture2D(Texture, TextureCoordsVarying);//将颜⾊mask 与 变换因⼦点乘得到灰度值.由向量转变成标量float luminance = dot(mask.rgb, W);//vec4、vec3是内建函数,vec3是将颜色值RGB都设置成luminancegl_FragColor = vec4(vec3(luminance), 1.0);
}

2.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) 内建函数,返回⼩于/等于X的最⼤整数值,向下取整// 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;
}

2.3六边形马赛克滤镜

六边形马赛克效果就是让⼀张图⽚,分割成由六边形组成,让每
个六边形中的颜⾊相同(直接取六边形中⼼点像素RGB较⽅便,我们
这⾥采⽤的就是这种⽅法),将它进⾏分割,取每个六边形的中⼼点画出⼀个矩阵,如下

图片中的所有的黄点就是六边形的中心点,每个六边形的颜色就取其中心点的颜色。
我们把上图中四个矩形单独拿出进行下一步分析,如下图:

思考:在左上角的长方形中,那个褐色的小点显示的颜色应该显示什么颜色呢?

答案显而易见应该与d2点的颜色一致,这个点距离d2这个中心点比较近,所以是d2六边形上点。

那么在片元着色器上点的颜色的值就应该与该点距离最近的六边形中心点的颜色一致。

在上图中我们还可以分析得到左上角的长方形只有(0,0)和(1,1)这两个点是六边形的中心点,左下角的长方形只有(0,1)和(1,0)这两个点是六边形的中心点。

并且在长方形线的的样式只有“\”和 “/”这两种。

并且由六边形的中心点组成的长方形有一个特点就是宽高比是3:√3,那么假定我们设定的矩阵⽐例为 3LEN : √3LEN ,那么屏幕上的任意点(x, y)所对应的矩阵坐标为(int(x/(3LEN)), int(y/
(√3
LEN)))。那么这四个点的坐标为:

片元着色器代码:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//六边形的边⻓
const float mosaicSize = 0.03;void main (void)
{float length = mosaicSize;//sqrt(3)/2;float TR = 0.866025;float TB = 1.5;//纹理坐标:(0,0)(0,1)(1,0)(1,1)float x = TextureCoordsVarying.x;float y = TextureCoordsVarying.y;//wx,wy -> 表示纹理坐标在所对应的矩阵坐标为int wx = int(x / TB / length);int wy = int(y / TR / length);vec2 v1, v2, vn;//判断wx,wy在矩形中的上半部还是下半部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 中gl_FragColor = color;}

3.4 三角形马赛克滤镜

三角形马赛克滤镜是在六边形滤镜的基础上,将六边形分成6个相同的三角形。
这样我们只需要再进一步的分析,我们需要根据当前点与六边形的中心点之间的角度来确定属于哪个三角,然后再获取三角形的中心点的颜色进行赋值。

片元着色的代码:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//六边形的边⻓
const float mosaicSize = 0.03;void main (void)
{float length = mosaicSize;//sqrt(3)/2;float TR = 0.866025;float TB = 1.5;//纹理坐标:(0,0)(0,1)(1,0)(1,1)float x = TextureCoordsVarying.x;float y = TextureCoordsVarying.y;//wx,wy -> 表示纹理坐标在所对应的矩阵坐标为int wx = int(x / TB / length);int wy = int(y / TR / length);vec2 v1, v2, vn;//判断wx,wy在矩形中的上半部还是下半部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 mid = texture2D(Texture, vn);//获取a与纹理中⼼的⻆度.//atan算出的范围是-180⾄180度,对应的数值是-PI⾄PIfloat 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);//判断夹⻆a 属于哪个三⻆形.则获取哪个三⻆形的中⼼点坐标if (a >= PI6 && a < PI6 * 3.0) {//[30,90]vn = area1;} else if (a >= PI6 * 3.0 && a < PI6 * 5.0) {//[90,150]vn = area2;} else if ((a >= PI6 * 5.0 && a <= PI6 * 6.0)|| (a<-PI6 * 5.0 && a>-PI6*6.0)) {//[150,180],[-150,-180]vn = area3;} else if (a < -PI6 * 3.0 && a >= -PI6 * 5.0) {//[-90,-150]vn = area4;} else if(a <= -PI6 && a> -PI6 * 3.0) {//[-30,-90]vn = area5;} else if (a > -PI6 && a < PI6){//[-30,30]vn = area6;}//获取对应三⻆形中⼼的颜⾊值vec4 color = texture2D(Texture, vn);//将颜⾊值填充到⽚元着⾊器内置变量gl_FragColorgl_FragColor = color;}

OpenGLSL初探(六)使用GLSL实现滤镜之灰度滤镜、正方形马赛克滤镜、六边形马赛克滤镜和三角形马赛克滤镜相关推荐

  1. python卡通滤镜_纯Python综合图像处理小工具(3)10种滤镜算法

    滤镜处理是图像处理中一种非常常见的方法.比如photoshop中的滤镜效果,除了自带的滤镜,还扩展了很多第三方的滤镜效果插件,可以对图像做丰富多样的变换:很多手机app实现了实时滤镜功能,最有名的当属 ...

  2. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——2.2 来一份LOMO滤镜

    Github项目地址 回到目录 了解了滤镜的基本知识以后,我们就可以试着来做我们的第一个滤镜了 虽然之前做过一个灰度滤镜,但是是采用直接修改片元着色器代码的方式,非常"不优雅",所 ...

  3. 100天精通Python丨黑科技篇 —— 20、Python 修图(滤镜、灰度、裁剪、视觉处理、图像分割、特征提取)

    文章目录 一.PIL 常规修图操作 1. 读取图片 2. 图片缩放 3. 图片旋转 4. 图片裁剪 5. 图片滤镜 二.OpenCV 图像处理.视频处理.对象识别 三.scikit-image 视觉算 ...

  4. linux图片添加滤镜,分享|在 Ubuntu 中给你的照片加上 Instagram 风格的滤镜程序

    拿起你的自拍杆跟我来. XnRetro 照片编辑器 XnRetro 是一个可以让你快速给你照片添加"类 Instagram"效果的程序. 你肯定知道我说的这些效果:划痕.噪点.相框 ...

  5. OpenGL ES之GLSL实现仿抖音“灰度滤镜”和“颠倒滤镜”效果

    无滤镜 "无滤镜"效果的实现准备工作的代码与"无分屏滤镜"中的实现逻辑和流程一致,只需要修改相应的底部item数组及对应的着色器名称等,这里不再说明这部分内容, ...

  6. OpenGL ES 入门之旅--灰度,旋涡,马赛克滤镜

    前情提要 这篇滤镜效果的实现是在上一篇分屏滤镜的基础上来进行实现的,同样的前提是可以利用GLSL加载一张正常的图片. 详情请参考上一篇OpenGL ES 入门之旅--分屏滤镜 下面步入这篇的正题: 灰 ...

  7. iOS开发之GPUImage研究总结,视频、图片等添加滤镜(转载)

    转载自:https://blog.csdn.net/Xoxo_x/article/details/52695032(非常感谢!) Part one: 关于GPUImage 这里直接引用官方描述: Th ...

  8. FireFox火狐浏览器与IE兼容问题 - 透明滤镜 DIV滚动条

    问题一:最简单的鼠标移过手变型的css要改了 cursor:pointer;/*FireFox(火狐)不支持cursor:hand*/ dw8下面自动出来的也没有hand这个属性了,标准的是point ...

  9. android camera 实时滤镜,【Camera】Android平台Camera实时滤镜实现方法

    Android+JNI+OpenGL开发自己的美图秀秀 2016-01-18 16:39 阅读(5116) 评论(19) Android平台Camera实时滤镜实现方法探讨(十一)--实时美颜滤镜 2 ...

最新文章

  1. python增量赋值是什么_python学习记录20190122_增量赋值
  2. Ajax框架及原理分析--视频
  3. abap 给用户分配事物代码权限_【第五篇】SAP ABAP7.50 之用户接口
  4. js:自动亮起100盏灯
  5. MySQL存储过程+游标+触发器
  6. 《测绘综合能力》——地籍测绘
  7. (含代码)基于51单片机电子密码锁设计
  8. 【web前端性能优化】12.css sprite(图片精灵)-雪碧图实现原理
  9. Axure 下载教程
  10. c++哈利波特编程代码
  11. 命令行方式实现QQ自动登录
  12. 第十三题:中国古代数学家张丘建在他的《算经》中提出了一个著名的“百钱百鸡问题”:一只公鸡值5钱,一只母鸡值3钱,三只小鸡值1钱,现在要用百钱买百鸡,请问公鸡、母鸡、小鸡各多少只?
  13. DCS任务编辑器文件无法正常加载,一直停在‘正在读取。。’
  14. Professional C# 6 and .NET Core 1.0 - Chapter 41 ASP.NET MVC
  15. leaflet+turf截取线上线段(leaflet篇.36)
  16. Python课堂程序之猜单词游戏
  17. Feelings on Life
  18. gitlab ci ERROR: Uploading artifacts to coordinator... too large archive
  19. 阅文集团的盛世危机才刚刚开始
  20. 【uboot】uboot环境下usb命令

热门文章

  1. C++学习之Pair
  2. Python 基础之字符串操作,函数及格式化format
  3. 手机安装python jam有什么影响_oppo 手机上运行 appium + python 遇到的坑
  4. 449php,【19/11/09】基于官版Win10_Pro_1909_x64_18363.449 无APPS适度精简版极致精简版
  5. 【单片机俱乐部】基于单片机的路灯控制设计【实物视频讲解】
  6. ThinkPHP代码生成器快速开发框架:ThinkPHP+VUE+APIdoc+Restful+Oauth2.0+代码生成器+系统基础功能(用户管理、菜单管理、角色管理、权限管理、字典管理、部门管理)
  7. JS设置CSS样式。
  8. 图书管理系统(Mysql+Java)心得
  9. 思维导图MindManager
  10. 招商网上银行接口(自己的网上银行)