看到一些默认 CIFilter 的实现了吗?

Posted

技术标签:

【中文标题】看到一些默认 CIFilter 的实现了吗?【英文标题】:See implementation of some default CIFilter's? 【发布时间】:2021-11-28 08:20:12 【问题描述】:

更新:根据@FrankSchlegel 回答主要问题 - 不,无法检查系统CIFilter 的工作方式。

是否可以看到一些CIFilter 默认过滤器是如何实现的,例如CIDissolveTransitionCISwipeTransition?我想构建一些自定义转换过滤器,如果可能的话,我想看看一些Metal Shading Language 的例子。在互联网上真的找不到任何用 MSL 完成的过渡过滤器的例子,只能在常规的 Metal 管道中。

更新 1: 这是我希望移植到 MSL 的 Fade 过滤器示例:

    #include <metal_stdlib>
    using namespace metal;
    #include "../../Vender/Render/Base/OperationShaderTypes.h"

struct TwoInputVertexIO

    float4 position [[position]];
    float2 textureCoordinate [[user(texturecoord)]];
    float2 textureCoordinate2 [[user(texturecoord2)]];
;
    
    typedef struct
    
        float tweenFactor;
     FadeTransitionUniform;
    
    fragment half4 fadeTransition(TwoInputVertexIO fragmentInput [[stage_in]],
                                  texture2d<half> inputTexture [[texture(0)]],
                                  texture2d<half> inputTexture2 [[texture(1)]],
                                  constant FadeTransitionUniform& uniform [[ buffer(1) ]])
    
        
        constexpr sampler quadSampler;
        half4 textureColor = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);
        half4 textureColor2 = inputTexture2.sample(quadSampler, fragmentInput.textureCoordinate2);
        
        return half4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * half(uniform.tweenFactor)), textureColor.a);
    

这是我移植它的失败尝试:

float4 fadeTransition(sampler fromTexture, sampler toTexture, float time) 
    
    float2 uv = fromTexture.coord();
    float4 textureColor = fromTexture.sample(uv);
    float4 textureColor2 = toTexture.sample(uv);
    
    return float4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * float(time)), textureColor.a);
    

目前这似乎没有做任何事情,我认为我没有添加 constexpr sampler quadSampler 等效项。

更新 2:

这是我如何初始化CIKernel

import CoreImage

class TestTransitionFilter: CIFilter 

    private let kernel: CIKernel
    @objc dynamic var inputImage: CIImage?
    @objc dynamic var inputImage2: CIImage?
    @objc dynamic var inputTime: CGFloat = 0
    
    override init() 
        let url = Bundle.main.url(forResource: "default", withExtension: "metallib")!
        let data = try! Data(contentsOf: url)
        kernel = try! CIKernel(functionName: "fadeTransition", fromMetalLibraryData: data)
        super.init()
    
    
    required init?(coder aDecoder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    func outputImage() -> CIImage? 
        
        guard let inputImage = inputImage else return nil
        guard let inputImage2 = inputImage2 else return nil
        
        return kernel.apply(extent: inputImage.extent, roiCallback: 
            (index, rect) in
            return rect.insetBy(dx: -1, dy: -1)
        , arguments: [inputImage, inputImage2, inputTime])
    
    

这是我调用它的方式:

public class TestTransition: NoneTransition 
    
    override public func renderImage(foregroundImage: CIImage, backgroundImage: CIImage, forTweenFactor tween: Float64, renderSize: CGSize) -> CIImage 
        
    
        // This DOES work
        /*
        if let crossDissolveFilter = CIFilter(name: "CIFlashTransition") 
            crossDissolveFilter.setValue(backgroundImage, forKey: "inputImage")
            crossDissolveFilter.setValue(CIVector(x: backgroundImage.extent.width / 2.0, y: backgroundImage.extent.height / 2.0), forKey: "inputCenter")
            crossDissolveFilter.setValue(foregroundImage, forKey: "inputTargetImage")
            crossDissolveFilter.setValue(tween, forKey: "inputTime")
            if let outputImage = crossDissolveFilter.outputImage 
                return outputImage
            
        */
        
        
        // This DOESN'T work
        let filter = TestTransitionFilter()
        filter.inputImage = backgroundImage
        filter.inputImage2 = foregroundImage
        filter.inputTime = CGFloat(tween)
        
        if let outputImage = filter.outputImage 
            return outputImage
        
        
        return super.renderImage(foregroundImage: foregroundImage, backgroundImage: backgroundImage, forTweenFactor: tween, renderSize: renderSize)
    

最终更新:

感觉很傻,但几天后我发现了错误。在我调用 CIKernel 的地方,我使用了filter.outputImage 而不是filter.outputImage(),因此首先没有效果。

【问题讨论】:

很遗憾,您无法查看系统过滤器的实现。但也许您可以发布一个指向您喜欢移植的“常规金属管道”过滤器的链接,我们可以一起解决。 嘿弗兰克!感谢您对默认 CIFilter 的澄清。我在编辑中添加了我希望移植的过滤器。 @FrankSchlegel 能否请您说明如何初始化CIKernel 以及如何调用它? @FrankSchlegel 完成!我的其他常规(非过渡)自定义过滤器以这种方式工作。 嗯,很有趣。 tween 介于 0.01.0 之间?过滤器的输出是什么? 【参考方案1】:

虽然您自己发现了该错误,但这里是您解决方案的补充:

您应该覆盖CIFilter 的现有属性,而不是func outputImage() -&gt; CIImage? ... ,因为它是获取过滤器输出的标准方式:

override var outputImage: CIImage? 
    // your computation here

还有一个提示:对于这种内核,您可以使用CIColorKernel,因为您只需要对单个像素进行采样,而无需查看它们的邻居。然后内核将如下所示:

float4 fadeTransition(sample_t foreground, sample_t background, float time) 
    return float4(mix(foreground.rgb, background.rgb, background.a * float(time)), foreground.a);

然后将内核初始化为CIColorKernel而不是CIKernel

说到这一点,您也不需要为每个过滤器实例初始化一个新内核,而是使用一个静态内核。 (这是我在 WWDC 实验室期间与 Apple 工程师交谈时推荐的)。这就是整个过滤器的样子:

class TestTransitionFilter: CIFilter 

    @objc dynamic var inputImage: CIImage?
    @objc dynamic var inputImage2: CIImage?
    @objc dynamic var inputTime: CGFloat = 0

    private static var kernel: CIColorKernel 
        let url = Bundle.main.url(forResource: "default", withExtension: "metallib")!
        let data = try! Data(contentsOf: url)
        return try! CIColorKernel(functionName: "fadeTransition", fromMetalLibraryData: data)
    

    override var outputImage: CIImage? 
        guard let inputImage = inputImage, let inputImage2 = inputImage2 else return nil
        return Self.kernel.apply(extent: inputImage.extent, arguments: [inputImage, inputImage2, inputTime])
    


【讨论】:

非常感谢!这看起来更加优化,我会按照你的提示! 唯一的问题是,如果新内核中有sample 关键字,我会崩溃。应该换成sample_t 吗? 啊,是的,很好!我修正了我的答案。 虽然它很老了,但 Core Image For Swift (books.apple.com/gb/book/core-image-for-swift/id1073029980) 有很多自定义过滤器的例子,可能对你有用(而且它是免费的!)。

以上是关于看到一些默认 CIFilter 的实现了吗?的主要内容,如果未能解决你的问题,请参考以下文章

应用 CIFilter 后,无论我做啥,图像都会变大

Swift核心图像对没有CIFilter的图像应用锐化

应用CIFilter后无论我做什么,图像都变大了

iOS通过CIFilter对图像进行滤镜处理

Embeded linux 之 cifs文件系统

将 CIFilter 应用于 OpenGL 渲染到纹理