Core Image处理并渲染为可显示图像流程分析
Core Image处理并渲染为可显示图像流程分析

Core Image处理并渲染为可显示图像流程分析

本文分析的步骤主要是围绕CIFilter渲染滤镜后,从CIFilter逐步渲染为UIImaged的步骤,因为是常用的渲染输出流程,因此拿出来单独进行分析。

示例代码

struct ContentView: View {
    var body: some View {
        if let image = applyBlurEffect(to: UIImage(named: "example")) {
            Image(uiImage: image)
                .resizable()
                .scaledToFit()
        }
    }

    func applyBlurEffect(to inputImage: UIImage?) -> UIImage? {
        guard let inputImage = inputImage else { return nil }
        let ciImage = CIImage(image: inputImage)
        
        // 创建模糊滤镜
        let filter = CIFilter.twirlDistortion()
        filter.inputImage = ciImage
        filter.center = CGPoint(x: 500, y: 500)
        filter.radius = 300
        filter.angle = 3.14
        // 渲染滤镜效果
        let context = CIContext()
        if let outputImage = filter.outputImage,
           let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
            return UIImage(cgImage: cgImage)
        }
        return nil
    }
}

上述代码实现了一张经过“扭曲失真”滤镜处理的图片。

View视图

var body: some View {
    if let image = applyBlurEffect(to: UIImage(named: "example")) {
        Image(uiImage: image)
            .resizable()
            .scaledToFit()
    }
}

在View视图中,创建Image临时变量并调用applyBlurEffect方法,将UImage(named:”example”)传入该方法中,如果该方法正常返回内容,则会被赋值给image,并通过Image(uiImage:)显示处理后的图片。

applyBlurEffect方法

此方法对传入的图片应用 “扭曲失真” 滤镜并返回处理后的图片。

func applyBlurEffect(to inputImage: UIImage?) -> UIImage? {
    guard let inputImage = inputImage else { return nil }
    let ciImage = CIImage(image: inputImage)
    
    // 创建模糊滤镜
    let filter = CIFilter.twirlDistortion()
    filter.inputImage = ciImage
    filter.center = CGPoint(x: 500, y: 500)
    filter.radius = 300
    filter.angle = 3.14
    // 渲染滤镜效果
    let context = CIContext()
    if let outputImage = filter.outputImage,
       let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
        return UIImage(cgImage: cgImage)
    }
    return nil
}

1、检查输入图片是否存在

guard let inputImage = inputImage else { return nil }

如果 inputImage 为 nil,返回 nil,避免后续操作发生错误。

2、转换图片为 Core Image 格式

let ciImage = CIImage(image: inputImage)

将 UIImage 转换为 Core Image 的 CIImage,以便后续滤镜操作。

3、配置滤镜

let filter = CIFilter.twirlDistortion()
filter.inputImage = ciImage
filter.center = CGPoint(x: 500, y: 500)
filter.radius = 300
filter.angle = 3.14

使用 CIFilter.twirlDistortion() 创建 “扭曲失真” 滤镜。

inputImage:指定要处理的图片。

center:设置扭曲的中心点,坐标 (500, 500)。

radius:设置扭曲的半径,值为 300 像素。

angle:设置扭曲的角度,值为 3.14(约等于 π)。

4、创建渲染上下文

let context = CIContext()

创建 CIContext 对象,用于渲染 CIImage,生成最终的图像数据。

5、渲染处理后的图片

if let outputImage = filter.outputImage,
   let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
    return UIImage(cgImage: cgImage)
}
return nil

filter.outputImage:获取滤镜处理后的 CIImage。

context.createCGImage

渲染 outputImage,将描述性的 CIImage 转换为具体的 CGImage。

渲染范围为 outputImage.extent,即处理图片的完整区域。

返回处理后的图片

将 CGImage 转换为 UIImage 以供 SwiftUI 显示。

如果渲染失败,返回 nil。

整体流程总结

1、加载图片。

2、应用 “扭曲失真” 滤镜。

3、使用 CIContext 渲染滤镜输出,生成具体的图像数据。

4、将渲染结果转换为 UIImage,以供 SwiftUI 显示。

多次转换及背后的工作原理

CIImage 是描述性的

CIImage 是 Core Image 的基础图像类型,它的设计理念是描述图像处理的链条,而不是存储最终的像素数据。

它内部记录了:

图像来源(如文件路径、像素数据、URL 等)。

应用的滤镜效果及参数。

未渲染的处理步骤。

let filter = CIFilter.gaussianBlur()
filter.inputImage = CIImage(image: UIImage(named: "example"))
filter.radius = 10.0

此时,filter.outputImage 是一个包含模糊效果描述的 CIImage,它告诉系统如何模糊原始图像,但尚未生成像素化的结果。

为什么需要 CIContext

CIContext 是渲染引擎:它将 CIImage 的描述“执行”成实际的图像数据。

渲染过程需要计算每个像素的值,例如模糊的强度、颜色调整等。

CIContext 的作用

将 Core Image 的描述性图像处理链条(CIImage)转换为像素级数据。

支持 Metal、CPU 或 OpenGL 渲染,为处理提供高效的性能优化。

CIFilter的输入和输出

inputImage:提供原始图像,作为滤镜的输入。

outputImage:滤镜处理后生成的结果图像。

inputImage

定义:inputImage 是 CIFilter 的一个输入属性,表示滤镜需要处理的原始图像。

类型:它通常是一个 CIImage?(可选类型的 CIImage),即 Core Image 用来描述图像数据的对象。

用途

通过设置 inputImage,我们告诉滤镜要对哪张图像进行处理。

如果没有为滤镜指定有效的 inputImage,滤镜将无法工作,其输出也会为空。

filter.inputImage = ciImage

这里的 ciImage 是一个通过 UIImage 转换得到的 CIImage,表示原始的待处理图像。

outputImage

定义:outputImage 是 CIFilter 的一个输出属性,表示滤镜处理后的结果图像。

类型:它是一个 CIImage?(可选类型的 CIImage),即处理后的图像描述。

用途

调用 outputImage 属性时,Core Image 会基于滤镜的配置(如参数设置)生成一个处理后的图像描述。     

需要进一步渲染(通过 CIContext)才能将其转化为实际的图像格式(如 UIImage 或 CGImage)。

let outputImage = filter.outputImage

渲染后的结果:CGImage

context.createCGImage(outputImage, from: outputImage.extent)

context.createCGImage 是使用 Core Image 的 CIContext 来渲染 CIImage,生成实际的像素图像(CGImage 类型)。

参数

outputImage 是需要渲染的 CIImage。

outputImage.extent 指定渲染的图像区域(通常是图像的边界)。

为什么要渲染?

CIImage 是一种延迟计算的数据结构,只描述图像和操作,但没有实际的像素数据。要显示、保存或进一步处理,就需要将其渲染为具体格式,如 CGImage。

渲染后的图像是 CGImage 类型,它代表已生成的、具体的像素图像。

为什么渲染为 CGImage?

Core Graphics 是底层的 2D 图形库,CGImage 是 Core Graphics 处理图像的核心类型。

iOS 和 macOS 的大部分图像处理管道(如 PDF 渲染、屏幕显示等)依赖 CGImage。

转换为 UIImage 的必要性

UIImage 是 UIKit 的图像类型,用于在 iOS 上显示或进一步处理。

为什么不能直接从 CIImage 转换为 UIImage?

UIKit 无法直接理解 Core Image 的描述链条。

需要通过 CIContext 渲染 CIImage 并生成像素数据(CGImage),再封装为 UIImage。

完整转换过程的作用

1、CIImage

用于描述图像处理链条,包括滤镜和参数。

不占用太多内存,因为它不包含实际的像素数据。

2、CIContext

负责解析和执行 CIImage 的处理链条,将其渲染为像素数据。

3、CGImage

渲染后的图像,包含具体的像素数据。

高效、轻量,可用于图像操作或显示。

4、UIImage

iOS 的标准图像类型,直接用于用户界面(如 UIImageView)。

包装了 CGImage 和元数据信息(如方向、缩放比例等)。

为什么需要分阶段转换?

性能考虑

CIImage 是懒加载的,仅在需要渲染时生成实际数据,节约内存和计算资源。

渲染过程可选择 CPU、GPU 或 Metal,以适应不同的性能需求。

灵活性

CGImage 可以直接用于 Core Graphics 和其他底层处理。

UIImage 用于 UI 层更方便。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注