DanielEdrisian
DanielEdrisian

Reputation: 726

CIColorMatrix Filter result is weird

I am trying to create a CIFilter which converts the following QR Code:

enter image description here

To:

enter image description here

Here is the code that I'm using:

let invert = CIFilter(name: "CIColorInvert")
invert!.setDefaults()
invert!.setValue(ciImage, forKey: "inputImage")

let filter = CIFilter(name: "CIColorMatrix")
filter?.setDefaults()
filter?.setValue(invert?.outputImage, forKey: kCIInputImageKey)

let r = CGFloat(70.0/255.0)
let g = CGFloat(224.0/255.0)
let b = CGFloat(182.0/255.0)

filter?.setValue(CIVector(x: r, y: 0, z: 0, w: 0), forKey: "inputRVector")
filter?.setValue(CIVector(x: 0, y: g, z: 0, w: 0), forKey: "inputGVector")
filter?.setValue(CIVector(x: 0, y: 0, z: b, w: 0), forKey: "inputBVector")
filter?.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")

What the code does is first invert the normal QR code so that it's black on white, then it takes that image and applies a filter on it. The result of the code is this:

enter image description here

Which is not the color that I wanted. I would appreciate any help!

Thanks!

Upvotes: 2

Views: 1292

Answers (2)

lenooh
lenooh

Reputation: 10682

I had to create a context without a colorspace, to get the color correct:

...
let ciContext = CIContext(options: [CIContextOption.outputColorSpace: NSNull(), CIContextOption.workingColorSpace: NSNull()])
let cgimg = ciContext.createCGImage(outputs!,from: output!.extent)
let processedImage = UIImage(cgImage: cgimg!)

(Swift 4)

Upvotes: 0

Joe
Joe

Reputation: 8986

You can use one of the following methods to achieve QR filter effect using coreImage.

Output:

enter image description here

Method 1: Using Custom Filter

Step1: Create seperate class to your custom kernel as follow.

class CustomFilter: CIFilter {
var inputImage: CIImage?

override public var outputImage: CIImage! {
    get {
        if let inputImage = self.inputImage {
            let args = [inputImage as AnyObject]
            return createCustomKernel().apply(withExtent: inputImage.extent, arguments: args)
        } else {
            return nil
        }
      }
    }
 }


func createCustomKernel() -> CIColorKernel {
let kernelString =
    "kernel vec4 chromaKey( __sample s) { \n" +
        "  vec4 newPixel = s.rgba;" +
        "  newPixel[0] = 0.0;" +
        "  newPixel[2] = newPixel[2] / 2.0;" +
        "  return newPixel;\n" +
"}"
return CIColorKernel(string: kernelString)!
 }

In your ViewController you can declare your custom filter as below.

 var context = CIContext(options: nil)

 func customQRFilter() {

    let myInvertFilter = CIFilter(name: "CIColorInvert")
    myInvertFilter!.setValue(CIImage(image: imageView.image!), forKey: kCIInputImageKey)
    let output = myInvertFilter!.outputImage 

    let filter = CustomFilter()
    filter.setValue(output, forKey: kCIInputImageKey)
    
    // Get the filtered output image and return it
    let outputImage = filter.outputImage!
    let cgimg = context.createCGImage(outputImage,from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!)
    imageView.image = processedImage
   }

Method 2: Using CIColorMatrix filter.

    func colorMatrixFilter() {
    
    let myInvertFilter = CIFilter(name: "CIColorInvert")
    myInvertFilter!.setValue(CIImage(image: imageView.image!), forKey: kCIInputImageKey)
    let output = myInvertFilter!.outputImage 
    
    let filter = CIFilter(name: "CIColorMatrix")
    filter?.setDefaults()
    filter?.setValue(output, forKey: kCIInputImageKey)
    
    let r = CGFloat(0.0)
    let g = CGFloat(0.9)
    let b = CGFloat(0.416)
    
    filter?.setValue(CIVector(x: r, y: 0, z: 0, w: 0), forKey: "inputRVector")
    filter?.setValue(CIVector(x: 0, y: g, z: 0, w: 0), forKey: "inputGVector")
    filter?.setValue(CIVector(x: 0, y: 0, z: b, w: 0), forKey: "inputBVector")
    filter?.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
    
    let outputs = filter?.outputImage 
    let cgimg = context.createCGImage(outputs!,from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!)
    imageView2.image = processedImage
}

Note: I advice you to use a colour Picker tool to pick RGB value of any colour you want.

Upvotes: 2

Related Questions