GLSL 参考GIMP源码实现色彩平衡调节
色彩平衡
修图工具中的色彩平衡一般用来根据亮度等级调整图片中颜色的偏色,调整偏色涉及到加色原理和减色原理
其实我们通过三原色加色原理的图片就可以知道,红色的对比色是青色,蓝色的对比色是黄色,绿色的对比色是品红,这样说可能不太直观,其实我们只要试一下,把图片的r值整体提高,图片会偏红(废话),降低r值,图片会偏青色,g通道和b通道同理,或者,我们用白色(255, 255, 255)减去红色(255, 0, 0),,得到了(0, 255, 255)青色,实际上红色就是青色的反相,在色相环也是正对面的颜色。
为了对三个亮度进行不同程度的偏色调整,我们需要拿到一个颜色每个通道的值对应的三个亮度的权重,举个例子,一个r值为127,那么这个值的阴影调整的权重就应该比较低,中亮调整的权重应该比较高,高亮调整的权重应该比较低,那么我调整中亮的红黄拉杆的时候,对这个颜色的影响是比较大的,如果这个r值是高亮部分的(比如250),那么调整中亮的红黄拉杆对这个颜色的影响就很小(实际上是0),调整高亮的红黄拉杆影响就比较大。
可以看到,调节高亮拉杆对图片影响是比较大的,说明这幅图中r值比较高的像素较多,但是有的区域无论是调整高亮的拉杆还是调整中亮的拉杆都会被影响,这是因为三个亮度的权重并不是你一我零,色彩平衡的调整并不是把像素的值严格按三个等级区分开进行调整,只是说调整的权重有高有低
这个是接下来会讲到的权重的映射,x轴为某个通道的值,红绿蓝三种颜色分别代表阴影,中亮,高亮的权重的变化曲线
GIMP计算权重的代码
static void
color_balance_transfer_init (void)
{
gint i;
for (i = 0; i < 256; i++)
{
static const gdouble a = 64, b = 85, scale = 1.785;
gdouble low = CLAMP ((i - b) / -a + .5, 0, 1) * scale;
gdouble mid = CLAMP ((i - b) / a + .5, 0, 1) *
CLAMP ((i + b - 255) / -a + .5, 0, 1) * scale;
shadows[i] = low;
midtones[i] = mid;
highlights[255 - i] = low;
}
}
这段代码是GIMP里生成三种亮度等级的权重映射,实际上映射出来的权重我们也可以用GIMP的公式单独计算出来
GLSL计算权重的代码
vec3 transfer(float value)
{
const float a = 64.0, b = 85.0, scale = 1.785;
vec3 result;
float i = value * 255.0;
float shadows = clamp ((i - b) / -a + 0.5, 0.0, 1.0) * scale;
float midtones = clamp ((i - b) / a + 0.5, 0.0, 1.0) * clamp ((i + b - 255.0) / -a + .5, 0.0, 1.0) * scale;
float highlights = clamp (((255.0 - i) - b) / -a + 0.5, 0.0, 1.0) * scale;
result.r = shadows;
result.g = midtones;
result.b = highlights;
return result;
}
该映射的曲线
红色曲线为阴影的权重映射
绿色曲线为中亮的权重映射
蓝色曲线为高亮的权重映射
计算的时候将每个通道的值加上这个通道的三种亮度的权重乘上对应的拉杆值就行了
最后如果要保持亮度的话就调用一下rgb与hsl的转换函数就好,拉杆的取值范围是[-100, 100]
代码:
precision mediump float;
varying mediump vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform float cyan_red_shadow;
uniform float cyan_red_midtones;
uniform float cyan_red_highlights;
uniform float magenta_green_shadow;
uniform float magenta_green_midtones;
uniform float magenta_green_highlights;
uniform float yellow_blue_shadow;
uniform float yellow_blue_midtones;
uniform float yellow_blue_highlights;
vec3 transfer(float value)
{
const float a = 64.0, b = 85.0, scale = 1.785;
vec3 result;
float i = value * 255.0;
float shadows = clamp ((i - b) / -a + 0.5, 0.0, 1.0) * scale;
float midtones = clamp ((i - b) / a + 0.5, 0.0, 1.0) * clamp ((i + b - 255.0) / -a + .5, 0.0, 1.0) * scale;
float highlights = clamp (((255.0 - i) - b) / -a + 0.5, 0.0, 1.0) * scale;
result.r = shadows;
result.g = midtones;
result.b = highlights;
return result;
}
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转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 main()
{
vec4 base = texture2D(inputImageTexture, textureCoordinate);
vec3 hsl = rgb2hsl(base.rgb);
vec3 weight_r = transfer(base.r);
vec3 weight_g = transfer(base.g);
vec3 weight_b = transfer(base.b);
vec3 color = vec3(base.rgb * 255.0);
color.r += cyan_red_shadow * weight_r.r;
color.r += cyan_red_midtones * weight_r.g;
color.r += cyan_red_highlights * weight_r.b;
color.g += magenta_green_shadow * weight_g.r;
color.g += magenta_green_midtones * weight_g.g;
color.g += magenta_green_highlights * weight_g.b;
color.b += yellow_blue_shadow * weight_b.r;
color.b += yellow_blue_midtones * weight_b.g;
color.b += yellow_blue_highlights * weight_b.b;
color.r = clamp(color.r, 0.0, 255.0);
color.g = clamp(color.g, 0.0, 255.0);
color.b = clamp(color.b, 0.0, 255.0);
vec3 hsl2 = rgb2hsl(color / 255.0);
hsl2.z = hsl.z;
gl_FragColor=vec4(hsl2rgb(hsl2), base.a);
}
GLSL 参考GIMP源码实现色彩平衡调节的更多相关文章
- list源码4(参考STL源码--侯捷):transfer、splice、merge、reverse、sort
list源码1(参考STL源码--侯捷):list节点.迭代器.数据结构 list源码2(参考STL源码--侯捷):constructor.push_back.insert list源码3(参考STL ...
- list源码1(参考STL源码--侯捷):list节点、迭代器、数据结构
list源码1(参考STL源码--侯捷):list节点.迭代器.数据结构 list源码2(参考STL源码--侯捷):constructor.push_back.insert list源码3(参考STL ...
- list源码2(参考STL源码--侯捷):constructor、push_back、insert
list源码1(参考STL源码--侯捷):list节点.迭代器.数据结构 list源码2(参考STL源码--侯捷):constructor.push_back.insert list源码3(参考STL ...
- list源码3(参考STL源码--侯捷):push_front、push_back、erase、pop_front、pop_back、clear、remove、unique
list源码1(参考STL源码--侯捷):list节点.迭代器.数据结构 list源码2(参考STL源码--侯捷):constructor.push_back.insert list源码3(参考STL ...
- vector源码3(参考STL源码--侯捷):pop_back、erase、clear、insert
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷):空间分配.push_back vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 v ...
- vector源码(参考STL源码--侯捷):空间分配导致迭代器失效
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- vector源码2(参考STL源码--侯捷):空间分配、push_back
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- vector源码1(参考STL源码--侯捷):源码
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- 转换器5:参考Python源码,实现Php代码转Ast并直接运行
前两个周末写了<手写PHP转Python编译器>的词法,语法分析部分,上个周末卡文了. 访问器部分写了两次都不满意,没办法,只好停下来,参考一下Python的实现.我实现的部分正好和Pyt ...
随机推荐
- Java日志框架SLF4J和log4j以及logback的联系和区别
1.SLF4J(Simple logging Facade for Java) 意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接 ...
- java架构师视频教程 内含activemq+jvm+netty+dubbo
目录: 架构师视频教程包含activemq jvm netty dubbo 0分布式项目实战所有视频(分布式项目视频)互联网架构师第二期-视频部分互联网架构师第二期-资料部分1.Netty快速入门教程 ...
- 阿里yum源与华为yum源的配置
如何使用华为云提供的CentOS镜像源(x86_64)? 更新时间: 2019/08/16 11:17 查看PDF 分享 微博 分享文档到微博 微信 扫码分享文档 ...
- android 之图片异步加载
一.概述 本文来自"慕课网" 的学习,只是对代码做一下分析 图片异步加载有2种方式: (多线程/线程池) 或者 用其实AsyncTask , 其实AsyncTask底层也是用的多 ...
- ios打包时候提示三方文件库错误,整理下解决的思路
这一短时间一直在打包APP上线,今天突然打包的时候碰到的头文件找不到 一开始我以为是路径的问题,检查了targets---Build settings----search Paths----heade ...
- SQL手工注入基础篇
0.前言 本篇博文是对SQL手工注入进行基础知识的讲解,更多进阶知识请参考进阶篇(咕咕),文中有误之处,还请各位师傅指出来.学习本篇之前,请先确保以及掌握了以下知识: 基本的SQL语句 HTTP的GE ...
- react navigation goBack()返回到任意页面(不集成redux) 二
实现思路: A -- > B (获取A的key值,传至C)-- >C(获取B传来的A页面key值,传至D) -- >D(获取C传来的A页面key值&C页面的key值,传至下一 ...
- SpringAop实现公共字段填充
一.说明 项目中经常会有一些放在缓存中的公共字段需要进行填充,我们知道mybatis-plus很方便地可以实现公共字段填充.在这里我定义了一个字段填充的注解,当我们需要进行数据填充的时候只要在方法上打 ...
- Linux服务器MySQL安装
Linux服务器MySQL安装 1. MySQL官网下载如图: 2. 安装MySQL [root@iZ2zebb0428roermd00462Z /]# rpm -ivh https://dev.my ...
- TCGA各种肿瘤数据的20多种不同玩法/挖掘方法
肿瘤基因组图谱 (The Cancer Genome Atlas,TCGA) 计划是由美国国家癌症研究院(National Cancer Institute,NCI)和美国国家人类基因组研究所(Nat ...