【问题标题】:CIFilter black and white image appears blue after blendingCIFilter黑白图像混合后呈蓝色
【发布时间】:2020-04-12 09:45:38
【问题描述】:

将 CIFilter 应用于图像时,我得到了意想不到的结果。预期的结果是黑白图像,橙色通过边缘混合。相反,我得到了一个蓝色的图像,边缘混合了红色。我的功能是:

func sketch(with ciImage: CIImage) -> CIImage {

    var sourceCore = ciImage

    var convolutionValue_A:CGFloat = -0.0925937220454216
    var convolutionValue_B:CGFloat = -0.4166666567325592
    var convolutionValue_C:CGFloat = -1.8518532514572144
    var convolutionValue_D:CGFloat = 0.23148006200790405
    var convolutionValue_E:CGFloat = 4.5833334922790527
    var convolutionValue_F:CGFloat = 14.166666984558105

    var brightnessVal:CGFloat = 1.1041666269302368
    var contrastVal:CGFloat = 3.0555555820465088

    var weightsArr: [CGFloat] = [
        convolutionValue_A, convolutionValue_A, convolutionValue_B, convolutionValue_B, convolutionValue_B, convolutionValue_A, convolutionValue_A,
        convolutionValue_A, convolutionValue_B, convolutionValue_C, convolutionValue_C, convolutionValue_C, convolutionValue_B, convolutionValue_A,
        convolutionValue_B, convolutionValue_C, convolutionValue_D, convolutionValue_E, convolutionValue_D, convolutionValue_C, convolutionValue_B,
        convolutionValue_B, convolutionValue_C, convolutionValue_E, convolutionValue_F, convolutionValue_E, convolutionValue_C, convolutionValue_B,
        convolutionValue_B, convolutionValue_C, convolutionValue_D, convolutionValue_E, convolutionValue_D, convolutionValue_C, convolutionValue_B,
        convolutionValue_A, convolutionValue_B, convolutionValue_C, convolutionValue_C, convolutionValue_C, convolutionValue_B, convolutionValue_A,
        convolutionValue_A, convolutionValue_A, convolutionValue_B, convolutionValue_B, convolutionValue_B, convolutionValue_A, convolutionValue_A
    ]

    let inputWeights:CIVector = CIVector(values: weightsArr, count: weightsArr.count)

    sourceCore = sourceCore
        .applyingFilter("CIColorControls", parameters: [kCIInputImageKey: sourceCore,
                                                        kCIInputSaturationKey: 0.0,
                                                        kCIInputBrightnessKey: brightnessVal,
                                                        kCIInputContrastKey: contrastVal])

    // transforms image to only show edges in black and white
    sourceCore = sourceCore
        .applyingFilter("CIConvolution7X7", parameters: [kCIInputImageKey: sourceCore,
                                                         kCIInputWeightsKey: inputWeights]).cropped(to: sourceCore.extent)

    // give camera image a black and white Noir effect
    var ciImage = ciImage
        .applyingFilter("CIPhotoEffectNoir", parameters: [kCIInputImageKey: ciImage])


    // make solid color
    let color = CIColor(red: 0.819, green: 0.309, blue: 0.309)
    let colFilter = CIFilter(name: "CIConstantColorGenerator")!
    colFilter.setValue(color, forKey: kCIInputColorKey)
    var solidColor = colFilter.value(forKey: "outputImage") as! CIImage
    solidColor = solidColor.cropped(to: ciImage.extent)

    // color should only be shown through outlines 
    // for some reason the input image is blue-ish
    sourceCore = sourceCore
        .applyingFilter("CIBlendWithMask", parameters: [
            kCIInputImageKey: ciImage, // black and white image
            kCIInputBackgroundImageKey: solidColor, // solid color
            kCIInputMaskImageKey:sourceCore]) // edge work image

    ciImage = sourceCore

    return ciImage

}

以下是函数执行过程中每一步的图像:

我的来源,全彩图像

这就是我应用具有 0 饱和度和 7x7 卷积的 CIColorControls 时的结果。我用它作为我的面具,试图通过黑色轮廓区域显示橙色。

这是使用 CIFilter "CIPhotoEffectNoir" 后的黑白,在将其与蒙版和纯色混合时用作输入图像。

与蒙版混合时用作背景的纯橙色。

执行 CIBlendWithMask 后生成的图像看起来不正确。

首先,我希望背景颜色仅出现在蒙版图像上的轮廓所在的位置。背景颜色是橙色而不是红色,输入图像是蓝色而不是严格的黑白。

【问题讨论】:

    标签: swift mask cifilter ciimage


    【解决方案1】:

    想通了,虽然我不确定为什么会这样。我猜这是Apple技术的错误。在 CIConvolution7X7 之后,我需要使用 CIColorDodgeBlendMode 或 CILinearDodgeBlendMode 将黑白图像与白色背景混合。

    最终代码:

    func sketch(with ciImage: CIImage) -> CIImage {
    
        var sourceCore = ciImage
    
        var convolutionValue_A:CGFloat = -0.0925937220454216
        var convolutionValue_B:CGFloat = -0.4166666567325592
        var convolutionValue_C:CGFloat = -1.8518532514572144
        var convolutionValue_D:CGFloat = 0.23148006200790405
        var convolutionValue_E:CGFloat = 4.5833334922790527
        var convolutionValue_F:CGFloat = 14.166666984558105
    
        var brightnessVal:CGFloat = 1.1041666269302368
        var contrastVal:CGFloat = 3.0555555820465088
    
        var weightsArr: [CGFloat] = [
            convolutionValue_A, convolutionValue_A, convolutionValue_B, convolutionValue_B, convolutionValue_B, convolutionValue_A, convolutionValue_A,
            convolutionValue_A, convolutionValue_B, convolutionValue_C, convolutionValue_C, convolutionValue_C, convolutionValue_B, convolutionValue_A,
            convolutionValue_B, convolutionValue_C, convolutionValue_D, convolutionValue_E, convolutionValue_D, convolutionValue_C, convolutionValue_B,
            convolutionValue_B, convolutionValue_C, convolutionValue_E, convolutionValue_F, convolutionValue_E, convolutionValue_C, convolutionValue_B,
            convolutionValue_B, convolutionValue_C, convolutionValue_D, convolutionValue_E, convolutionValue_D, convolutionValue_C, convolutionValue_B,
            convolutionValue_A, convolutionValue_B, convolutionValue_C, convolutionValue_C, convolutionValue_C, convolutionValue_B, convolutionValue_A,
            convolutionValue_A, convolutionValue_A, convolutionValue_B, convolutionValue_B, convolutionValue_B, convolutionValue_A, convolutionValue_A
        ]
    
        let inputWeights:CIVector = CIVector(values: weightsArr, count: weightsArr.count)
    
        sourceCore = sourceCore
            .applyingFilter("CIColorControls", parameters: [kCIInputImageKey: sourceCore,
                                                            kCIInputSaturationKey: 0.0,
                                                            kCIInputBrightnessKey: brightnessVal,
                                                            kCIInputContrastKey: contrastVal])
    
        // transforms image to only show edges in black and white
        sourceCore = sourceCore
            .applyingFilter("CIConvolution7X7", parameters: [kCIInputImageKey: sourceCore,
    
        let whiteCIColor = CIColor(red: 1, green: 1, blue: 1)
    
        let whiteColor = CIImage(color: whiteCIColor).cropped(to: ciImage.extent)
    
        // CIColorDodgeBlendMode, CILinearDodgeBlendMode
    
        sourceCore = sourceCore
                .applyingFilter("CIColorDodgeBlendMode", parameters: [kCIInputImageKey: sourceCore,
                                                                        kCIInputBackgroundImageKey: whiteColor])
                                                             kCIInputWeightsKey: inputWeights]).cropped(to: sourceCore.extent)
    
        // give camera image a black and white Noir effect
        var ciImage = ciImage
            .applyingFilter("CIPhotoEffectNoir", parameters: [kCIInputImageKey: ciImage])
    
    
        // make solid color
        let color = CIColor(red: 0.819, green: 0.309, blue: 0.309)
        let colFilter = CIFilter(name: "CIConstantColorGenerator")!
        colFilter.setValue(color, forKey: kCIInputColorKey)
        var solidColor = colFilter.value(forKey: "outputImage") as! CIImage
        solidColor = solidColor.cropped(to: ciImage.extent)
    
        // color is shown through outlines correctly, 
        // and image is black and white
        sourceCore = sourceCore
            .applyingFilter("CIBlendWithMask", parameters: [
                kCIInputImageKey: ciImage, // black and white image
                kCIInputBackgroundImageKey: solidColor, // solid color
                kCIInputMaskImageKey:sourceCore]) // edge work image
    
        ciImage = sourceCore
    
        return ciImage
    
    }
    

    【讨论】:

      【解决方案2】:

      我认为问题出在最后的混合步骤中。当您调用sourceCore.applyingFilter(...) 时,它会自动在该过滤器上将sourceCore 设置为inputImage。而且我不确定当您在 parameters 中重新定义它时会发生什么。

      您可以像这样创建过滤器:

      let blendFilter = CIFilter(name: "CIBlendWithMask", parameters: [
          kCIInputImageKey: ciImage,
          kCIInputBackgroundImageKey: solidColor,
          kCIInputMaskImageKey: sourceCore
      ])
      return blendFilter.outputImage
      

      顺便说一句,您可以像这样更轻松地创建纯色图像:

      let solidColor = CIImage(color: color).cropped(to: ciImage.extent)
      

      【讨论】:

      • 感谢关于纯色的提示。不幸的是,通过使用您的 blendFilter 代码或更改代码以使其不会自动将 sourceCore 设置为 inputImage,生成的图像是相同的。您认为这可能与设置超出预期值范围的值有关吗?
      • 有趣...您介意将混合过滤器更改为CIBlendWithRedMask 看看结果如何吗?
      • 当然。它与我的问题中显示的结果图像完全相同。
      • 您能否尝试将使用.applyingFilter 的部分重写为类似上面的内容?我仍然对文档中的这句话感到困惑:“这种方法虽然方便,但如果连续多次使用,效率会很低。通过链接过滤器而不询问单个过滤器的输出来获得更好的性能。”使用此方法时还设置kCIInputImageKey参数应该是不需要的并且可能会导致副作用?
      • 如果我用 CIEdgeWork 过滤器替换 CIConvolution7X7 过滤器,过滤器会正确显示。 (黑白图像上有橙色边缘) CIEdgeWork 的问题在于它在设备和 iOS 版本之间不再一致地工作。 CIConvolution7X7 和 CIEdgeWork 过滤器都会生成黑白图像。我感觉组成 CIImage 的信息有问题,该 CIImage 由 CIConvolution7X7 过滤器制成,不能与蒙版正常工作。
      猜你喜欢
      • 2016-01-24
      • 2021-08-05
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 2016-11-30
      • 2017-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多