一些常用滤镜的实现思路
一些常用滤镜的实现思路
1.什么是颜色?
早在17世纪,颜色的本质是牛顿最早通过三棱镜的试验发现的。牛顿通过三棱镜研究对白光的折射就已经发现了白光可以分解成一系列从紫色到红色的一系列连续光谱。从而证明了白光是由不同的颜色的光线混合而成的。
“ 正确得讲,光线并不是彩色的。” --牛顿
- 颜色是人的视觉系统对可见光的感知结果,感知到的颜 色由光波的波长决定
- 视觉系统能感觉的波长范围为380~780nm。
颜色,其实本身不是一个物理意义的概念,其实是人的感知,因为彩色仅仅是存在于人的眼镜和大脑中。
可见光的光谱:400nm-700nm
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oZWq6ibt-1623408706908)(/Users/william/Library/Application Support/typora-user-images/page49image9436816.png)]
S-Cone(锥状) :短波长(B)
M-Cone :中波长(G)
L-Cone :长波长(R)
2.简单的图像分类
- Binary images (0 or 1)二值图像
- Gray images(0-255 or 8 bits/pixel)灰度图
- color images 色彩图像
- 举例:Full color images(24 bits/pixel, rgb) 真彩色图像
这张图可以看出,我们定义灰度图,需要256个灰度级,灰度级太多了会浪费内存,灰度级太少了会产生马赫带效应,因此,我们在分配图像内存的时候通常一个像素是分配3个字节(24个bit),也就是我们常说的真彩色(三通道)
图片滤镜思路 — 对顶点坐标,纹理坐标进行各种变换
几个例子
1.分屏滤镜:
分2格:
思路:判断纹理的y坐标,在纹理的(0.0, 0.5)和(0.5, 1.0)坐标填充为(0.25, 0.75)区间的内容。
vec2 uv = TextureCoords.xy;float y;if (uv.y >= 0.0 && uv.y <= 0.5) {y = uv.y + 0.25;} else {y = uv.y - 0.25;}
其余类似
2.灰度
基础知识:
亮度:亮度指的颜色的综合明亮程度,并且与颜色的色调无关。
在sRGB规范中,亮度可以被定义为红,黄,蓝三种元素的现行组合,具体的权重如下:
const highp vec3 w = vec3(0.2125, 0.7154, 0.0721);
权值向量w中的三个数值的和为1.0,因此,该向量与有效的RGB之间的点积的结果将生成位于0-1之间的亮度值。
ps:sRGB色彩空间(标准红绿蓝色彩空间)是惠普与微软于1996年一起开发的用于显示器、打印机以及因特网的一种标准RGB色彩空间。
思路:灰度滤镜的实现有很多方法可以得到灰度滤镜,这边列举了一下几种方法
- 权重算法: Gray = R * 0.3 + G * 0.59 + B * 0.11(比较逼真)
- 平均值法: Gray = (R + G + B) / 3;(比较柔和)
- 仅取绿色: Gray = G //人的眼睛对绿色比较敏感。
- 亮度替代颜色值
GPUImage:中使用的是权重提取;
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
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);gl_FragColor = vec4(vec3(luminance), 1.0);
}
由RGB到HSV的转换:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xln1euOY-1623408706912)(/Users/william/Library/Application Support/typora-user-images/image-20200724233809425.png)]
3.lookup table: 颜色查找表
目前我已知的有四种lookup 颜色查找表
1* 256 有局限,但是是无损的(rgb三个通道分开查询)
32 * 1024 选择性有损查询
256 * 256 精度损失较大
512 * 512 比较常用
通过LUT,你可以将一组RGB值输出为另一组RGB值,从而改变画面的曝光与色彩。我们可以看下一张颜色查找表长什么样,可以发现这边总共有8 * 8 = 64个格子.尺寸是512* 512 = 262,144。也就是说,一张基准图可以表示64 * 64 * 64 = 262,144种颜色。
不妨我们可以先看下其中一个格子,对应的尺寸就是64* 64, 换句话说,也就是64 * 64 = 4,096个像素构成,可以表示 64 * 64种颜色。那么为啥需要64个格子呢,原因是在真彩色颜色空间中,是由rgb三个通道组成,一个格子只能用x和y构成的二维笛卡尔坐标来表示两个颜色通道的映射关系。原则上三通道的话,就需要x,y,z构成的三维笛卡尔坐标系来表示映射关系(也就是需要一张三维体纹理)。64个格子可以理解为把第三个维度(也就是z轴)一层一层抽出来,然后铺平,模拟表示一张三维纹理。
到这里,我们就可以明白,lookup table 的原理其实就是一个颜色区间的查询过程。举个例子0-4的灰度级都对应查找表的第一个像素的颜色。最后,得到了查询表的颜色值之后,再跟原图进行mix混合,就是叠加上滤镜的效果了。具体可以看看glsl的实现代码:
const float stepDis = 1.0 / 8.0;
const float perPixel = 1.0 / 512.0;
const float halfPixel = 0.5 / 512.0;vec3 lookup(vec4 color, sampler2D lookupTexture) {float blue = color.b * 63.0;vec2 coord1;coord1.y = floor(blue / 8.0);coord1.x = floor(blue) - (coord1.y * 8.0);coord1 = coord1 * stepDis + halfPixel + (stepDis - perPixel) * color.xy;return texture2D(lookupTexture, coord1).rgb;
}
4.腐蚀/膨胀
https://www.bilibili.com/video/av15515818/
5.曝光:
快门打开时,光线透过镜头,经过光圈,进入暗室,最后照在成像材料上,这个过程称为曝光。
增加曝光,就是进入相加的光线更多了,可以通过把颜色值乘以一个2的指数次方来实现。
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif // GL_FRAGMENT_PRECISION_HIGHuniform sampler2D inputImageTexture;
varying vec2 textureCoord;
const float intensity = 1.2;void main() {vec4 color = texture2D(inputImageTexture, textureCoord);color.rgb *= pow(2.0, intensity);gl_FragColor = color;
}
6.噪声
基础知识
随机:
y = fract(sin(x)*1.0)
y = fract(sin(x)*2.);
y = fract(sin(x)*4.);
sin(x)值域为-1.0
到 1.0
,这里实际是指模1,返回0.0
到 1.0
间的正值,我们可以用这种效果通过把正弦函数打散成小片段来得到一些伪随机数。
y = fract(sin(x)*43758.5453123);
glsl业界里面求随机数的函数
float random (vec2 st) {return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
}
具体的数字可能是出自一篇论文
举个例子:
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif // GL_FRAGMENT_PRECISION_HIGHvarying vec2 textureCoord;float random (vec2 st) {return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
}void main() {float rnd = random( textureCoord );gl_FragColor = vec4(rnd);
}
一些常用滤镜的实现思路相关推荐
- Google Maps API 进级: GoogleMaps常用事件及应用思路1
转自:http://hi.baidu.com/xfm_zhr/blog/item/8c1790517e87ea888d54302a.html 1. GoogleMaps常用事件及应用思路 ...
- 常用不等式及证明思路总结(一)
文章目录 写在前面 Jensen不等式 证明思路 均值不等式 应用 例题1 Cauchy不等式 证明思路 方法一 方法二 方法三 Schwartz不等式 证明思路 方法一 方法二 方法三 应用 证明不 ...
- 数据分析常用6种分析思路
文章发布于公号[数智物语] (ID:decision_engine),关注公号不错过每一篇干货. 转自 | CrossHands 作者 | Ahong 作为数据分析师,你是否常因为缺乏分析思路,而被以 ...
- 数据分析师常用的十种数据分析思路,你都知道吗?
十大数据分析方法,让你了解如何做好数据分析. 随着互联网的发展.业务逻辑越来越复杂,数据的分析也就变的越来越重要.对数据的分析可有效避免逻辑的混乱,防止在繁杂的业务理解上逻辑不清.判断错误. 道家曾强 ...
- 数据分析师常用的十种数据分析思路
道家曾强调四个字,叫"道.法.术.器". 层次分别为: "器"是指物品或工具,在数据分析领域指的就是数据分析的产品或工具,"工欲善其事,必先利其器&q ...
- ffmpeg常用滤镜命令
FFmpeg添加了很多滤镜,查看哪些滤镜有效可用命令: # ./ffmpeg -filters. 1. FFmpeg滤镜文档 更多的信息和每个滤镜的使用示例可查看FFmpeg的滤镜文档: h ...
- 常用处理海量数据的思路和方法
一.Bloom filter(布隆过滤器) 适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集 基本原理及要点: 对于原理来说很简单,(位数组+k个独立hash函数),将hash函数对应的 ...
- 常用的排序算法思路及代码
原文地址:那些年,让我面试头大的几个排序算法,今天终于搞懂了! 最近带广告的博客总是被封,于是copy一下备份,如有侵权,还请告知,必定删除! 快速排序 介绍: 快速排序(Quicksort)是对冒泡 ...
- pm2显示查询sql_作为PM液态SQL的技术贡献
pm2显示查询sql 问题 (The Problem) My startup - One - is a digital challenger bank for the middle class, he ...
最新文章
- [C# Control] 仿RAR式进度条 (RarProgressBar)
- C#性能优化:延迟初始化LazyT
- 【C语言】创建一个函数,利用该函数将字符串中的小写字母转换为大写字母
- JavaScript-Load-Image
- Node.app让Nodejs平台在iOS和OS X系统上奔跑
- Python使用freetype渲染显示阿拉伯语
- 揭秘微信身份证背后的高科技——人脸识别技术
- 项目上线流程-实时Flink
- 纯CSS实现点击一个元素,背景颜色切换
- flutter能开发游戏吗_Flutter Flame游戏开发上手(1)
- 2.4 混合策略和混合策略纳什均衡
- Spring Boot 微信-网页授权获取用户信息
- python 编程入门学习基础
- 计算机老是卡顿怎么解决,电脑反应太慢怎么处理_电脑卡顿什么原因-win7之家
- 偶感 - 写在细雨朦胧的早晨
- C#,打印漂亮杨辉三角形(帕斯卡三角形)的源代码
- x32dbg、x64dbg逆向微信发送信息
- mysql性能优化 洪斌_mysql explain分析
- 中国移动Wlan手机客户端系统用户体验设计
- 爬取某直播网站首页小姐姐的照骗