Core Image 中用于帧平均的 Alpha 混合

Alpha blending for frame averaging in Core Image

在我的应用程序中,我试图实现一种运动模糊功能,该功能可将来自视频输出的不同帧(对其进行平均)堆叠到单个图像中。我试图获得的效果在这里得到了很好的解释:https://photographylife.com/image-averaging-technique.

我尝试使用自定义 CIKernel 对每个颜色通道执行如下平均操作:

float4 makeAverage(sample_t currentStack, sample_t newImage, float stackCount) {
          
          float4 cstack = unpremultiply(currentStack);
          float4 nim = unpremultiply(newImage);
          float4 avg = ((cstack * stackCount) + nim) / (stackCount + 1.0);
          
          return premultiply(avg);
          
      }

您可以在此处找到有关完整代码的更多详细信息:Problems with frame averaging with Core Image

它有效,但过了一会儿,奇怪的补丁开始出现在图像中,暗示颜色通道正在剪裁。

有没有一种方法可以在核心图像中使用 alpha 混合实现相同的结果?也许,而不是在颜色通道上进行堆叠操作,我可以堆叠具有递减 alpha 值的后续图像吗?

如果是这样,procedure/algorithm 会怎么做?

经过一番尝试,我找到了解决办法。基本上,这是达到预期效果的方法:

我使用 CIColorMatrix 过滤器降低了每个连续帧的不透明度。函数代码下方:

func setOpacity (image : CIImage, alpha : Double) ->CIImage {

guard let overlayFilter: CIFilter = CIFilter(name: "CIColorMatrix") else { fatalError() }
let overlayRgba: [CGFloat] = [0, 0, 0, alpha]
let alphaVector: CIVector = CIVector(values: overlayRgba, count: 4)
overlayFilter.setValue(image, forKey: kCIInputImageKey)
overlayFilter.setValue(alphaVector, forKey: "inputAVector")

return overlayFilter.outputImage!

}

每次帧到达时,alpha 值计算为 1/计数。然后,我使用 CISourceOverCompositing 过滤器执行 alpha 混合:

func makeCompositeImage(stackImage: CIImage?, newImage: CIImage?, count: Double) -> CIImage {
    
    let bgImage = stackImage
    
    let opacity = 1.0 / count
    
    let newImageFiltered = setOpacity(image: newImage!, alpha: opacity)
    // Filter part
    let currentFilter = CIFilter(name: "CISourceOverCompositing")
    currentFilter?.setValue(newImageFiltered, forKey: kCIInputImageKey)
    currentFilter?.setValue(bgImage, forKey: kCIInputBackgroundImageKey)
    guard let outputImage = currentFilter?.outputImage else { return bgImage!}
    
    return outputImage
}

该方法按预期工作,我可以模拟连续帧的运动模糊。然而,最初的问题仍然存在,一段时间后,图像中开始出现明显的色带和色块,破坏了最终结果。

不过,我希望上面的代码对某些人有用。

您可以通过像这样使用 CIMix 过滤器以更简单的方式组合 CIColorMatrix 和 CISourceOverCompositing 来完成与您正在做的相同的事情

    func makeCompositeImage(stackImage: CIImage, newImage: CIImage?, count: Double) -> CIImage {
        let opacity = 1.0 / count
        return newImage?
            .applyingFilter("CIMix", parameters: [
                kCIInputBackgroundImageKey: stackImage,
                kCIInputAmountKey: opacity
            ]) ?? stackImage
    }

请查看我刚刚发布的这个应用程序:https://apps.apple.com/us/app/filter-magic/id1594986951。它可以让你玩弄每一个过滤器。