
GPUImageColorBlendFilter代码全解析
GPUImageColorBlendFilter 是基于GPUImage框架的Android端双输入颜色混合滤镜,核心通过GLSL(OpenGL Shading Language)片段着色器实现像素级颜色混合逻辑,可将两张纹理(基础纹理/叠加纹理)按"保留基础纹理亮度、融合叠加纹理色彩"的规则混合,是移动端图像/视频滤镜开发中常用的色彩融合组件。
代码逐行注释与分段解析
1 版权与许可声明(1-13行)
这是开源项目的标准版权声明,定义了代码的使用、分发规则,遵循Apache License 2.0开源协议。
java
/*
* Copyright (C) 2018 CyberAgent, Inc. // 版权归属:2018年CyberAgent(日本赛博特工公司)
*
* Licensed under the Apache License, Version 2.0 (the "License"); // 代码遵循Apache 2.0开源许可证
* you may not use this file except in compliance with the License. // 使用代码必须遵守许可证条款
* You may obtain a copy of the License at // 许可证文本的获取地址提示
*
* http://www.apache.org/licenses/LICENSE-2.0 // Apache 2.0许可证官方地址
*
* Unless required by applicable law or agreed to in writing, software // 除非法律强制或书面约定
* distributed under the License is distributed on an "AS IS" BASIS, // 软件按"原样"分发,无任何担保
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // 不提供明示/默示的质量担保
* See the License for the specific language governing permissions and // 许可证中明确了权限和限制的
* limitations under the License. // 具体法律条款
*/
2 包导入(15行)
java
package jp.co.cyberagent.android.gpuimage.filter; // 声明类所属包:GPUImage框架的滤镜模块
GPUImage框架的所有滤镜类均归属于该包,便于统一管理和引用,也是框架内类之间依赖的基础。
3 类定义(17行)
java
public class GPUImageColorBlendFilter extends GPUImageTwoInputFilter { // 定义公开的颜色混合滤镜类,继承双输入滤镜基类
GPUImageColorBlendFilter:类名语义为"颜色混合滤镜",符合GPUImage框架的命名规范;extends GPUImageTwoInputFilter:继承双输入滤镜基类,该基类封装了"双纹理输入"的核心逻辑(如纹理坐标传递、双纹理绑定、着色器程序编译等),子类仅需实现自定义的混合着色器即可。
4 核心:片段着色器字符串(18-60行)
GLSL片段着色器是滤镜的核心,负责逐像素处理颜色混合逻辑,以下是逐行注释+功能解析:
java
public static final String COLOR_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + // 接收顶点着色器传递的「基础纹理坐标」(高精度二维向量,对应第一张输入图)
" varying highp vec2 textureCoordinate2;\n" + // 接收顶点着色器传递的「叠加纹理坐标」(对应第二张输入图)
" \n" +
" uniform sampler2D inputImageTexture;\n" + // 基础纹理采样器(统一变量,关联第一张输入纹理)
" uniform sampler2D inputImageTexture2;\n" + // 叠加纹理采样器(统一变量,关联第二张输入纹理)
" \n" +
" highp float lum(lowp vec3 c) {\n" + // 定义亮度计算函数:入参为低精度RGB颜色向量,返回高精度亮度值
" return dot(c, vec3(0.3, 0.59, 0.11));\n" + // 亮度公式:RGB分量分别乘以人眼感知权重(0.3红/0.59绿/0.11蓝),点积求和
" }\n" +
" \n" +
" lowp vec3 clipcolor(lowp vec3 c) {\n" + // 定义颜色裁剪函数:将RGB值限制在[0,1]范围,避免颜色溢出
" highp float l = lum(c);\n" + // 计算当前颜色的亮度值
" lowp float n = min(min(c.r, c.g), c.b);\n" + // 取RGB分量的最小值(判断是否低于0)
" lowp float x = max(max(c.r, c.g), c.b);\n" + // 取RGB分量的最大值(判断是否高于1)
" \n" +
" if (n < 0.0) {\n" + // 若最小值<0(颜色溢出下限)
" c.r = l + ((c.r - l) * l) / (l - n);\n" + // 基于亮度调整红色分量,拉回有效范围
" c.g = l + ((c.g - l) * l) / (l - n);\n" + // 调整绿色分量(逻辑同上)
" c.b = l + ((c.b - l) * l) / (l - n);\n" + // 调整蓝色分量(逻辑同上)
" }\n" +
" if (x > 1.0) {\n" + // 若最大值>1(颜色溢出上限)
" c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\n" + // 基于亮度和上限1.0调整红色分量
" c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\n" + // 调整绿色分量(逻辑同上)
" c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\n" + // 调整蓝色分量(逻辑同上)
" }\n" +
" \n" +
" return c;\n" + // 返回裁剪后的RGB颜色
" }\n" +
"\n" +
" lowp vec3 setlum(lowp vec3 c, highp float l) {\n" + // 定义亮度调整函数:将颜色c的亮度改为指定值l
" highp float d = l - lum(c);\n" + // 计算目标亮度与当前亮度的差值
" c = c + vec3(d);\n" + // 给RGB分量统一加差值,初步调整亮度
" return clipcolor(c);\n" + // 裁剪调整后的颜色,避免溢出
" }\n" +
" \n" +
" void main()\n" + // 片段着色器主函数(逐像素执行)
" {\n" +
" highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\n" + // 采样基础纹理的像素颜色(RGBA)
" highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\n" + // 采样叠加纹理的像素颜色(RGBA)
"\n" +
" gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a, baseColor.a);\n" + // 计算最终像素颜色:基础色×(1-叠加色透明度) + 亮度匹配后的叠加色×叠加色透明度;Alpha通道沿用基础色
" }";
着色器核心函数拆解:
| 函数名 | 核心作用 |
|---|---|
lum |
按人眼视觉权重计算颜色亮度,保证亮度值符合人眼感知(行业通用YUV亮度公式) |
clipcolor |
裁剪溢出的颜色值,避免出现过暗/过亮的失真像素,同时保留原亮度 |
setlum |
调整颜色亮度至指定值,是"保留叠加色色彩、匹配基础色亮度"的核心 |
main |
最终混合逻辑:按叠加色透明度,融合基础色与"亮度匹配后的叠加色" |
5 构造函数(62-64行)
java
public GPUImageColorBlendFilter() { // 无参构造函数
super(COLOR_BLEND_FRAGMENT_SHADER); // 调用父类构造器,传入自定义片段着色器
}
父类GPUImageTwoInputFilter的构造函数会完成:① 加载框架默认的顶点着色器;② 编译/链接传入的片段着色器;③ 初始化纹理采样器等统一变量,为滤镜渲染做准备。
片段着色器全解析
该着色器运行在GPU端,为图像的每个像素独立执行一次main函数,通过「工具函数封装+主函数混合」的结构,实现高效、自然的颜色混合,以下先明确GLSL基础约定,再按**「变量声明区」→「核心工具函数区」→「主函数执行区」** 逐行、逐段解析代码的实现含义、数学逻辑和设计巧思。
前置GLSL基础约定
为方便理解,先明确代码中核心GLSL语法的含义,适配移动端GPU特性:
- 精度限定符 :
highp(高精度)用于需要精准计算的变量(纹理坐标、亮度),避免精度损失;lowp(低精度)用于颜色分量,满足视觉效果的同时节省GPU带宽; - 变量类型 :
varying:易变变量,由顶点着色器传递,经光栅化线性插值后为每个像素分配唯一值(如纹理坐标);uniform:统一变量,整个绘制过程中值不变,用于Java/GPU层参数交互(如纹理采样器、配置参数);
- 核心函数 :
texture2D(sampler, uv):根据纹理坐标uv从纹理采样器sampler中采样像素的RGBA颜色,返回vec4(r/g/b/a,值均为0~1的归一化值); - 向量运算 :GLSL支持向量直接加减/乘除,如
vec3(c) + vec3(d)等价于vec3(c.r+d, c.g+d, c.b+d),简化代码。
变量声明区:定义着色器输入依赖
该区域声明着色器的纹理坐标输入 和纹理采样器,是双纹理混合的基础,为工具函数和主函数提供原始输入,逐行解析如下:
c
// 接收顶点着色器传递的「基础纹理坐标」,高精度二维向量(u/v)
// 对应第一张输入纹理(待处理的基础图/相机帧),经光栅化插值后每个像素唯一
varying highp vec2 textureCoordinate;
// 接收顶点着色器传递的「叠加纹理坐标」,高精度二维向量
// 对应第二张输入纹理(色彩图层/滤镜层),与基础纹理坐标一一对应,保证像素对齐
varying highp vec2 textureCoordinate2;
// 基础纹理采样器,统一变量,关联GPU中基础纹理的ID
// 用于通过textureCoordinate采样基础纹理的像素颜色
uniform sampler2D inputImageTexture;
// 叠加纹理采样器,统一变量,关联GPU中叠加纹理的ID
// 用于通过textureCoordinate2采样叠加纹理的像素颜色
uniform sampler2D inputImageTexture2;
关键设计说明
- 纹理坐标使用
highp高精度:纹理坐标是像素的"GPU定位地址",低精度会导致纹理采样偏移、画面模糊,必须用高精度保证定位精准; - 双纹理采样器一一对应:
inputImageTexture+textureCoordinate、inputImageTexture2+textureCoordinate2形成两组采样对,保证基础纹理和叠加纹理的像素位置严格对齐,避免混合时的画面错位; - 无自定义配置参数:该着色器的混合规则是固定的"亮度锚定",因此仅声明基础输入变量,无额外uniform配置参数,简化GPU/Java层交互。
核心工具函数区:
该区域是着色器的核心算法层 ,封装了三个高内聚的工具函数,均围绕"保色彩的亮度操作"设计,解决了普通颜色混合的三大痛点:亮度计算不贴合人眼、颜色溢出导致失真、亮度调整破坏色相,是"亮度锚定混合"的技术基础。
函数1:lum ------ 计算人眼感知的亮度值
glsl
// 函数作用:将RGB颜色转换为**人眼感知的亮度值**(0~1)
// 入参:c - lowp vec3,待计算的RGB颜色(归一化值0~1),低精度节省GPU资源
// 返回:highp float,计算后的亮度值,高精度保证后续计算无精度损失
highp float lum(lowp vec3 c) {
// 亮度计算公式:dot点积展开为 0.3*c.r + 0.59*c.g + 0.11*c.b
return dot(c, vec3(0.3, 0.59, 0.11));
}
核心原理与设计
- 点积运算简化代码 :GLSL中
dot(vec3(a), vec3(b))等价于a.r*b.r + a.g*b.g + a.b*b.b,用点积替代手动加减乘,让代码更简洁,且GPU对向量运算有硬件优化,效率更高; - 行业标准亮度公式 :
0.3R+0.59G+0.11B是ITU-R BT.601 数字图像标准的简易亮度公式,贴合人眼视觉特性------人眼对绿色最敏感(权重0.59),红色次之(0.3),蓝色最弱(0.11),比简单的(R+G+B)/3平均亮度更符合人眼感知; - 亮度值范围 :输入RGB为01,因此输出亮度值也在01之间(纯黑0,纯白1),便于后续归一化计算。
函数2:clipcolor ------ 保亮度的颜色溢出裁剪(核心难点)
c
// 函数作用:将溢出0~1范围的RGB颜色分量**按比例拉回有效范围**,且**严格保留原颜色亮度**
// 入参:c - lowp vec3,可能溢出的RGB颜色(如r=1.2、g=-0.1)
// 返回:lowp vec3,裁剪后的合法RGB颜色(0≤r/g/b≤1),亮度与入参一致
lowp vec3 clipcolor(lowp vec3 c) {
// 步骤1:计算当前颜色的原始亮度,后续裁剪全程保留该亮度
highp float l = lum(c);
// 步骤2:获取RGB分量的最小值n,判断是否有分量低于0(下溢)
lowp float n = min(min(c.r, c.g), c.b);
// 步骤3:获取RGB分量的最大值x,判断是否有分量高于1(上溢)
lowp float x = max(max(c.r, c.g), c.b);
// 情况1:存在颜色分量下溢(n < 0),按保亮度规则拉回0以上
if (n < 0.0) {
// 对R/G/B分量分别按比例调整,公式核心:保亮度的线性拉伸
c.r = l + ((c.r - l) * l) / (l - n);
c.g = l + ((c.g - l) * l) / (l - n);
c.b = l + ((c.b - l) * l) / (l - n);
}
// 情况2:存在颜色分量上溢(x > 1),按保亮度规则拉回1以下
if (x > 1.0) {
// 对R/G/B分量分别按比例调整,公式核心与下溢一致,仅参考值改为1-l
c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);
c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);
c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);
}
// 步骤4:返回裁剪后的合法颜色,亮度与原始颜色完全一致
return c;
}
核心设计亮点:为什么不用普通clamp?
普通的clamp(c, 0.0, 1.0)会直接截断 溢出的颜色分量(如r=1.2→1.0,g=-0.1→0.0),这会导致颜色的色相、饱和度严重失真(比如亮红色截断后变成暗红色)。
而clipcolor函数是**「保亮度的非线性裁剪」**,核心逻辑是:将溢出的颜色分量按"亮度锚定比例"线性拉伸至有效范围,保持颜色的色相和饱和度不变,这是专业图像调色的标准做法。
公式简易推导(以上溢x>1为例)
以红色分量c.r的调整公式为例,拆解各部分含义:
c.r - l:红色分量与原始亮度的偏差值,反映红色分量相对亮度的偏移程度;1.0 - l:亮度到颜色上限1.0的剩余空间,限制拉伸的最大幅度;x - l:最大值与原始亮度的偏差值 ,作为拉伸的比例分母,保证所有分量同步拉伸;- 整体公式:
l + 偏差值 × 剩余空间 / 最大偏差值,本质是将所有颜色分量按相同比例拉伸至1.0以下,且以原始亮度l为锚点,不改变亮度。
函数3:setlum ------ 保色彩的亮度调整
c
// 函数作用:将指定RGB颜色的亮度**修改为目标亮度**,且**保留原颜色的色相和饱和度**
// 入参1:c - lowp vec3,待调整亮度的RGB颜色
// 入参2:l - highp float,目标亮度值(0~1)
// 返回:lowp vec3,亮度为l的新RGB颜色,色相/饱和度与原颜色一致
lowp vec3 setlum(lowp vec3 c, highp float l) {
// 步骤1:计算「目标亮度」与「当前亮度」的差值d
highp float d = l - lum(c);
// 步骤2:RGB三通道**统一加上差值d**,实现亮度线性偏移
c = c + vec3(d);
// 步骤3:裁剪偏移后可能溢出的颜色分量,保证结果合法
return clipcolor(c);
}
核心原理与设计
- RGB同加差值实现保色彩 :亮度的本质是RGB的"整体明暗程度",给RGB三通道统一加上一个值
d,会让颜色的整体明暗变化 ,但各通道的比例关系不变 (如R:G:B=2:3:4,加d后仍为2+d:3+d:4+d),而色相和饱和度由RGB的比例关系决定,因此这种方式能严格保留原颜色的色相和饱和度; - 先偏移后裁剪 :RGB同加差值后,可能出现分量溢出(如原c.r=0.9,d=0.2→c.r=1.1),因此必须调用
clipcolor裁剪,保证输出颜色合法; - 高精度差值计算 :
d使用highp高精度,避免亮度调整的精度损失,保证最终亮度与目标亮度完全一致。
核心作用:实现"色彩复用,亮度锚定"
该函数是整个着色器的核心桥梁 ,其作用是:提取叠加纹理的色彩特征(色相/饱和度),将其亮度替换为基础纹理的亮度,让叠加纹理的色彩能"贴合"基础纹理的亮度层次,避免混合后画面亮度失真。
主函数main
main是GLSL片段着色器的唯一入口函数 ,GPU会为图像的每个像素独立执行一次 该函数,核心逻辑是:采样双纹理像素→通过setlum实现叠加色的亮度锚定→按透明度加权混合双纹理颜色→输出最终像素颜色。
c
// 片段着色器入口函数,每个像素执行一次,无入参无返回
void main()
{
// 步骤1:采样基础纹理的当前像素颜色,RGBA四通道(vec4)
// texture2D(采样器, 纹理坐标):GLSL内置纹理采样函数,返回归一化RGBA颜色
highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);
// 步骤2:采样叠加纹理的当前像素颜色,与基础纹理像素位置严格对齐
highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);
// 步骤3:核心混合逻辑,计算最终像素颜色并输出
// gl_FragColor:GLSL内置输出变量,存储当前像素的最终RGBA颜色
gl_FragColor = vec4(
// 混合公式:透明度加权的线性混合(保亮度版)
baseColor.rgb * (1.0 - overlayColor.a) + // 基础色保留部分:按叠加色透明度反向加权
setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a, // 叠加色融合部分:亮度锚定后按透明度加权
baseColor.a // Alpha通道:直接沿用基础纹理的Alpha,保证基础图的透明区域不变
);
}
核心混合公式拆解(重点)
最终的颜色混合公式是**「透明度加权的线性混合」**的升级版本,普通线性混合公式为:混合色 = 基础色×(1-透明度) + 叠加色×透明度,而该着色器将其升级为:
混合色 = 基础色×(1-α) + 「亮度锚定后的叠加色」×α
其中α = overlayColor.a(叠加纹理的Alpha通道值,0~1),各部分含义:
- 基础色保留部分 :
baseColor.rgb * (1.0 - overlayColor.a)- 当叠加色完全透明(α=0):该部分=基础色,最终混合色=基础色,无任何叠加效果;
- 当叠加色完全不透明(α=1):该部分=0,最终混合色=亮度锚定后的叠加色,完全融合叠加色的色彩。
- 叠加色融合部分 :
setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a- 先通过
setlum将叠加色的亮度替换为基础色的亮度(保留叠加色的色相/饱和度); - 再按叠加色的透明度加权,实现"透明度过渡的自然混合"。
- 先通过
- Alpha通道处理 :直接沿用基础色的
baseColor.a,保证基础纹理的透明区域(如抠图后的人像边缘)在混合后仍保持透明,符合实际使用需求。
混合公式的效果示例
假设:
- 基础色:暗红色
vec3(0.2, 0.0, 0.0),亮度lum=0.06; - 叠加色:亮黄色
vec3(1.0, 1.0, 0.0),亮度lum=0.89,透明度α=0.5;
混合过程:
- 亮度锚定:
setlum(亮黄色, 0.06)→ 得到暗黄色(色相/饱和度与亮黄色一致,亮度与暗红色一致); - 加权混合:
暗红色×0.5 + 暗黄色×0.5→ 得到暗橙红色,既融合了黄色的色彩特征,又保留了红色的暗调亮度,混合效果自然,无过曝/过暗。
整体工作流程总结
该着色器为每个像素 执行的完整工作流程可概括为5步,GPU并行执行所有像素的计算,效率远高于CPU端处理:
- 纹理采样:根据对齐的纹理坐标,分别采样基础纹理和叠加纹理的当前像素RGBA颜色;
- 亮度提取:计算基础色的亮度值,作为后续混合的"亮度锚点";
- 色彩复用 :通过
setlum提取叠加色的色相/饱和度,将其亮度替换为基础色的亮度,得到"亮度锚定的叠加色"; - 加权混合:按叠加色的Alpha通道,将"基础色"和"亮度锚定的叠加色"进行透明度加权线性混合;
- 颜色输出 :将混合后的RGB颜色与基础色的Alpha通道组合,赋值给
gl_FragColor,作为当前像素的最终显示颜色。
核心设计亮点与适用场景
核心设计亮点
- 亮度锚定混合:区别于普通RGB直接混合,融合叠加色色彩的同时保留基础色亮度,避免画面亮度失真,混合效果更自然;
- 保色彩的亮度操作 :通过
lum/clipcolor/setlum三个函数,实现"亮度计算-颜色裁剪-亮度调整"的全流程保色彩,保证混合后的色相/饱和度无失真; - GPU硬件优化:大量使用GLSL向量运算(点积、向量加减),GPU对向量运算有硬件加速,兼顾效果和实时性,适合移动端相机预览、短视频实时滤镜等高性能场景;
- 像素级对齐:双纹理坐标严格一一对应,保证混合时画面无错位,支持任意尺寸的双纹理混合(GPU自动完成纹理坐标插值)。
典型适用场景
- 图片调色:将预设的色彩图层(如复古色卡、莫兰迪色卡)作为叠加纹理,融合到基础图片中,保留基础图的明暗层次,实现专业级调色;
- 视频实时滤镜:将相机实时帧作为基础纹理,预设色彩图层作为叠加纹理,实现直播/拍照的实时色彩融合滤镜;
- 创意图像合成:融合两张图片的色彩特征(如将风景图的色彩融合到人像图中),保留人像图的亮度层次,让合成效果更逼真;
- UI色彩主题融合:将UI的主题色图层作为叠加纹理,融合到背景图中,保证背景图的明暗纹理可见,同时贴合UI主题色。
与普通RGB混合的核心区别
| 混合方式 | 核心逻辑 | 优点 | 缺点 |
|---|---|---|---|
| 普通RGB混合 | 基础色×(1-α)+叠加色×α | 计算简单、效率高 | 亮度易失真(过曝/过暗),色相/饱和度可能偏移 |
| 亮度锚定混合(本着色器) | 基础色×(1-α)+「亮度锚定的叠加色」×α | 保留基础色亮度,色相/饱和度无失真,混合效果自然 | 多三步工具函数计算,GPU开销略高(移动端可忽略) |
该着色器以极小的GPU开销 解决了普通混合的核心痛点,是移动端图像/视频色彩融合的工业级实现方案,也是GPUImage框架中色彩混合类滤镜的经典设计。
实际使用
1 前置条件
在Android项目中集成GPUImage框架(推荐Gradle依赖):
gradle
dependencies {
implementation 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1' // 以最新版本为准
}
2 完整使用示例(Activity中)
以下示例实现"基础图片 + 叠加色彩图层"的混合效果,包含核心步骤注释:
java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.SurfaceView;
import androidx.appcompat.app.AppCompatActivity;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.filter.GPUImageColorBlendFilter;
import jp.co.cyberagent.android.gpuimage.filter.GPUImageTwoInputFilter;
public class ColorBlendDemoActivity extends AppCompatActivity {
private GPUImage gpuImage; // GPUImage核心类,负责滤镜渲染
private SurfaceView surfaceView; // 显示滤镜效果的控件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color_blend);
// 1. 初始化显示控件
surfaceView = findViewById(R.id.sv_filter_display);
// 2. 初始化GPUImage,绑定显示控件
gpuImage = new GPUImage(this);
gpuImage.setGLSurfaceView(surfaceView); // 关联SurfaceView,渲染结果会显示在该控件上
// 3. 加载输入图片(基础纹理+叠加纹理)
// 基础纹理:原始待处理的图片
Bitmap baseBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.base_photo);
// 叠加纹理:用于混合的色彩图层(如复古色卡、渐变图层)
Bitmap overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.overlay_color);
// 4. 实例化颜色混合滤镜
GPUImageColorBlendFilter blendFilter = new GPUImageColorBlendFilter();
// 5. 设置滤镜并绑定第二张输入纹理(叠加纹理)
gpuImage.setFilter(blendFilter); // 设置当前使用的滤镜
((GPUImageTwoInputFilter) blendFilter).setSecondImage(overlayBitmap); // 双输入滤镜需手动绑定第二张纹理
// 6. 处理并显示图片
gpuImage.setImage(baseBitmap); // 传入基础纹理,GPUImage会自动执行混合并渲染到SurfaceView
}
}
3 布局文件(activity_color_blend.xml)
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<jp.co.cyberagent.android.gpuimage.GLSurfaceView
android:id="@+id/sv_filter_display"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
4 关键使用说明
- 纹理尺寸:建议基础纹理和叠加纹理尺寸一致,避免纹理坐标映射导致的拉伸/变形;
- 叠加色透明度 :叠加纹理的Alpha通道决定混合强度:
- Alpha=0:完全显示基础图片;
- Alpha=1:完全显示"匹配基础亮度的叠加图片";
- 0<Alpha<1:按比例混合两者;
- 使用场景 :
- 图片调色:将叠加图层的色彩风格融合到基础图,保留基础图的亮度层次;
- 视频实时滤镜:摄像头画面作为基础纹理,预设色彩图层作为叠加纹理,实现实时混合;
- 创意合成:融合两张图片的色彩(如人物照+风景色)。
总结
GPUImageColorBlendFilter的核心优势是"亮度匹配的颜色混合"------区别于简单的RGB叠加,它通过lum/setlum/clipcolor三个GLSL函数保证混合后画面的亮度与基础纹理一致,仅融合叠加纹理的色彩特征,让混合效果更自然。
在实际开发中,只需完成"实例化滤镜→绑定双输入纹理→设置显示控件"三步,即可快速实现高质量的颜色混合效果,是GPUImage框架中处理色彩融合的经典实现。
