这个系列文章我们来介绍一位海外工程师如何探索 GPUImage 音视频技术,对于想要开始学习音视频技术的朋友,这些文章是份不错的入门资料,本篇介绍 GPUImage 滤镜链。
——来自公众号“关键帧Keyframe”的分享
滤镜链是 GPUImage 最强大的功能之一,它让你能够将多个滤镜连接起来,构建出单一滤镜难以实现的复杂图像与视频处理流水线。本指南将介绍 GPUImage 中滤镜链的工作原理,并示范如何创建并管理高效的滤镜链。
1、架构概览
GPUImage 采用基于“目标(target)”的架构,图像数据以 OpenGL 纹理的形式从源头流经一系列滤镜,最终到达输出端。每个组件各司其职:
- 数据源(Sources):如
GPUImageVideoCamera、GPUImageStillCamera、GPUImagePicture、GPUImageMovie,负责提供纹理格式的图像数据。 - 滤镜(Filters):接收纹理、处理后输出新纹理(实现了
GPUImageInput协议)。 - 输出端(Outputs):负责显示或保存最终图像,例如
GPUImageView用于屏幕显示,或导出为UIImage/ 视频文件。
得益于此设计,你可以按需自由组合这些组件,搭建任何想要的处理流水线。
2、基本的线性滤镜链
最简单的情况是一条直线:数据源 → 滤镜1 → 滤镜2 → … → 输出端。
2.1、示例:相机 → 棕褐色 → 亮度 → 屏幕显示
// 1. 创建摄像头
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc]
initWithSessionPreset:AVCaptureSessionPreset640x480
cameraPosition:AVCaptureDevicePositionBack];
videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
// 2. 创建滤镜
GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
GPUImageBrightnessFilter *brightnessFilter = [[GPUImageBrightnessFilter alloc] init];
brightnessFilter.brightness = 0.1;
// 3. 创建显示视图
GPUImageView *filteredVideoView = [[GPUImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, width, height)];
// 4. 建立链
[videoCamera addTarget:sepiaFilter]; // 摄像头 → 棕褐色滤镜
[sepiaFilter addTarget:brightnessFilter]; // 棕褐色 → 亮度滤镜
[brightnessFilter addTarget:filteredVideoView];// 亮度 → 显示视图
// 5. 开始采集
[videoCamera startCameraCapture];
3、分支滤镜链
GPUImage 允许把一个组件的输出同时送到多个目标,实现“分叉”效果。
3.1、示例:摄像头同时输出到棕褐色滤镜和高斯模糊滤镜
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480
cameraPosition:AVCaptureDevicePositionBack];
GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
GPUImageGaussianBlurFilter *blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
GPUImageView *sepiaView = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 0, width, height/2)];
GPUImageView *blurView = [[GPUImageView alloc] initWithFrame:CGRectMake(0, height/2, width, height/2)];
// 分叉:摄像头同时连到两个滤镜
[videoCamera addTarget:sepiaFilter];
[videoCamera addTarget:blurFilter];
// 各自显示
[sepiaFilter addTarget:sepiaView];
[blurFilter addTarget:blurView];
[videoCamera startCameraCapture];
4、多输入滤镜(链合并)
某些效果需要把多条图像流合并,例如混合模式、合成操作或自定义多输入滤镜。GPUImage 提供了 GPUImageTwoInputFilter 等专用滤镜。
4.1、示例:摄像头实时画面与一张 PNG 做 Alpha 混合
// 1. 摄像头
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480
cameraPosition:AVCaptureDevicePositionBack];
// 2. 静态图片
UIImage *overlayImage = [UIImage imageNamed:@"Overlay.png"];
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:overlayImage];
// 3. Alpha 混合滤镜
GPUImageAlphaBlendFilter *blendFilter = [[GPUImageAlphaBlendFilter alloc] init];
blendFilter.mix = 0.5; // 50% 混合
// 4. 显示视图
GPUImageView *displayView = [[GPUImageView alloc] initWithFrame:self.view.bounds];
// 5. 连接
[videoCamera addTarget:blendFilter]; // 第一输入
[stillImageSource addTarget:blendFilter]; // 第二输入
[blendFilter addTarget:displayView];
// 6. 启动
[videoCamera startCameraCapture];
[stillImageSource processImage];
对于
GPUImageTwoInputFilter等多输入滤镜,目标的添加顺序决定了主次输入;不同滤镜对输入顺序有不同要求。
5、复杂滤镜链示例
将“分叉”与“合并”组合,可搭建更高级的流水线:
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480
cameraPosition:AVCaptureDevicePositionBack];
GPUImageContrastFilter *contrastFilter = [[GPUImageContrastFilter alloc] init];
GPUImageGaussianBlurFilter *blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
GPUImageSobelEdgeDetectionFilter *edgeFilter = [[GPUImageSobelEdgeDetectionFilter alloc] init];
GPUImageAlphaBlendFilter *blendFilter = [[GPUImageAlphaBlendFilter alloc] init];
blendFilter.mix = 0.5;
GPUImageView *displayView = [[GPUImageView alloc] initWithFrame:self.view.bounds];
/* 构造链
摄像头 → 对比度 ─┬─> 模糊 ─┐
└─> 边缘 ─┴─> 混合 → 显示
*/
[videoCamera addTarget:contrastFilter];
[contrastFilter addTarget:blurFilter];
[contrastFilter addTarget:edgeFilter];
[blurFilter addTarget:blendFilter];
[edgeFilter addTarget:blendFilter];
[blendFilter addTarget:displayView];
[videoCamera startCameraCapture];
6、动态链管理
滤镜链并非一成不变,可在运行时增删组件或调节参数。
6.1、增删滤镜
// 追加新滤镜
GPUImageSepiaFilter *newFilter = [[GPUImageSepiaFilter alloc] init];
[existingFilter addTarget:newFilter];
[newFilter addTarget:finalOutput];
// 替换滤镜
[sourceFilter removeTarget:filterToRemove];
[sourceFilter addTarget:replacementFilter];
[replacementFilter addTarget:finalOutput];
6.2、实时调整参数
// 带动画地调整模糊强度
CGFloat startValue = 0.0;
CGFloat endValue = 1.0;
CGFloat duration = 2.0;
[UIView animateWithDuration:duration animations:^{
blurFilter.blurSize = endValue;
}];
实际应用中推荐使用
CADisplayLink等机制以获得更平滑的动画。
7、性能注意事项
- 减少 CPU↔GPU 数据往返:纹理上传/下载开销大,尽量全程在 GPU 完成。
- 滤镜顺序:把计算量大的滤镜放在链后端,或在降分辨率后执行。
- 合理分辨率:并非所有环节都要全尺寸;可在关键位置插入缩放滤镜。
- 复用滤镜:创建滤镜有开销,尽量复用而非频繁新建。
- 测试帧率:链路过长或过于复杂会影响性能,务必在目标设备实测。
8、结语
GPUImage 的滤镜链机制让你能够像搭积木一样构建任意复杂度的图像/视频处理流水线。掌握“线性链—分叉—合并”三大模式,再结合动态管理,即可充分发挥 GPU 加速的威力,从简单照片滤镜到高级计算机视觉应用,皆可轻松实现。
学习和提升音视频开发技术,推荐你加入我们的知识星球:【关键帧的音视频开发圈】

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。