【Android 美颜相机】第十七天:GPUImageAddBlendFilter 解析

GPUImageAddBlendFilter 代码深度解析与使用指南

GPUImageAddBlendFilter 是基于 Android 平台的 GPUImage 框架实现的加法混合滤镜,核心作用是将两张图像按照特定的加法混合算法进行像素级融合,本文将逐行解析代码逻辑,并说明其实际使用方式。

代码整体结构概览

该类继承自 GPUImageTwoInputFilter(双输入滤镜基类),核心是自定义的 GLSL 片段着色器,通过逐像素计算实现两张图像的加法混合效果。整体代码分为:版权声明、包声明、类定义、片段着色器常量、构造函数五个核心部分。

逐行代码解析与含义说明

1. 版权与许可注释(1-13行)

java 复制代码
/*
 * Copyright (C) 2018 CyberAgent, Inc.  // 版权归属:CyberAgent 公司,2018年
 *
 * 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 GPUImageAddBlendFilter extends GPUImageTwoInputFilter {  // 定义加法混合滤镜类,继承双输入滤镜基类

核心含义

  • public:类对外可见,允许框架内外调用;
  • GPUImageAddBlendFilter:类名,明确功能为"加法混合滤镜";
  • extends GPUImageTwoInputFilter:继承双输入滤镜基类,基类已实现双纹理输入、GLSL 编译等基础逻辑,子类只需实现自定义着色器即可。

4. 片段着色器常量(18-52行)

片段着色器(Fragment Shader)是 GPU 执行的核心代码,负责逐像素计算最终显示颜色,也是该滤镜的核心逻辑。

java 复制代码
// 定义加法混合的片段着色器字符串,使用final修饰表示常量,避免被修改
public static final String ADD_BLEND_FRAGMENT_SHADER = 
    // 声明纹理坐标变量(来自顶点着色器),highp表示高精度,用于接收第一个输入纹理的坐标
    "varying highp vec2 textureCoordinate;\n" +
    // 声明第二个输入纹理的坐标变量,与textureCoordinate对应双输入纹理的坐标
    " varying highp vec2 textureCoordinate2;\n" +
    "\n" +
    // 声明第一个输入纹理的采样器,sampler2D表示2D纹理采样器,对应基础图像
    " uniform sampler2D inputImageTexture;\n" +
    // 声明第二个输入纹理的采样器,对应需要混合叠加的图像
    " uniform sampler2D inputImageTexture2;\n" +
    " \n" +
    // GLSL的main函数,是片段着色器的入口,逐像素执行
    " void main()\n" +
    " {\n" +
    // 从第一个纹理中采样获取基础像素颜色,base表示基础图像的像素(rgba),lowp表示低精度(节省GPU资源)
    "   lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" +
    // 从第二个纹理中采样获取叠加像素颜色,overlay表示叠加图像的像素(rgba)
    "   lowp vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" +
    "\n" +
    // 声明红色通道计算结果变量,mediump表示中精度,平衡精度与性能
    "   mediump float r;\n" +
    // 红色通道混合条件判断:判断叠加层红通道与基础层红通道的加权和是否≥两层透明度的乘积
    "   if (overlay.r * base.a + base.r * overlay.a >= overlay.a * base.a) {\n" +
    // 条件成立时的红色通道计算逻辑:混合透明度补偿后的红通道值
    "     r = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" +
    "   } else {\n" +
    // 条件不成立时:直接相加红色通道值(核心加法混合逻辑)
    "     r = overlay.r + base.r;\n" +
    "   }\n" +
    "\n" +
    // 声明绿色通道计算结果变量
    "   mediump float g;\n" +
    // 绿色通道混合条件判断(逻辑同红色通道)
    "   if (overlay.g * base.a + base.g * overlay.a >= overlay.a * base.a) {\n" +
    // 条件成立时的绿色通道计算逻辑
    "     g = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" +
    "   } else {\n" +
    // 条件不成立时:直接相加绿色通道值
    "     g = overlay.g + base.g;\n" +
    "   }\n" +
    "\n" +
    // 声明蓝色通道计算结果变量
    "   mediump float b;\n" +
    // 蓝色通道混合条件判断(逻辑同红/绿色通道)
    "   if (overlay.b * base.a + base.b * overlay.a >= overlay.a * base.a) {\n" +
    // 条件成立时的蓝色通道计算逻辑
    "     b = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" +
    "   } else {\n" +
    // 条件不成立时:直接相加蓝色通道值
    "     b = overlay.b + base.b;\n" +
    "   }\n" +
    "\n" +
    // 计算最终透明度:叠加层透明度 + 基础层透明度 - 两层透明度的乘积(标准Alpha混合公式)
    "   mediump float a = overlay.a + base.a - overlay.a * base.a;\n" +
    "   \n" +
    // 将计算后的rgba值赋值给gl_FragColor,作为当前像素的最终颜色输出
    "   gl_FragColor = vec4(r, g, b, a);\n" +
    " }";

核心逻辑拆解

  • 纹理采样:通过 texture2D 从两个输入纹理中获取对应像素的 RGBA 值(base 为基础图,overlay 为叠加图);
  • 颜色通道计算:对 R/G/B 三个颜色通道分别做条件判断:
    • 条件1(成立):当颜色通道加权和≥透明度乘积时,采用"透明度补偿"公式,避免颜色值溢出;
    • 条件2(不成立):直接相加两个通道的值,实现"加法混合"核心效果;
  • 透明度计算:采用标准 Alpha 混合公式,保证叠加后透明度的合理性(避免透明度超过1或小于0);
  • 输出颜色:将计算后的 R/G/B/A 组合为 vec4,赋值给 gl_FragColor,完成单个像素的颜色输出。

5. 构造函数(54-56行)

java 复制代码
// 无参构造函数,供外部创建滤镜实例
public GPUImageAddBlendFilter() {
    // 调用父类GPUImageTwoInputFilter的构造函数,传入自定义的片段着色器
    super(ADD_BLEND_FRAGMENT_SHADER);
}

核心含义

  • 无参构造函数简化外部调用,无需传入额外参数;
  • 调用父类构造器时传入自定义片段着色器,父类会自动完成着色器的编译、链接,以及双输入纹理的绑定逻辑,子类无需重复实现基础 GL 操作。

6. 类结束标识(57行)

java 复制代码
}

核心含义:标记类定义结束,是 Java 语法的标准闭合符号。

GPUImageAddBlendFilter 实际使用方法

该滤镜的核心是"双输入纹理混合",使用时需要依赖 GPUImage 框架的上下文(如 GPUImage 实例),步骤如下:

1. 前置依赖

确保项目中引入 GPUImage 框架的依赖(如 Gradle 依赖):

gradle 复制代码
dependencies {
    implementation 'jp.co.cyberagent.android:gpuimage:1.4.1' // 以实际版本为准
}

2. 核心使用代码示例

java 复制代码
// 1. 初始化GPUImage上下文(关联SurfaceView/TextureView,用于显示滤镜效果)
GPUImage gpuImage = new GPUImage(context);
gpuImage.setGLSurfaceView((GLSurfaceView) findViewById(R.id.glsurfaceview));

// 2. 创建加法混合滤镜实例
GPUImageAddBlendFilter addBlendFilter = new GPUImageAddBlendFilter();

// 3. 设置基础图像(第一个输入纹理)
gpuImage.setImage(new File("/sdcard/base_image.jpg")); // 基础图(如背景图)

// 4. 设置叠加图像(第二个输入纹理)
// 方式1:通过滤镜设置第二个输入纹理(GPUImageTwoInputFilter的核心方法)
addBlendFilter.setSecondTexture(gpuImage.loadTexture(new File("/sdcard/overlay_image.png")));

// 5. 应用滤镜
gpuImage.setFilter(addBlendFilter);

// 6. 显示处理后的图像
gpuImage.requestRender();

3. 关键使用说明

  • 双输入纹理要求:基础纹理(inputImageTexture)通过 gpuImage.setImage() 设置,叠加纹理(inputImageTexture2)必须通过 setSecondTexture() 方法设置,这是 GPUImageTwoInputFilter 基类约定的双输入纹理绑定方式;
  • 纹理格式支持:支持 JPG/PNG 等常见格式,PNG 带透明通道时,透明度(Alpha)会参与混合计算,效果更自然;
  • 性能优化:着色器中使用 lowp/mediump 精度,避免 highp 带来的性能损耗,适配中低端安卓设备;
  • 扩展场景:可结合 GPUImage 其他滤镜(如亮度调整、模糊),先处理基础/叠加图像,再执行加法混合。

总结

GPUImageAddBlendFilter 是一个轻量级的加法混合滤镜,核心逻辑集中在自定义片段着色器中:通过逐像素判断颜色通道的加权和,实现"条件加法混合",既保证了加法混合的视觉效果(颜色更明亮),又通过透明度补偿避免颜色溢出。

该类的设计遵循 GPUImage 框架的"基类封装通用逻辑、子类实现自定义着色器"的设计思想,简化了滤镜开发成本。实际使用中只需关注双输入纹理的设置,即可快速实现两张图像的加法混合效果,适用于图片编辑、视频特效等场景。

相关推荐
符哥20082 小时前
一篇讲透掌握 Kotlin 协程
android·kotlin
开发者小天2 小时前
python中的Dictionaries
android·开发语言·python
_F_y2 小时前
MySQL表的内连和外连
android·数据库·mysql
肖。35487870942 小时前
窗口半初始化导致的BadTokenException闪退!解决纯Java开发的安卓软件开局闪退!具体表现为存储中的缓存为0和数据为0。
android·java·javascript·css·html
2601_9495758612 小时前
Flutter for OpenHarmony二手物品置换App实战 - 商品卡片实现
android·flutter
2601_9495758614 小时前
Flutter for OpenHarmony二手物品置换App实战 - 表单验证实现
android·java·flutter
龚礼鹏16 小时前
图像显示框架八——BufferQueue与BLASTBufferQueue(基于android 15源码分析)
android·c语言
XuanTao7717 小时前
【安卓工具实测】影视仓更新!!追剧党狂喜!影视仓无广告版太香了!
深度学习·数码相机·智能手机·软件工程·软件构建
1登峰造极17 小时前
uniapp 运行安卓报错reportJSException >>>> exception function:createInstanceContext, exception:white screen
android·java·uni-app