Output of CIFilter has different effect for different sizes of same image

263 Views Asked by At
func getImageWithFilter(by filterType: MainViewModel.FilterType,
    image: CIImage) -> CIImage {

    guard filterType.filterEnabled,
        let filter = CIFilter(name: filterType.rawValue)
    else {
        return image
    }
    filter.setValue(image, forKey: kCIInputImageKey)

    return filter.outputImage ?? image
}

enter image description here enter image description here

I have two output:

  • AVCaptureVideoDataOutput for preview
  • AVCapturePhotoOutput for save photo in hightResolution.

After applied filters i get different results

Help me please resolve this problem.

2

There are 2 best solutions below

2
Frank Rupprecht On BEST ANSWER

This happens because most parameters of built-in Core Image filters operate on a pixel basis. In your case it's the inputRadius parameter of the CICrystallize filter. From the docs:

The radius determines how many pixels are used to create the effect. The larger the radius, the larger the resulting crystals.

That means that you need to set the parameter to different values depending on the input size.

I usually calculate some kind of factor that I multiply with my base parameter value. For instance:

let inputSizeFactor = min(inputImage.size.width, inputImage.size.height) / 1000
let scaledRadius = radius * inputSizeFactor
filter.setValue(scaledRadius, forKey: "inputRadius")
0
ToooLazy On

As @FrankRupprecht mentioned,

This happens because most parameters of built-in Core Image filters operate on a pixel basis. In your case it's the inputRadius parameter of the CICrystallize filter.

To get the same output, I usually apply an intuitive approach.

  1. First Step:

Apply CIAffineClamp filter, which takes your image in infinite extent. See cifilter.io/CIAffineClamp/

  1. Second Step:

Apply any filter like CICrystallize, CIComicEffect, CIGaussianBlur...

  1. Final Step:

Crop the image according to source image extends

let outputImage = sourceImage // Step 1
        .applyingFilter("CIAffineClamp", parameters: [
            "inputTransform": CGAffineTransform.identity
        ])
        .applyingFilter("CIGaussianBlur") // Step 2

guard let outputImage = filter.outputImage,
      let cgImage = contex.createCGImage(outputImage, from: sourceImage.extent) // Final Step
let uiImage = UIImage(cgImage: cgImage)