07-iOS 多媒体技术| 滤镜框架Core Image、GPUImage要点回顾【滤镜链、内置滤镜、自定义滤镜、GPUImage的简单使用等】

前言

我们在前面,首先进行了针对 iOS中的多媒体技术相关几个框架概述:

  1. 进而 用 两篇文章 对 其中的 UIKit相关要点 进行了分述:
  2. 然后我们 针对 Core Animation框架的要点 进一步展开分述:
  3. 紧接着 我们快速回顾了 2D绘图引擎Core Graphics框架的要点
  4. 我们 在此篇文章 ,将 针对 滤镜框架Core Image、GPUImage框架的要点 进一步展开分述:

一、Core Image

Core Image是苹果提供的图像处理框架,主要用于实现图像处理滤镜应用图像分析等功能。以下是Core Image的核心要点:

1. 主要特点和功能

    1. 滤镜(Filter):
    • Core Image提供了丰富的滤镜效果,如模糊锐化色彩调整边缘检测等。
    • 开发者可以通过Core Image的滤镜功能对图像进行处理和增强。
    • iOS 8 之后 引入 CIFilter,Core Image从此支持自定义滤镜的创建和应用,实现个性化的图像处理效果。
    1. 图像处理链(Image Processing Pipeline):
    • Core Image使用图像处理链来处理图像,包括输入图像滤镜效果和输出图像
    • 开发者可以构建自定义的图像处理链,实现复杂的图像处理流程。
    1. 图像分析(Image Analysis):
    • Core Image支持图像分析功能,如人脸检测特征识别颜色识别物体识别等。
    • 开发者可以利用Core Image进行图像分析,提取图像中的信息和特征
    1. Metal性能优化:
    • Core Image可以与Metal框架结合,利用GPU硬件加速来提高图像处理的性能。
    • 开发者可以通过Metal框架优化Core Image的性能,实现高效的图像处理和滤镜效果。
    1. 图像格式转换(Image Format Conversion):
    • Core Image支持图像格式的转换和处理,如颜色空间转换像素格式转换等。
    • 开发者可以使用Core Image进行图像格式的转换和处理,满足不同的图像处理需求。
    1. 实时预览(Real-time Preview):
    • Core Image提供实时预览功能,可以在应用程序中实时显示滤镜效果的预览。
    • 开发者可以通过Core Image实现实时的滤镜预览,方便用户调整和查看效果。
    1. 其它
    • Core Image 与 Core Graphics 恰恰相反

      • Core Graphics 用于在运行时创建图像
      • 而 Core Image 是用来处理已经创建的图像的。
    • Core Image 是 iOS5 新加入到 iOS 平台的一个图像处理框架,提供了强大高效的图像处理功能, 用来对基于像素的图像进行操作与分析, 内置了很多强大的滤镜(Filter) (目前数量超过了180种), 这些Filter 提供了各种各样的效果, 并且还可以通过 滤镜链 将各种效果的 Filter叠加 起来形成强大的自定义效果。

      • iOS8 之后更是支持自定义 CIFilter,可以定制满足业务需求的复杂效果。
    • Core Image 的优点在于十分高效。大部分情况下,它会在 GPU 中完成工作,但如果 GPU 忙,会使用 CPU 进行处理。如果设备支持 Metal,那么会使用 Metal 处理。这些操作会在底层完成,Apple 的工程师们已经帮助开发者们完成这些操作了。

      • 例如他可以根据需求选择 CPU 或者 GPU 来处理。
      objc 复制代码
        // 创建基于 CPU 的 CIContext 对象 (默认是基于 GPU,CPU 需要额外设置参数)
        context = [CIContext contextWithOptions: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];
        // 创建基于 GPU 的 CIContext 对象
        context = [CIContext contextWithOptions: nil];
        // 创建基于 GPU 的 CIContext 对象
        EAGLContext *eaglctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        context = [CIContext contextWithEAGLContext:eaglctx];

2. 核心类介绍

    1. CIImage:
    • CIImage是Core Image框架中表示图像数据的类,可以用来表示图像数据源
    • CIImage可以从各种来源创建,如UIImage、CGImage、NSData、图像文件或者像素数据等,用于输入到Core Image的滤镜中进行处理。
    1. CIFilter:
    • CIFilter是Core Image框架中的滤镜类,用于实现各种图像处理和滤镜效果。
    • CIFilter包含了各种内置的滤镜效果,也可以自定义滤镜来实现特定的图像处理需求。
    • 这个框架中对图片属性进行细节处理的类。它对所有的像素进行操作,用一些键-值设置来决定具体操作的程度。
    1. CIContext:
    • CIContext是Core Image框架中的上下文类,用于管理图像处理的环境和输出。
    • CIContext可以指定渲染目标(如屏幕、图像文件)、渲染选项(如颜色空间、缩放比例)等参数。
    1. CIFeature:
    • CIFeature是Core Image框架中的特征类,用于检测图像中的特征和对象。
    • CIFeature可以用于人脸检测、文本识别、条形码识别等应用场景。
    1. CIColor:
    • CIColor是Core Image框架中的颜色类,用于表示颜色信息。
    • CIColor可以用来创建颜色对象,设置滤镜效果中的颜色参数。
    1. CIVector:
    • CIVector是Core Image框架中的向量类,用于表示多维向量数据。
    • CIVector可以用来设置滤镜效果中的向量参数,如位置、大小等。
  • Core Image 的 API 主要就是三类:

    • CIContext 表示上下文,如 Core Graphics 以及 Core Data 中的上下文用于处理绘制渲染以及处理托管对象一样,Core Image 的上下文也是实现对图像处理的具体对象。可以从其中取得图片的信息。

3. 代码示例

3.1 滤镜|模糊、锐化、色彩调整、边缘检测 和 自定义滤镜

Objective-C示例:

objc 复制代码
// Objective-C示例:
#import <UIKit/UIKit.h>
#import <CoreImage/CoreImage.h>

// 模糊处理
UIImage *applyBlurFilter(UIImage *image) {
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:@10 forKey:kCIInputRadiusKey];
    CIImage *outputImage = [filter outputImage];
    
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
    UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    
    return resultImage;
}

// 锐化处理
UIImage *applySharpenFilter(UIImage *image) {
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    CIFilter *filter = [CIFilter filterWithName:@"CISharpenLuminance"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:@0.5 forKey:kCIInputSharpnessKey];
    CIImage *outputImage = [filter outputImage];
    
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
    UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    
    return resultImage;
}

// 色彩调整
UIImage *applyColorAdjustmentFilter(UIImage *image) {
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:@1.2 forKey:kCIInputContrastKey];
    [filter setValue:@0.5 forKey:kCIInputBrightnessKey];
    [filter setValue:@0.8 forKey:kCIInputSaturationKey];
    CIImage *outputImage = [filter outputImage];
    
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
    UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    
    return resultImage;
}

// 边缘检测
UIImage *applyEdgeDetectionFilter(UIImage *image) {
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    CIFilter *filter = [CIFilter filterWithName:@"CIEdges"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    CIImage *outputImage = [filter outputImage];
    
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
    UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    
    return resultImage;
}

// 自定义滤镜
UIImage *applyCustomFilter(UIImage *image) {
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    
    // 自定义滤镜
    CIFilter *filter = [CIFilter filterWithName:@"CIColorMatrix"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    
    // 设置自定义参数
    CIVector *RVector = [CIVector vectorWithX:1 Y:0 Z:0 W:0];
    CIVector *GVector = [CIVector vectorWithX:0 Y:1 Z:0 W:0];
    CIVector *BVector = [CIVector vectorWithX:0 Y:0 Z:1 W:0];
    CIVector *AVector = [CIVector vectorWithX:0 Y:0 Z:0 W:1];
    [filter setValue:RVector forKey:@"inputRVector"];
    [filter setValue:GVector forKey:@"inputGVector"];
    [filter setValue:BVector forKey:@"inputBVector"];
    [filter setValue:AVector forKey:@"inputAVector"];
    
    CIImage *outputImage = [filter outputImage];
    
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
    UIImage *resultImage = [UIImage imageWithCGImage

Swift示例:

swift 复制代码
import UIKit
import CoreImage

// 图像处理类
class ImageProcessor {
    
    // 应用模糊滤镜
    func applyBlurFilter(to image: UIImage) -> UIImage? {
        if let ciImage = CIImage(image: image) {
            let filter = CIFilter(name: "CIGaussianBlur")
            filter?.setValue(ciImage, forKey: kCIInputImageKey)
            filter?.setValue(5.0, forKey: kCIInputRadiusKey)
            
            if let outputImage = filter?.outputImage {
                let context = CIContext()
                if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
        }
        return nil
    }
    
    // 应用锐化滤镜
    func applySharpenFilter(to image: UIImage) -> UIImage? {
        if let ciImage = CIImage(image: image) {
            let filter = CIFilter(name: "CISharpenLuminance")
            filter?.setValue(ciImage, forKey: kCIInputImageKey)
            filter?.setValue(0.5, forKey: kCIInputSharpnessKey)
            
            if let outputImage = filter?.outputImage {
                let context = CIContext()
                if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
        }
        return nil
    }
    
    // 应用色彩调整滤镜
    func applyColorAdjustmentFilter(to image: UIImage) -> UIImage? {
        if let ciImage = CIImage(image: image) {
            let filter = CIFilter(name: "CIColorControls")
            filter?.setValue(ciImage, forKey: kCIInputImageKey)
            filter?.setValue(1.2, forKey: kCIInputContrastKey)
            filter?.setValue(0.8, forKey: kCIInputBrightnessKey)
            filter?.setValue(0.5, forKey: kCIInputSaturationKey)
            
            if let outputImage = filter?.outputImage {
                let context = CIContext()
                if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
        }
        return nil
    }
    
    // 应用边缘检测滤镜
    func applyEdgeDetectionFilter(to image: UIImage) -> UIImage? {
        if let ciImage = CIImage(image: image) {
            let filter = CIFilter(name: "CIEdges")
            filter?.setValue(ciImage, forKey: kCIInputImageKey)
            
            if let outputImage = filter?.outputImage {
                let context = CIContext()
                if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
        }
        return nil
    }
    
    // 应用自定义滤镜
    func applyCustomFilter(to image: UIImage) -> UIImage? {
        if let ciImage = CIImage(image: image) {
            // 自定义滤镜:将图像转为灰度图
            let filter = CIFilter(name: "CIPhotoEffectMono")
            filter?.setValue(ciImage, forKey: kCIInputImageKey)
            
            if let outputImage = filter?.outputImage {
                let context = CIContext()
                if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
        }
        return nil
    }
}

// 使用示例
let image = UIImage(named: "example.jpg")!
let processor = ImageProcessor()

let blurredImage = processor.applyBlurFilter(to: image)
let sharpenedImage = processor.applySharpenFilter(to: image)
let colorAdjustedImage = processor.applyColorAdjustmentFilter(to: image)
let edgeDetectedImage = processor.applyEdgeDetectionFilter(to: image)
let customFilteredImage = processor.applyCustomFilter(to: image)

3.1 图像处理链|输入图像、滤镜效果、和输出图像

Objective-C示例:

objc 复制代码
// Objective-C示例:
#import <UIKit/UIKit.h>
#import <CoreImage/CoreImage.h>

UIImage *applyFilterToImage(UIImage *inputImage) {
    CIImage *ciImage = [[CIImage alloc] initWithImage:inputImage];
    
    CIFilter *filter = [CIFilter filterWithName:@"CIPhotoEffectMono"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    
    CIImage *outputImage = [filter outputImage];
    
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
    
    UIImage *filteredImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    
    return filteredImage;
}

Swift示例:

swift 复制代码
// Swift示例:
import UIKit
import CoreImage

func applyFilterToImage(inputImage: UIImage) -> UIImage? {
    if let ciImage = CIImage(image: inputImage) {
        let filter = CIFilter(name: "CIPhotoEffectMono")
        filter?.setValue(ciImage, forKey: kCIInputImageKey)
        
        if let outputImage = filter?.outputImage {
            let context = CIContext(options: nil)
            if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                let filteredImage = UIImage(cgImage: cgImage)
                return filteredImage
            }
        }
    }
    return nil
}

3.1 图像分析|人脸检测、特征识别、颜色识别、物体识别

Objective-C示例:

objc 复制代码
// Objective-C示例:
#import <UIKit/UIKit.h>
#import <CoreImage/CoreImage.h>

- (void)analyzeImage:(UIImage *)image {
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    
    // 人脸检测
    NSDictionary *options = @{CIDetectorAccuracy: CIDetectorAccuracyHigh};
    CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:options];
    NSArray *faces = [faceDetector featuresInImage:ciImage];
    for (CIFaceFeature *faceFeature in faces) {
        NSLog(@"Detected face at %@", NSStringFromCGRect(faceFeature.bounds));
    }
    
    // 特征识别
    NSDictionary *featureOptions = @{CIDetectorImageOrientation: @(1)};
    CIDetector *featureDetector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:featureOptions];
    NSArray *features = [featureDetector featuresInImage:ciImage];
    for (CIQRCodeFeature *feature in features) {
        NSLog(@"Detected QR code with message: %@", feature.messageString);
    }
    
    // 颜色识别
    CIColor *averageColor = [ciImage valueForKey:@"inputImage"];
    NSLog(@"Average color of the image: %@", averageColor);
    
    // 物体识别
    NSDictionary *objectOptions = @{CIDetectorAccuracy: CIDetectorAccuracyHigh};
    CIDetector *objectDetector = [CIDetector detectorOfType:CIDetectorTypeRectangle context:nil options:objectOptions];
    NSArray *objects = [objectDetector featuresInImage:ciImage];
    for (CIRectangleFeature *objectFeature in objects) {
        NSLog(@"Detected object at %@", NSStringFromCGRect(objectFeature.bounds));
    }
}

Swift示例:

swift 复制代码
import UIKit
import CoreImage

class ImageAnalysis {
    
    func analyzeImage(image: UIImage) {
        if let ciImage = CIImage(image: image) {
            let context = CIContext()
            
            // 人脸检测
            let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: context, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
            let faces = faceDetector?.features(in: ciImage)
            for face in faces as! [CIFaceFeature] {
                print("Face bounds: \(face.bounds)")
                if face.hasLeftEyePosition {
                    print("Left eye position: \(face.leftEyePosition)")
                }
                if face.hasRightEyePosition {
                    print("Right eye position: \(face.rightEyePosition)")
                }
            }
            
            // 特征识别
            let featureDetector = CIDetector(ofType: CIDetectorTypeRectangle, context: context, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
            let features = featureDetector?.features(in: ciImage)
            for feature in features as! [CIRectangleFeature] {
                print("Feature bounds: \(feature.bounds)")
            }
            
            // 颜色识别
            let colorDetector = CIDetector(ofType: CIDetectorTypeColor, context: context, options: nil)
            let colors = colorDetector?.features(in: ciImage)
            for color in colors as! [CIColorFeature] {
                print("Detected color: \(color.color)")
            }
            
            // 物体识别
            let objectDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: nil)
            let objects = objectDetector?.features(in: ciImage)
            for object in objects as! [CIQRCodeFeature] {
                print("Detected QR code: \(object.messageString ?? "")")
            }
        }
    }
}

// 使用示例
let image = UIImage(named: "sampleImage")
let imageAnalysis = ImageAnalysis()
imageAnalysis.analyzeImage(image: image)

3.1 Metal性能优化

Objective-C示例:

objc 复制代码
// Objective-C示例:
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import <CoreImage/CoreImage.h>

// 创建Metal设备和CIContext
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
CIContext *ciContext = [CIContext contextWithMTLDevice:device];

// 创建Metal纹理
MTKView *metalView = [[MTKView alloc] initWithFrame:CGRectZero device:device];
id<MTLTexture> metalTexture = metalView.currentDrawable.texture;

// 创建CIImage
CIImage *ciImage = [CIImage imageWithMTLTexture:metalTexture options:nil];

// 创建滤镜
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
[filter setValue:ciImage forKey:kCIInputImageKey];
[filter setValue:@(1.2) forKey:kCIInputContrastKey];

// 渲染并显示结果
CIImage *outputImage = [filter outputImage];
[ciContext render:outputImage toMTLTexture:metalTexture commandBuffer:nil bounds:outputImage.extent colorSpace:outputImage.colorSpace];

Swift示例:

swift 复制代码
// Swift示例:
import Metal
import MetalKit
import CoreImage

// 创建Metal设备和CIContext
let device = MTLCreateSystemDefaultDevice()
let ciContext = CIContext(mtlDevice: device!)

// 创建Metal纹理
let metalView = MTKView(frame: CGRect.zero, device: device)
let metalTexture = metalView.currentDrawable?.texture

// 创建CIImage
let ciImage = CIImage(mtlTexture: metalTexture!, options: nil)

// 创建滤镜
let filter = CIFilter(name: "CIColorControls")
filter?.setValue(ciImage, forKey: kCIInputImageKey)
filter?.setValue(1.2, forKey: kCIInputContrastKey)

// 渲染并显示结果
if let outputImage = filter?.outputImage {
    ciContext.render(outputImage, to: metalTexture!, commandBuffer: nil, bounds: outputImage.extent, colorSpace: outputImage.colorSpace)
}

3.1 实时预览

Objective-C示例:

objc 复制代码
// Objective-C示例:
#import <UIKit/UIKit.h>
#import <CoreImage/CoreImage.h>

@interface ViewController : UIViewController <AVCaptureVideoDataOutputSampleBufferDelegate>

@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (nonatomic, strong) CIContext *ciContext;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.captureSession = [[AVCaptureSession alloc] init];
    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    NSError *error = nil;
    AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
    
    if (videoInput) {
        [self.captureSession addInput:videoInput];
        
        AVCaptureVideoDataOutput *videoOutput = [[AVCaptureVideoDataOutput alloc] init];
        [videoOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
        [self.captureSession addOutput:videoOutput];
        
        self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
        self.previewLayer.frame = self.view.bounds;
        [self.view.layer addSublayer:self.previewLayer];
        
        [self.captureSession startRunning];
        
        self.ciContext = [CIContext contextWithOptions:nil];
    } else {
        NSLog(@"Error setting up video input: %@", error);
    }
}

- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
    CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
    
    // 应用滤镜
    CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:@(1.2) forKey:kCIInputContrastKey];
    
    CIImage *outputImage = [filter outputImage];
    
    // 渲染到预览层
    [self.ciContext render:outputImage toCVPixelBuffer:pixelBuffer];
}

@end

Swift示例:

swift 复制代码
// Swift示例:
import UIKit
import AVFoundation

class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
    
    var captureSession: AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer!
    var ciContext: CIContext!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        captureSession = AVCaptureSession()
        guard let videoDevice = AVCaptureDevice.default(for: .video),
              let videoInput = try? AVCaptureDeviceInput(device: videoDevice) else {
            return
        }
        
        if captureSession.canAddInput(videoInput) {
            captureSession.addInput(videoInput)
            
            let videoOutput = AVCaptureVideoDataOutput()
            videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
            captureSession.addOutput(videoOutput)
            
            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            previewLayer.frame = view.bounds
            view.layer.addSublayer(previewLayer)
            
            captureSession.startRunning()
            
            ciContext = CIContext()
        }
    }
    
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
        
        // 应用滤镜
        let filter = CIFilter(name: "CIColorControls")
        filter?.setValue(ciImage, forKey: kCIInputImageKey)
        filter?.setValue(1.2, forKey: kCIInputContrastKey)
        
        if let outputImage = filter?.outputImage {
            // 渲染到预览层
            ciContext.render(outputImage, to: pixelBuffer)
        }
    }
}

4. 总结

Core Image的图像分析功能比较鸡肋,且滤镜功能比较封闭。我们在日常开发中一般用GPUImage较多.因此在这里只做基本了解.

相对 Core Image有更深的认识和实践,推荐几篇文章:

二、GPUImage

1. 简介

GPUImage是一个基于OpenGL ES 2.0的开源的图像处理库,作者是Brad LarsonGPUImageOpenGL ES封装为简洁的Objective-CSwift接口,可以用来给图像、实时相机视频、电影等添加滤镜。

目前GPUImage有三个版本:

本文 主要针对 GPUImage1展开介绍。GPUImage2、GPUImage3与GPUImage1大同小异。

2. 与Core Image区别

对于图像的处理苹果官方提供了Core Image框架,那么GPUImage和Core Image有哪些区别呢?

2.1 GPUImage

  • 最低支持iOS 4.0,iOS 5.0之后就支持自定义滤镜
  • 在低端机型上,GPUImage有更高的表现
  • GPUImage 在视频处理上有更好的表现.
  • GPUImage 代码完全开源,实现透明.
  • 可以根据自己的业务需求,定制更加复杂的管线操作.可定制程度高.
  • GPUImage当处理超过纹理限制的图像的时候,会先做判断,压缩成最大纹理限制的图像,导致图像质量损失

2.2 Core Image

  • 官方框架,使用放心,维护方便.
  • 支持CPU渲染,可以在后台继续处理和保存图片.
  • 支持使用Metal渲染图像,而Metal在iOS 平台上有更好的表现.
  • 一些滤镜的性能更强劲,例如由Metal Performance Shaders支持的模糊滤镜等
  • Metal,SpriteKit,Core Animation 等更完美的配合.
  • 支持图像识别功能.包括人脸识别,条形码识别,文本识别等.
  • 支持自动增强图像效果,会分析图像的直方图,图像属性,脸部区域,然后通过一组滤镜来改善图像效果.
  • 支持对原生RAW格式图片的处理.
  • 滤镜链的性能比GPUImage高.
  • 支持对大图进行处理,超过GPU纹理限制4096 * 4096的时候,会自动拆分成几个小块处理(Automatic tiling).
    • GPUImage对大图的处理方案则是压缩图片到最大纹理限制,会导致图像质量损失.

3. GPUImage特性

  • 丰富的输入组件摄像头、图片、视频、OpenGL纹理、二进制数据、UIElement (UIView, CALayer)
  • 大量现成的内置滤镜(4大类)
    1. 颜色类(亮度、色度、饱和度、对比度、曲线、白平衡..)
    2. 图像类(仿射变换、裁剪、高斯模糊、毛玻璃效果..)
    3. 颜色混合类(差异混合、alpha混合、遮罩混合..)
    4. 效果类(像素化、素描效果、压花效果、球形玻璃效果..)
  • 丰富的输出组件UIView 、视频文件、GPU纹理、二进制数据
  • 灵活的滤镜链滤镜效果之间可以相互串联、并联,调用管理相当灵活。
  • 接口易用,滤镜和OpenGL资源的创建及使用都做了统一的封装,简单易用,并且内置了一个cache模块实现了framebuffer 的复用。
  • 线程管理OpenGLContext不是多线程安全的, GPUImage创建了专的contextQueue,所有的滤镜都会扔到统一的线程中处理。
  • 轻松实现自定义滤镜效果继承GPUImageFilter自动获得上面全部特性,无需关注上下文的环境搭建,专注于效果的核心算法实现即可。

4. 使用流程|滤镜链介绍

在 GPUImage 中,对图像数据的处理都是通过建立滤镜链来实现的。

这里就涉及到了一个类 GPUImageOutput 和一个协议 GPUImageInput

  • 对于继承了 GPUImageOutput 的类,可以理解为具备输出图像数据的能力;
  • 对于实现了 GPUImageInput 协议的类,可以理解为具备接收图像数据输入的能力。
  • 顾名思义,滤镜链作为一个链路,具有起点、中间节点和终点。根据前面的描述,
    • 滤镜链的起点应该只继承了 GPUImageOutput 类,
    • 滤镜链的终点应该只实现了 GPUImageInput 协议
    • 而对于中间的结点应该同时继承了 GPUImageOutput 类并实现了 GPUImageInput 协议,这样才具备承上启下的作用。

GPUImage的使用主要分为三部分:

  1. 滤镜链起点: 输入数据
  2. 滤镜: 处理数据
  3. 滤镜链终点: 输出数据

4.1 滤镜链起点

在 GPUImage 中,只继承了 GPUImageOutput,而没有实现 GPUImageInput 协议的类有六个,也就是说有六种类型的输入源:

  1. GPUImagePicture :

    用来处理静态图片。本质解压图片->纹理->用滤镜来进行处理.
    GPUImagePicture 通过图片来初始化,本质上是先将图片转化为 CGImageRef,然后将 CGImageRef 转化为纹理。

  2. GPUImageRawDataInput :

    二进制数据->纹理图片. CVPixelFormat
    GPUImageRawDataInput 通过二进制数据初始化,然后将二进制数据转化为纹理,在初始化的时候需要指明数据的格式(GPUPixelFormat)。

  3. GPUImageTextureInput :

    用纹理数据.
    GPUImageTextureInput 通过已经存在的纹理来初始化。既然纹理已经存在,在初始化的时候就不会重新去生成,只是将纹理的索引保存下来

  4. GPUImageUIElement :

    UIView/CAL ayer ->图像数据->纹理.
    GPUImageUIElement 可以通过 UIView 或者 CALayer 来初始化,最后都是调用 CALayerrenderInContext: 方法,将当前显示的内容绘制到 CoreGraphics 的上下文中,从而获取图像数据。然后将数据转化为纹理。简单来说就是截屏,截取当前控件的内容。

    这个类可以用来实现在视频上添加文字水印的功能。因为在 OpenGL 中不能直接进行文本的绘制,所以如果我们想把一个 UILabel 的内容添加到滤镜链里面去,使用 GPUImageUIElement 来实现是很合适的。

  5. GPUImageMovie :

    视频文件-> AVAssetReader -> 逐帧读取视频->帧数据转化成纹理->滤镜处理.AVAssetReader0utput -> CMSamplerBufferRef -> CVImageBufferRef ->CVOpenGLESTextureRef -> Texture
    GPUImageMovie 通过本地的视频来初始化。首先通过 AVAssetReader 来逐帧读取视频,然后将帧数据转化为纹理,具体的流程大概是:AVAssetReaderOutput -> CMSampleBufferRef -> CVImageBufferRef -> CVOpenGLESTextureRef -> Texture

  6. GPUImageVideoCamera :

    基于AVFundation -> didoutPutSampleBuffer
    GPUImageVideoCamera 通过相机参数来初始化,通过屏幕比例相机位置(前后置) 来初始化相机。

    这里主要使用 AVCaptureVideoDataOutput 来获取持续的视频流数据输出,在代理方法 captureOutput:didOutputSampleBuffer:fromConnection: 中可以拿到 CMSampleBufferRef ,将其转化为纹理的过程与 GPUImageMovie 类似。

  7. 子类(GPUImageStillCamera )

    我们在项目中使用的是它的子类 GPUImageStillCamera
    GPUImageStillCamera 在原来的基础上多了一个 AVCaptureStillImageOutput,它是我们实现拍照功能的关键,在 captureStillImageAsynchronouslyFromConnection:completionHandler: 方法的回调中,同样能拿到我们熟悉 CMSampleBufferRef

简单来说,GPUImageVideoCamera 只能录制视频,GPUImageStillCamera 还可以拍照, 因此我们使用 GPUImageStillCamera

4.2 滤镜(GPUImageFilter及其子类)

基类:GPUImageFilter

  • 滤镜链的关键角色是 GPUImageFilter,它同时继承了 GPUImageOutput 类并实现了 GPUImageInput 协议。GPUImageFilter 实现承上启下功能的基础是「渲染到纹理」
  • 目前GPUImage大概有200多个滤镜,这里不一一赘述.
  • 如果需要自定义滤镜,只需要一个继承于GPUImageFilter.并根据需求修改着色器程序即可.
  • GPUImage库中提供的大部分滤镜都是通过片元着色器的一系列操作来实现相应的效果
  • 大部分滤镜都是对图片中的像素进行计算产生新的像素颜色处理
  • 滤镜处理的原理:
    静态图片或者视频的每一帧进行图形变换后再显示到屏幕上,其本质就是像素点的位置和颜色的变化
  • 每一个滤镜都能把输出的纹理可以作为下一个滤镜的输入,实现多层滤镜效果的叠加(多层滤镜处理)

4.3 滤镜终点

  1. GPUImageMoviewWriter: AVAssetWriter把每-帧纹理的数据从帧缓存区->指定文件.
  2. GPUImageRawData0utput: 处理滤镜帧缓存区的二进制数据
  3. GPUImageTextureOutput
  4. GPUlmageView

在 GPUImage 中,实现了 GPUImageInput 协议,而没有继承 GPUImageOutput 的类有四个:

  • 1、GPUImageMovieWriter
    GPUImageMovieWriter 封装了 AVAssetWriter,可以逐帧从帧缓存的渲染结果中读取数据,最后通过 AVAssetWriter 将视频文件保存到指定的路径。
  • 2、GPUImageRawDataOutput
    GPUImageRawDataOutput 通过 rawBytesForImage 属性,可以获取到当前输入纹理的二进制数据。
    假设我们的滤镜链在输入源和终点之间,连接了三个滤镜,而我们需要拿到第二个滤镜渲染后的数据,用来做人脸识别。那我们可以在第二个滤镜后面再添加一个 GPUImageRawDataOutput 作为输出,则可以拿到对应的二进制数据,且不会影响原来的渲染流程。
  • 3、GPUImageTextureOutput
    这个类的实现十分简单,提供协议方法 newFrameReadyFromTextureOutput:,在每一帧渲染结束后,将自身返回,通过 texture 属性就可以拿到输入纹理的索引。
  • 4、GPUImageView
    GPUImageView 继承自 UIView,通过输入的纹理,执行一遍渲染流程。这次的渲染目标不是新的纹理,而是自身的 layer

这个类是我们实现相机功能的重要组成部分,我们所有的滤镜效果,都要依靠它来呈现。

5. 框架解析

  • GPUImage框架采用的链式( Chain )结构.
    • 主要有一个GPUImageoutput interfaceGPUImageInput protocol 串联起来.
  • GPUImageOutput负责输出纹理Texture ;
  • GPUImageInput负责输入纹理Texture ;

整个链式图像数据过程,纹理作为核心载体.

  • 当然GPUImage不仅仅适用于静态图片,还适用视频、实时拍摄等,这些不同的载体都是继承于GPUImageOutput类。
  • 基本上每一个滤镜都是继承自GPUImageFilter,而GPUImageFilter是整套框架的核心
    • GPUImageFilter接收一个GPUImageFrameBuffer输入,调用GLProgram渲染处理之后,输出一个GPUImageFrameBuffer
    • 再把输出的GPUImageFrameBuffer传给通过targets属性关联的下一级滤镜,直到传递给最终的输出组件。

6. 源码结构分析

7. 内置滤镜介绍

目前GPUImage内置了125滤镜,分为以下几类:

7.1 颜色调整

  • GPUImageBrightnessFilter : 调整图像的亮度

    • brightness:调整后的亮度(-1.0 - 1.0,默认为 0.0)
  • GPUImageExposureFilter : 调整图像的曝光

    • exposure:调整后的曝光(-10.0 - 10.0,默认为 0.0)
  • GPUImageContrastFilter : 调整图像的对比度

    • contrast:调整后的对比度(0.0 - 4.0,默认为 1.0)
  • GPUImageSaturationFilter:调整图像的饱和度

    • 饱和度:应用于图像的饱和度或去饱和度(0.0 - 2.0,默认值为 1.0)
  • GPUImageGammaFilter:调整图像的伽玛

    • gamma:要应用的 gamma 调整(0.0 - 3.0,默认值为 1.0)
  • GPUImageLevelsFilter:类似 Photoshop 的级别调整。min、max、minOut 和 maxOut 参数是 [0, 1] 范围内的浮点数。如果 Photoshop 的参数在 [0, 255] 范围内,则必须先将它们转换为 [0, 1]。gamma/mid 参数是一个 >= 0 的浮点数。这与来自 Photoshop 的值相匹配。如果您想将级别应用到 RGB 以及单个通道,您需要使用此过滤器两​​次 - 首先是单个通道,然后是所有通道。

  • GPUImageColorMatrixFilter:通过对图像应用矩阵来转换图像的颜色

    • colorMatrix :一个 4x4 矩阵,用于转换图像中的每种颜色 - intensity:新变换的颜色替换每个像素的原始颜色的程度
  • GPUImageRGBFilter:调整图像的各个 RGB 通道

    • red :每个颜色通道乘以的归一化值。范围从 0.0 开始,默认值为 1.0。 - 绿色 : - 蓝色
  • GPUImageHueFilter:调整图像的色调

    • 色调:色调角度,以度为单位。默认90度
  • GPUImageVibranceFilter:调整图像的振动

    • vibrance:要应用的 vibrance 调整,使用 0.0 作为默认值,建议的最小值/最大值分别约为 -1.2 和 1.2。
  • GPUImageWhiteBalanceFilter:调整图像的白平衡。

    • temperature :调整图像的温度,以ºK为单位。值 4000 非常凉爽,7000 非常温暖。默认值为 5000。请注意,4000 到 5000 之间的比例在视觉上几乎与 5000 到 7000 之间的比例一样重要。 - tint :调整图像的色调。值 -200非常 绿,200非常粉红色。默认值为 0。
  • GPUImageToneCurveFilter:根据每个颜色通道的样条曲线调整图像的颜色。

    • 红色控制点 : - 绿色控制点 : - 蓝色控制点 : - rgbCompositeControlPoints:色调曲线采用一系列控制点,这些控制点为每个颜色分量或合成中的所有三个分量定义样条曲线。它们在 NSArray 中存储为 NSValue-wrapped CGPoints,具有从 0 - 1 的标准化 X 和 Y 坐标。默认值为 (0,0)、(0.5,0.5)、(1,1)。
  • GPUImageHighlightShadowFilter:调整图像的阴影和高光

    • shadows :增加以减轻阴影,从 0.0 到 1.0,默认值为 0.0。 - highlights:从 1.0 到 0.0 减少以加深高光,默认值为 1.0。
  • GPUImageHighlightShadowTintFilter:允许您使用颜色和强度独立地为图像的阴影和高光着色

    • shadowTintColor :阴影色调 RGB 颜色 (GPUVector4)。默认值:({1.0f, 0.0f, 0.0f, 1.0f}红色)。 - highlightTintColor :突出显示色调 RGB 颜色 (GPUVector4)。默认值:({0.0f, 0.0f, 1.0f, 1.0f}蓝色)。 - shadowTintIntensity :阴影色调强度,从 0.0 到 1.0。默认值:0.0 - highlightTintIntensity:突出显示色调强度,从 0.0 到 1.0,默认值为 0.0。
  • GPUImageLookupFilter:使用 RGB 颜色查找图像重新映射图像中的颜色。首先,使用您最喜欢的照片编辑应用程序对来自 GPUImage/framework/Resources 的 lookup.png 应用过滤器。为了使其正常工作,每个像素颜色不得依赖于其他像素(例如,模糊将不起作用)。如果您需要更复杂的过滤器,您可以根据需要创建尽可能多的查找表。准备就绪后,使用新的 lookup.png 文件作为 GPUImageLookupFilter 的第二个输入。

  • GPUImageAmatorkaFilter :基于 Amatorka 的 Photoshop 动作的照片滤镜:http: //amatorka.deviantart.com/art/Amatorka-Action-2-121069631。如果您想使用此效果,您必须将 GPUImage Resources 文件夹中的 lookup_amatorka.png 添加到您的应用程序包中。

  • GPUImageMissEtikateFilter :基于 Miss Etikate 的 Photoshop 动作的照片滤镜:http: //miss-etikate.deviantart.com/art/Photoshop-Action-15-120151961。如果您想使用此效果,您必须将 GPUImage Resources 文件夹中的 lookup_miss_etikate.png 添加到您的应用程序包中。

  • GPUImageSoftEleganceFilter:另一个基于查找的颜色重映射过滤器。如果您想使用此效果,您必须将 GPUImage Resources 文件夹中的 lookup_soft_elegance_1.png 和 lookup_soft_elegance_2.png 添加到您的应用程序包中。

  • GPUImageSkinToneFilter:一种肤色调整滤镜,可影响独特的浅肤色范围,并相应地调整粉红色/绿色或粉红色/橙色范围。默认值针对白种人皮肤,但可以根据需要进行调整。

    • skinToneAdjust :调整肤色的量。默认值:0.0,建议的最小值/最大值:分别为 -0.3 和 0.3。 - skinHue :要检测的肤色。默认值:0.05(白种人至微红皮肤)。 - skinHueThreshold :肤色的变化量。默认值:40.0。 - maxHueShift :允许的最大色调偏移量。默认值:0.25。 - maxSaturationShift = 要移动的最大饱和度(使用橙色时)。默认值:0.4。 - upperSkinToneColor =GPUImageSkinToneUpperColorGreenGPUImageSkinToneUpperColorOrange
  • GPUImageColorInvertFilter:反转图像的颜色

  • GPUImageGrayscaleFilter:将图像转换为灰度(饱和度过滤器的实现速度稍快,但无法改变颜色贡献)

  • GPUImageMonochromeFilter:根据每个像素的亮度将图像转换为单色版本

    • intensity : 特定颜色替代正常图像颜色的程度(0.0 - 1.0,默认为 1.0) - color:用作效果基础的颜色,默认值为 (0.6, 0.45, 0.3, 1.0)。
  • GPUImageFalseColorFilter:使用图像的亮度在两种用户指定的颜色之间进行混合

    • firstColor :第一种和第二种颜色分别指定用什么颜色替换图像的暗区和亮区。默认值是 (0.0, 0.0, 0.5) 和 (1.0, 0.0, 0.0)。 - 第二颜色
  • GPUImageHazeFilter:用于添加或去除雾度(类似于 UV 过滤器)

    • distance : 应用颜色的强度。默认值 0。最佳值介于 -.3 和 .3 之间。 - 斜率:颜色变化量。默认值 0。最佳值介于 -.3 和 .3 之间。
  • GPUImageSepiaFilter : 简单的棕褐色调滤镜

    • intensity:棕褐色调替换正常图像颜色的程度(0.0 - 1.0,默认值为 1.0)
  • GPUImageOpacityFilter:调整传入图像的 alpha 通道

    • 不透明度:将每个像素的传入 alpha 通道乘以的值(0.0 - 1.0,默认值为 1.0)
  • GPUImageSolidColorGenerator:这会输出具有纯色的生成图像。您需要使用 -forceProcessingAtSize 定义图像大小:

    • color:用于填充图像的颜色,采用四分量格式。
  • GPUImageLuminanceThresholdFilter:亮度高于阈值的像素将显示为白色,低于阈值的像素将显示为黑色

    • threshold : 亮度阈值,从0.0到1.0,默认为0.5
  • GPUImageAdaptiveThresholdFilter:确定像素周围的局部亮度,如果低于该局部亮度则将像素变为黑色,如果高于该亮度则将像素变为白色。这对于在不同光照条件下挑选文本很有用。

    • blurRadiusInPixels:背景平均模糊半径的乘数(以像素为单位),默认值为 4。
  • GPUImageAverageLuminanceThresholdFilter:这应用了阈值操作,其中阈值根据场景的平均亮度不断调整。

    • thresholdMultiplier:这是一个因子,平均亮度将乘以该因子以达到要使用的最终阈值。默认情况下,这是 1.0。
  • GPUImageHistogramFilter:\ This analyzes the incoming image and creates an output histogram with the frequency at which each color value occurs. The output of this filter is a 3-pixel-high, 256-pixel-wide image with the center (vertical) pixels containing pixels that correspond to the frequency at which various color values occurred. Each color value occupies one of the 256 width positions, from 0 on the left to 255 on the right. This histogram can be generated for individual color channels (kGPUImageHistogramRed, kGPUImageHistogramGreen, kGPUImageHistogramBlue), the luminance of the image (kGPUImageHistogramLuminance), or for all three color channels at once (kGPUImageHistogramRGB).

    • downsamplingFactor:这不是对每个像素进行采样,而是指示对图像的哪一部分进行采样。默认情况下,这是 16,最小值为 1。这是防止直方图饱和所必需的,直方图在过载之前只能为每个颜色值记录 256 个像素。
  • GPUImageHistogramGenerator:这是一个特殊的过滤器,因为它主要用于与 GPUImageHistogramFilter 一起使用。它生成由 GPUImageHistogramFilter 生成的颜色直方图的输出表示,但它可以重新用于显示其他类型的值。它接收图像并查看中心(垂直)像素。然后它在输出纹理的单独彩色图表中绘制 RGB 分量的数值。您可能需要为此过滤器强制调整大小以使其输出可见。

  • GPUImageAverageColor:这会处理输入图像并通过平均图像中每个像素的 RGBA 分量来确定场景的平均颜色。缩减过程用于在 GPU 上逐步对源图像进行下采样,然后在 CPU 上进行短暂的平均计算。此过滤器的输出没有意义,但您需要将 colorAverageProcessingFinishedBlock 属性设置为一个块,该块接收四个颜色分量和一个帧时间并对它们执行某些操作。

  • GPUImageLuminosity:与 GPUImageAverageColor 一样,这会将图像降低到其平均亮度。您需要设置 luminosityProcessingFinishedBlock 来处理这个过滤器的输出,它只返回一个亮度值和一个帧时间。

  • GPUImageChromaKeyFilter:对于图像中的给定颜色,将 alpha 通道设置为 0。这类似于 GPUImageChromaKeyBlendFilter,只是不是混合第二张图像以获得匹配的颜色,它不会接收第二张图像,只是将给定的颜色透明。

    • thresholdSensitivity :颜色匹配需要与要替换的目标颜色有多接近(默认为 0.4) - smoothing:颜色匹配的平滑度(默认为 0.1)

7.2 图像处理

  • GPUImageTransformFilter:这对图像应用任意 2-D 或 3-D 转换

    • affineTransform :这需要一个 CGAffineTransform 来调整二维图像 - transform3D :这需要一个 CATransform3D 来操作 3-D 图像 - ignoreAspectRatio:默认情况下,变换图像的纵横比保持不变,但可以将其设置为 YES 以使变换与纵横比无关
  • GPUImageCropFilter:将图像裁剪到特定区域,然后仅将该区域传递到过滤器的下一个阶段

    • cropRegion:要从图像中裁剪的矩形区域,标准化为 0.0 - 1.0 之间的坐标。(0.0, 0.0) 位置在图像的左上角。
  • GPUImageLanczosResamplingFilter:这使您可以使用 Lanczos 重采样对图像进行上采样或下采样,从而产生比标准线性或三线性插值明显更好的质量。只需使用 -forceProcessingAtSize: 设置过滤器的目标输出分辨率,图像将根据新尺寸重新采样。

  • GPUImageSharpenFilter:锐化图像

    • 清晰度:要应用的清晰度调整(-4.0 - 4.0,默认值为 0.0)
  • GPUImageUnsharpMaskFilter:应用反锐化蒙版

    • blurRadiusInPixels :底层高斯模糊的模糊半径。默认值为 4.0。 - intensity : 锐化的强度,从 0.0 开始,默认为 1.0
  • GPUImageGaussianBlurFilter:硬件优化的可变半径高斯模糊

    • texelSpacingMultiplier :纹素之间间距的乘数,范围从 0.0 开始,默认值为 1.0。调整此项可能会略微增加模糊强度,但会在结果中引入伪影。强烈建议先使用其他参数,然后再接触这个参数。 - blurRadiusInPixels :用于模糊的半径(以像素为单位),默认值为 2.0。这会调整高斯分布函数中的 sigma 变量。 - 模糊半径作为图像宽度的分数 : - blurRadiusAsFractionOfImageHeight :设置这些属性将允许模糊半径随图像大小缩放 - blurPasses:顺序模糊传入图像的次数。通过的次数越多,过滤器越慢。
  • GPUImageBoxBlurFilter:硬件优化的可变半径框模糊

    • texelSpacingMultiplier :纹素之间间距的乘数,范围从 0.0 开始,默认值为 1.0。调整此项可能会略微增加模糊强度,但会在结果中引入伪影。强烈建议先使用其他参数,然后再接触这个参数。 - blurRadiusInPixels :用于模糊的半径(以像素为单位),默认值为 2.0。这会调整高斯分布函数中的 sigma 变量。 - 模糊半径作为图像宽度的分数 : - blurRadiusAsFractionOfImageHeight :设置这些属性将允许模糊半径随图像大小缩放 - blurPasses:顺序模糊传入图像的次数。通过的次数越多,过滤器越慢。
  • GPUImageSingleComponentGaussianBlurFilter:对 GPUImageGaussianBlurFilter 的修改,仅对红色分量进行操作

    • texelSpacingMultiplier :纹素之间间距的乘数,范围从 0.0 开始,默认值为 1.0。调整此项可能会略微增加模糊强度,但会在结果中引入伪影。强烈建议先使用其他参数,然后再接触这个参数。 - blurRadiusInPixels :用于模糊的半径(以像素为单位),默认值为 2.0。这会调整高斯分布函数中的 sigma 变量。 - 模糊半径作为图像宽度的分数 : - blurRadiusAsFractionOfImageHeight :设置这些属性将允许模糊半径随图像大小缩放 - blurPasses:顺序模糊传入图像的次数。通过的次数越多,过滤器越慢。
  • GPUImageGaussianSelectiveBlurFilter:将焦点保留在圆形区域内的高斯模糊

    • blurRadiusInPixels :用于模糊的半径(以像素为单位),默认值为 5.0。这会调整高斯分布函数中的 sigma 变量。 - excludeCircleRadius :从模糊中排除的圆形区域的半径 - excludeCirclePoint :从模糊中排除的圆形区域的中心 - excludeBlurSize : 模糊部分和清晰圆圈之间的区域大小 - aspectRatio:图像的纵横比,用于调整对焦区域的圆度。默认情况下,这与图像纵横比匹配,但您可以覆盖该值。
  • GPUImageGaussianBlurPositionFilter : GPUImageGaussianSelectiveBlurFilter 的逆函数,仅在特定圆圈内应用模糊

    • blurSize :模糊大小的乘数,范围从 0.0 到 up,默认值为 1.0 - blurCenter : 模糊中心,默认为 0.5, 0.5 - blurRadius : 模糊的半径,默认为 1.0
  • GPUImageiOSBlurFilter:尝试在控制中心等位置复制 iOS 7 上使用的背景模糊。

    • blurRadiusInPixels :用于模糊的半径(以像素为单位),默认值为 12.0。这会调整高斯分布函数中的 sigma 变量。 - 饱和度 :饱和度范围从 0.0(完全去饱和)到 2.0(最大饱和度),0.8 为正常水平 - 下采样:下采样的程度,然后对输入图像进行上采样以最小化高斯模糊内的计算,默认值为 4.0。
  • GPUImageMedianFilter:在 3x3 区域上取三个颜色分量的中值

  • GPUImageBilateralFilter:双边模糊,它试图模糊相似的颜色值,同时保留锐利的边缘

    • texelSpacingMultiplier : 纹素读取间距的倍数,范围从 0.0 到上,默认为 4.0 - distanceNormalizationFactor:中心颜色和样本颜色之间距离的归一化因子,默认值为 8.0。
  • GPUImageTiltShiftFilter:模拟倾斜移位镜头效果

    • blurRadiusInPixels :底层模糊的半径,以像素为单位。默认情况下为 7.0。 - topFocusLevel : 对焦区域顶部在图像中的归一化位置,该值应低于 bottomFocusLevel,默认 0.4 - bottomFocusLevel : 对焦区域底部在图像中的归一化位置,该值应高于 topFocusLevel,默认 0.6 - focusFallOffRate:图像远离对焦区域变得模糊的速率,默认 0.2
  • GPUImage3x3ConvolutionFilter:对图像运行 3x3 卷积核

    • convolutionKernel:卷积核是一个 3x3 值矩阵,应用于像素及其周围的 8 个像素。矩阵按行优先顺序指定,左上角的像素为 one.one,右下角的像素为 three.three。如果矩阵中的值加起来不等于 1.0,图像可能会变亮或变暗。
  • GPUImageSobelEdgeDetectionFilter:索贝尔边缘检测,边缘以白色突出显示

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - edgeStrength:调整过滤器的动态范围。较高的值会导致更强的边缘,但会使强度色彩空间饱和。默认值为 1.0。
  • GPUImagePrewittEdgeDetectionFilter : Prewitt 边缘检测,边缘以白色突出显示

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - edgeStrength:调整过滤器的动态范围。较高的值会导致更强的边缘,但会使强度色彩空间饱和。默认值为 1.0。
  • GPUImageThresholdEdgeDetectionFilter:执行 Sobel 边缘检测,但应用阈值而不是提供渐变强度值

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - edgeStrength :调整过滤器的动态范围。较高的值会导致更强的边缘,但会使强度色彩空间饱和。默认值为 1.0。 - threshold:任何高于此阈值的边缘都将是黑色的,任何低于该阈值的边缘都是白色的。范围从 0.0 到 1.0,默认值为 0.8
  • GPUImageCannyEdgeDetectionFilter:这使用完整的 Canny 过程来突出显示一个像素宽的边缘

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - blurRadiusInPixels :高斯模糊的基础模糊半径。默认值为 2.0。 - blurTexelSpacingMultiplier :底层模糊纹素间距乘数。默认值为 1.0。 - upperThreshold :任何梯度幅度高于此阈值的边缘都将通过并显示在最终结果中。默认值为 0.4。 - lowerThreshold:梯度幅值低于此阈值的任何边缘都将失败并从最终结果中删除。默认值为 0.1。
  • GPUImageHarrisCornerDetectionFilter:在输入图像上运行 Harris 角点检测算法,并生成一个图像,其中这些角点为白色像素,其他所有像素为黑色。可以设置 cornersDetectedBlock,您将在该回调中获得一个角列表(在标准化的 0..1 X,Y 坐标中),用于您想要执行的任何其他操作。

    • blurRadiusInPixels :底层高斯模糊的半径。默认值为 2.0。 - sensitivity :一个内部比例因子,用于调整过滤器中生成的转角图的动态范围。默认值为 5.0。 - threshold:点被检测为角点的阈值。这可能会根据尺寸、照明条件和 iOS 设备相机类型而有很大差异,因此可能需要进行一些试验才能适合您的情况。默认值为 0.20。
  • GPUImageNobleCornerDetectionFilter:在 Harris 角检测器上运行 Noble 变体。它的行为与上述 Harris 检测器相同。

    • blurRadiusInPixels :底层高斯模糊的半径。默认值为 2.0。 - sensitivity :一个内部比例因子,用于调整过滤器中生成的转角图的动态范围。默认值为 5.0。 - threshold:点被检测为角点的阈值。这可能会根据尺寸、照明条件和 iOS 设备相机类型而有很大差异,因此可能需要进行一些试验才能适合您的情况。默认值为 0.2。
  • GPUImageShiTomasiCornerDetectionFilter:运行 Shi-Tomasi 特征检测器。它的行为与上述 Harris 检测器相同。

    • blurRadiusInPixels :底层高斯模糊的半径。默认值为 2.0。 - sensitivity :一个内部比例因子,用于调整过滤器中生成的转角图的动态范围。默认值为 1.5。 - threshold:点被检测为角点的阈值。这可能会根据尺寸、照明条件和 iOS 设备相机类型而有很大差异,因此可能需要进行一些试验才能适合您的情况。默认值为 0.2。
  • GPUImageNonMaximumSuppressionFilter:目前仅用作 Harris 角点检测过滤器的一部分,这将对每个像素周围的 1 像素框进行采样,并确定中心像素的红色通道是否是该区域的最大值。如果是,它会留下来。如果不是,则将所有颜色分量设置为 0。

  • GPUImageXYDerivativeFilter:Harris 角点检测过滤器中的一个内部组件,计算该像素左右像素的平方差、该像素上下像素的平方差,以及这两个差的乘积。

  • GPUImageCrosshairGenerator:这会在图像上绘制一系列十字准线,最常用于识别机器视觉特征。它不像其他滤镜那样接收标准图像,而是接收其 -renderCrosshairsFromArray:count: 方法中的一系列点,该方法执行实际绘图。您将需要强制此过滤器以您需要的特定输出大小呈现。

    • crosshairWidth:要在屏幕上绘制的十字准线的宽度(以像素为单位)。
  • GPUImageDilationFilter:这执行图像膨胀操作,其中矩形邻域中红色通道的最大强度用于该像素的强度。要采样的矩形区域的半径在初始化时指定,范围为 1-4 像素。这是为了与灰度图像一起使用,它扩展了明亮的区域。

  • GPUImageRGBDilationFilter:这与 GPUImageDilationFilter 相同,只是它作用于所有颜色通道,而不仅仅是红色通道。

  • GPUImageErosionFilter:这执行图像侵蚀操作,其中矩形邻域中红色通道的最小强度用于该像素的强度。要采样的矩形区域的半径在初始化时指定,范围为 1-4 像素。这是为了与灰度图像一起使用,它扩展了黑暗区域。

  • GPUImageRGBErosionFilter:这与 GPUImageErosionFilter 相同,只是它作用于所有颜色通道,而不仅仅是红色通道。

  • GPUImageOpeningFilter:这对图像的红色通道执行腐蚀,然后是相同半径的膨胀。半径在初始化时设置,范围为 1-4 像素。这会过滤掉较小的明亮区域。

  • GPUImageRGBOpeningFilter:这与 GPUImageOpeningFilter 相同,除了它作用于所有颜色通道,而不仅仅是红色通道。

  • GPUImageClosingFilter:这对图像的红色通道执行膨胀,然后是相同半径的腐蚀。半径在初始化时设置,范围为 1-4 像素。这会过滤掉较小的暗区。

  • GPUImageRGBClosingFilter:这与 GPUImageClosingFilter 相同,只是它作用于所有颜色通道,而不仅仅是红色通道。

  • GPUImageLocalBinaryPatternFilter:这对周围 8 个像素的红色通道与中心像素的红色通道的强度进行比较,将比较结果编码为成为该像素强度的位串。最不重要的位是右上角的比较,逆时针旋转到最右边的比较结束。

  • GPUImageLowPassFilter:这对传入的视频帧应用低通滤波器。这基本上是累积先前帧与当前帧的加权滚动平均值。这可用于视频降噪、添加运动模糊或用于创建高通滤波器。

    • filterStrength:这控制了以前累积的帧与当前帧混合的程度。范围从 0.0 到 1.0,默认值为 0.5。
  • GPUImageHighPassFilter:这对传入的视频帧应用高通滤波器。这是低通滤波器的逆过程,显示当前帧与之前帧的加权滚动平均值之间的差异。这对于运动检测最有用。

    • filterStrength:这控制了先前累积帧混合的程度,然后从当前帧中减去。范围从 0.0 到 1.0,默认值为 0.5。
  • GPUImageMotionDetector:这是一个基于高通滤波器的运动检测器。您设置 motionDetectionBlock 并在每个传入帧上为您提供场景中任何检测到的运动的质心(在标准化的 X、Y 坐标中)以及场景的运动强度。

    • lowPassFilterStrength:它控制在幕后使用的低通滤波器的强度,以建立与传入帧进行比较的基线。范围从 0.0 到 1.0,默认值为 0.5。
  • GPUImageHoughTransformLineDetector :使用 Hough 变换到平行坐标空间来检测图像中的线。这种方法完全基于 PC 线过程,该过程由布尔诺科技大学的 Graph@FIT 研究小组开发,并在他们的出版物中进行了描述:M. Dubská、J. Havel 和 A. Herout。使用平行坐标和 OpenGL 实时检测线。SCCG 2011 会议记录,布拉迪斯拉发,SK,p. 7 ( medusa.fit.vutbr.cz/public/data... ) 和 M. Dubská, J . 哈维尔和A.赫鲁特。PClines - 使用平行坐标的线检测。2011 年 IEEE 计算机视觉和模式识别会议 (CVPR),p. 1489- 1494 (medusa.fit.vutbr.cz/public/data...).

    • edgeThreshold :一个阈值,对于该阈值,点被检测为属于用于确定线的边缘。默认值为 0.9。 - lineDetectionThreshold :检测到局部最大值属于平行坐标空间中的一条线的阈值。默认值为 0.20。 - linesDetectedBlock:此块在检测线时调用,通常在每个处理过的帧上调用。包含 m、b 对 (y=mx+b) 中的归一化斜率和截距的 AC 数组被传入,以及检测到的行数计数和视频帧的当前时间戳。
  • GPUImageLineGenerator:生成可以覆盖场景的线条的辅助类。可以使用 -setLineColorRed:green:blue 调整这些线条的颜色:

    • lineWidth:线条的宽度,以像素为单位,默认为 1.0。
  • GPUImageMotionBlurFilter:对图像应用定向运动模糊

    • blurSize :模糊大小的乘数,范围从 0.0 到 up,默认值为 1.0 - blurAngle:模糊的角度方向,以度为单位。默认为 0 度。
  • GPUImageZoomBlurFilter:对图像应用定向运动模糊

    • blurSize :模糊大小的乘数,范围从 0.0 到 up,默认值为 1.0 - blurCenter:模糊的归一化中心。(0.5, 0.5) 默认

7.3 混合模式

  • GPUImageChromaKeyBlendFilter:有选择地用第二张图像替换第一张图像中的颜色

    • thresholdSensitivity :颜色匹配需要与要替换的目标颜色有多接近(默认为 0.4) - smoothing:颜色匹配的平滑度(默认为 0.1)
  • GPUImageDissolveBlendFilter:应用两个图像的溶解混合

    • mix:第二个图像覆盖第一个图像的程度(0.0 - 1.0,默认为 0.5)
  • GPUImageMultiplyBlendFilter:应用两个图像的乘法混合

  • GPUImageAddBlendFilter:应用两个图像的加法混合

  • GPUImageSubtractBlendFilter:应用两个图像的减法混合

  • GPUImageDivideBlendFilter:应用两个图像的分割混合

  • GPUImageOverlayBlendFilter:应用两个图像的叠加混合

  • GPUImageDarkenBlendFilter:通过取图像之间每个颜色分量的最小值来混合两个图像

  • GPUImageLightenBlendFilter:通过取图像之间每个颜色分量的最大值来混合两个图像

  • GPUImageColorBurnBlendFilter:应用两个图像的颜色加深混合

  • GPUImageColorDodgeBlendFilter:应用两个图像的颜色减淡混合

  • GPUImageScreenBlendFilter:应用两个图像的屏幕混合

  • GPUImageExclusionBlendFilter:应用两个图像的排除混合

  • GPUImageDifferenceBlendFilter:应用两个图像的差异混合

  • GPUImageHardLightBlendFilter:应用两个图像的强光混合

  • GPUImageSoftLightBlendFilter:应用两个图像的柔光混合

  • GPUImageAlphaBlendFilter:根据第二个的 alpha 通道将第二个图像混合到第一个图像上

    • mix:第二个图像覆盖第一个图像的程度(0.0 - 1.0,默认值为 1.0)
  • GPUImageSourceOverBlendFilter:在两个图像的混合上应用源

  • GPUImageColorBurnBlendFilter:应用两个图像的颜色加深混合

  • GPUImageColorDodgeBlendFilter:应用两个图像的颜色减淡混合

  • GPUImageNormalBlendFilter:应用两个图像的正常混合

  • GPUImageColorBlendFilter:应用两个图像的颜色混合

  • GPUImageHueBlendFilter:应用两个图像的色调混合

  • GPUImageSaturationBlendFilter:应用两个图像的饱和度混合

  • GPUImageLuminosityBlendFilter:应用两个图像的光度混合

  • GPUImageLinearBurnBlendFilter:应用两个图像的线性加深混合

  • GPUImagePoissonBlendFilter:应用两个图像的泊松混合

    • mix :混合范围从 0.0(仅图像 1)到 1.0(仅图像 2 渐变),1.0 为正常级别 - numIterations:传播梯度的次数。如果您想接近收敛,可以将其调到 100 甚至 1000。是的,这会很慢。
  • GPUImageMaskFilter:使用另一个图像遮盖一个图像

7.4 视觉效果

  • GPUImagePixellateFilter:对图像或视频应用像素化效果

    • fractionalWidthOfAPixel:像素有多大,作为图像宽度和高度的分数(0.0 - 1.0,默认 0.05)
  • GPUImagePolarPixellateFilter:基于极坐标而不是笛卡尔坐标对图像或视频应用像素化效果

    • center : 应用像素化的中心,默认为 (0.5, 0.5) - pixelSize:分数像素大小,分为宽度和高度分量。默认值为 (0.05, 0.05)
  • GPUImagePolkaDotFilter:将图像分解为规则网格内的彩色点

    • fractionalWidthOfAPixel :点有多大,作为图像宽度和高度的一部分(0.0 - 1.0,默认 0.05) - dotScaling:每个网格空间被点占用的比例,从 0.0 到 1.0,默认值为 0.9。
  • GPUImageHalftoneFilter:对图像应用半色调效果,如新闻印刷

    • fractionalWidthOfAPixel:半色调点有多大,作为图像宽度和高度的分数(0.0 - 1.0,默认 0.05)
  • GPUImageCrosshatchFilter:这会将图像转换为黑白交叉影线图案

    • crossHatchSpacing :用作剖面线间距的图像的小数宽度。默认值为 0.03。 - lineWidth:交叉影线的相对宽度。默认值为 0.003。
  • GPUImageSketchFilter:将视频转换为草图。这只是颜色反转的 Sobel 边缘检测滤波器

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - edgeStrength:调整过滤器的动态范围。较高的值会导致更强的边缘,但会使强度色彩空间饱和。默认值为 1.0。
  • GPUImageThresholdSketchFilter : 和素描滤镜一样,只是对边缘进行阈值处理,而不是灰度化

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - edgeStrength :调整过滤器的动态范围。较高的值会导致更强的边缘,但会使强度色彩空间饱和。默认值为 1.0。 - threshold:任何高于此阈值的边缘都将是黑色的,任何低于该阈值的边缘都是白色的。范围从 0.0 到 1.0,默认值为 0.8
  • GPUImageToonFilter:这使用 Sobel 边缘检测在对象周围放置黑色边框,然后它量化图像中存在的颜色以赋予图像类似卡通的质量。

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - threshold :边缘检测的灵敏度,值越小越灵敏。范围从 0.0 到 1.0,默认值为 0.2 - quantizationLevels:最终图像中要表示的颜色级别数。默认值为 10.0
  • GPUImageSmoothToonFilter:这使用与 GPUImageToonFilter 类似的过程,只是它在卡通效果之前使用高斯模糊来平滑噪声。

    • 纹素宽度 : - texelHeight :这些参数影响检测到的边缘的可见性 - blurRadiusInPixels :底层高斯模糊的半径。默认值为 2.0。 - threshold :边缘检测的灵敏度,值越小越灵敏。范围从 0.0 到 1.0,默认值为 0.2 - quantizationLevels:最终图像中要表示的颜色级别数。默认值为 10.0
  • GPUImageEmbossFilter:对图像应用浮雕效果

    • intensity : 压花的强度,从 0.0 到 4.0,1.0 为正常水平
  • GPUImagePosterizeFilter:这会将颜色动态范围减少到指定的步数,从而使图像具有卡通般的简单阴影。

    • colorLevels:将图像空间缩小到的颜色级别数。范围从 1 到 256,默认值为 10。
  • GPUImageSwirlFilter:在图像上创建漩涡失真

    • radius :从中心开始应用扭曲的半径,默认值为 0.5 - center :图像的中心(在 0 - 1.0 的标准化坐标中)围绕其旋转,默认值为 (0.5, 0.5) - angle:应用于图像的扭曲量,默认值为 1.0
  • GPUImageBulgeDistortionFilter:在图像上创建凸起失真

    • radius :从中心开始应用扭曲的半径,默认值为 0.25 - center :图像的中心(在 0 - 1.0 的规范化坐标中)围绕其扭曲,默认值为 (0.5, 0.5) - scale:要应用的失真量,从 -1.0 到 1.0,默认值为 0.5
  • GPUImagePinchDistortionFilter:创建图像的收缩失真

    • radius :从中心开始应用扭曲的半径,默认值为 1.0 - center :图像的中心(在 0 - 1.0 的规范化坐标中)围绕其扭曲,默认值为 (0.5, 0.5) - scale:要应用的失真量,从 -2.0 到 2.0,默认值为 1.0
  • GPUImageStretchDistortionFilter:创建图像的拉伸失真

    • center:图像的中心(在 0 - 1.0 的规范化坐标中)围绕其扭曲,默认值为 (0.5, 0.5)
  • GPUImageSphereRefractionFilter:模拟通过玻璃球体的折射

    • center :应用扭曲的中心,默认值为 (0.5, 0.5) - radius :扭曲的半径,范围从0.0到1.0,默认为0.25 - refractiveIndex:球体的折射率,默认值为 0.71
  • GPUImageGlassSphereFilter : 与 GPUImageSphereRefractionFilter 相同,只是图像没有反转,玻璃边缘有一点点磨砂

    • center :应用扭曲的中心,默认值为 (0.5, 0.5) - radius :扭曲的半径,范围从0.0到1.0,默认为0.25 - refractiveIndex:球体的折射率,默认值为 0.71
  • GPUImageVignetteFilter:执行渐晕效果,在边缘淡出图像

    • vignetteCenter : tex 坐标 (CGPoint) 中小插图的中心,默认值为 0.5, 0.5 - vignetteColor :用于小插图的颜色(GPUVector3),默认为黑色 - vignetteStart :距离晕影效果开始的中心的归一化距离,默认值为 0.5 - vignetteEnd:与晕影效果结束的中心的归一化距离,默认值为 0.75
  • GPUImageKuwaharaFilter:Kuwahara 图像抽象,取自 Kyprianidis 等人的作品。阿尔。在 GPU Pro 系列中的出版物"GPU 上的各向异性 Kuwahara 过滤"中。这会生成类似油画的图像,但计算量极大,因此在 iPad 2 上渲染帧可能需要几秒钟。这可能最适合静态图像。

    • radius:在整数中,指定在应用过滤器时要测试的中心像素的像素数,默认值为 4。更高的值创建更抽象的图像,但以更长的处理时间为代价。
  • GPUImageKuwaharaRadius3Filter:Kuwahara 过滤器的修改版本,经过优化以仅在三个像素的半径范围内工作

  • GPUImagePerlinNoiseFilter:生成充满 Perlin 噪声的图像

    • 颜色开始 : - colorFinish :正在生成的噪声的颜色范围 - scale:生成的噪声的缩放比例
  • GPUImageCGAColorspaceFilter : 模拟 CGA 显示器的色彩空间

  • GPUImageMosaicFilter:此过滤器采用输入图块集,图块的亮度必须上升。它会查看输入图像,并根据输入图块的亮度用输入图块替换每个显示图块。这个想法是复制在其他应用程序中看到的 ASCII 视频过滤器,但 tileset 可以是任何东西。

    • 输入图块大小 : - 瓷砖数 : - 显示图块大小 : - 上色
  • GPUImageJFAVoronoiFilter:生成 Voronoi 映射,供后期使用。

    • sizeInPixels:单个元素的大小
  • GPUImageVoronoiConsumerFilter:接受 Voronoi 地图,并使用它来过滤传入的图像。

    • sizeInPixels:单个元素的大小

如上所述,您还可以使用类似 C 的 OpenGL 着色语言轻松编写自己的自定义滤镜。

8. 自定义滤镜

8.1 基于原有的滤镜进行多个滤镜组合

我们创建一个 继承自 GPUImageFilterGroup的类,往内部提前设置好我们想要组合的滤镜对象.调好参数即可

objc 复制代码
#import <GPUImage/GPUImageFilterGroup.h>

@interface HPBeautifulGPUBaseImageFilter : GPUImageFilterGroup

@end
#import "HPBeautifulGPUBaseImageFilter.h"

@implementation HPBeautifulGPUBaseImageFilter
- (instancetype)init
{
    self = [super init];
    if (self) {
        [self addFilter:<#(GPUImageOutput<GPUImageInput> *)#>]
        [self addFilter:<#(GPUImageOutput<GPUImageInput> *)#>]
        [self addFilter:<#(GPUImageOutput<GPUImageInput> *)#>]
        ...
    }
    return self;
}

@end

8.2 基于滤镜基类GPUImageFilter

基于滤镜基类GPUImageFilter,则是通过创建一个新的滤镜类继承自GPUImageFilter,重新编写着色器程序;

举例说明:

objc 复制代码
#import <GPUImage/GPUImageFilter.h>
NSString * const kHPGPUImageLightFilterShaderString = SHADER_STRING
(
 precision highp float;
 
 uniform sampler2D inputImageTexture;
 varying vec2 textureCoordinate;
 
 uniform float time;
 const vec2 TextureCoordsVarying = vec2(400.0, 400.0);
 const vec2 TexSize = vec2(400.0, 400.0);
 const vec2 mosaicSize = vec2(16.0, 16.0);
 
 void main (void) {
    
     vec2 intXY = vec2(TextureCoordsVarying.x*TexSize.x, TextureCoordsVarying.y*TexSize.y);
     
     vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x,floor(intXY.y/mosaicSize.y)*mosaicSize.y) + 0.5*mosaicSize;
     
     vec2 delXY = XYMosaic - intXY;
     float delL = length(delXY);
     vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x,XYMosaic.y/TexSize.y);
     
     vec4 _finalColor;
     if(delL< 0.5*mosaicSize.x)
        _finalColor = texture2D(Texture,UVMosaic);
     else
        _finalColor = texture2D(Texture,TextureCoordsVarying);
     
     gl_FragColor = _finalColor;
 }
 
 );


@interface NewImageFilter : GPUImageFilter
@end 
@implementation NewImageFilter 
- (instancetype)init {
    self = [super initWithFragmentShaderFromString:kHPGPUImageLightFilterShaderString];
    return self;
}
@end

这里的kHPGPUImageLightFilterShaderString就是新写的着色器程序,是基于GLSL语言编写的。

因此,我们要自定义滤镜,还要学GLSL语言(后面回顾OPenGL ES 的时候 会重点关注)

9. 示例代码

给静态图添加滤镜

objc 复制代码
    //1.获取图片
    _myImage = [UIImage imageNamed:@"my.jpeg"];
    //2.初始化饱和度滤镜
    _disFilter = [[GPUImageSaturationFilter alloc]init];
    //设置饱和度值
    _disFilter.saturation = 1.0;
    //设置要渲染的区域 --图片大小
    [_disFilter forceProcessingAtSize:_myImage.size];
    //使用单个滤镜
    [_disFilter useNextFrameForImageCapture];
    
    //3.创建图片组件--输入数据(静态图片)
    GPUImagePicture *stillImageSoucer = [[GPUImagePicture alloc]initWithImage:_myImage];
    //为图片添加一个滤镜
    [stillImageSoucer addTarget:_disFilter];
    //处理数据(图片)
    [stillImageSoucer processImage];
    
    //4.处理完成,从FrameBuffer帧缓存区中获取图片--输出数据
    UIImage *newImage = [_disFilter imageFromCurrentFramebuffer];
    
    //更新图片
    _myImagView.image = newImage;

文章推荐

GPUImage的 实战,我推荐几篇文章:

GPUImage2 内置滤镜介绍推荐:

相关推荐
DisonTangor13 小时前
苹果发布iOS 18.2首个公测版:Siri接入ChatGPT、iPhone 16拍照按钮有用了
ios·chatgpt·iphone
- 羊羊不超越 -13 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
2401_865854881 天前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
HackerTom2 天前
iOS用rime且导入自制输入方案
ios·iphone·rime
良技漫谈2 天前
Rust移动开发:Rust在iOS端集成使用介绍
后端·程序人生·ios·rust·objective-c·swift
2401_852403552 天前
高效管理iPhone存储:苹果手机怎么删除相似照片
ios·智能手机·iphone
星际码仔2 天前
【动画图解】是怎样的方法,能被称作是 Flutter Widget 系统的核心?
android·flutter·ios
emperinter2 天前
WordCloudStudio:AI生成模版为您的文字云创意赋能 !
图像处理·人工智能·macos·ios·信息可视化·iphone
关键帧Keyframe2 天前
音视频面试题集锦第 8 期
ios·音视频开发·客户端
pb82 天前
引入最新fluwx2.5.4的时候报错
flutter·ios