How to give effect something like this using CIFilter in UIImage? - swift

I wanted to achieve something like this using CIFilter.
I'm googling a lot but not finding any best solutions for the same.
Thank you.
Here is my code
func applyProcessing() {
var context: CIContext = CIContext()
let currentFilter = CIFilter(name: "CIBumpDistortion")
let beginImage = CIImage(image: currentImage)
self.currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
self.currentFilter.setValue(100, forKey: kCIInputRadiusKey)
self.currentFilter.setValue(intensity, forKey: kCIInputScaleKey)
self.currentFilter.setValue(CIVector(x: currentImage.size.width / 2, y: currentImage.size.height / 2), forKey: kCIInputCenterKey)
guard let image = self.currentFilter.outputImage else { return }
if let cgimg = context.createCGImage(image, from: image.extent) {
let processedImage = UIImage(cgImage: cgimg)
self.imgMain.image = processedImage
}
}

Related

Why is my CIImage nil after I invert a UIImage?

I have a very peculiar issue here where I convert a UIImage to CIImage after I inverted the UIImage. Here is the code:
let imageFromBuffer1 = self.imageInvert(image: self.imageFromBuffer)
let ciImage = CIImage(image: imageFromBuffer1)
So, in above code ciImage is nil for some bizarre reason. Can anybody explain this, or tell me what else to do to get the UIImage converted to CIImage?
This is the invert function I am using above:
func imageInvert(image: UIImage) -> UIImage{
let beginImage = CIImage(image: image)
var newImage = UIImage()
if let filter = CIFilter(name: "CIColorInvert") {
filter.setValue(beginImage, forKey: kCIInputImageKey)
let ciImage = filter.outputImage
newImage = UIImage(ciImage: ciImage!)
}
else{
print("filter does not exist")
newImage = image
}
return newImage
}
Because when an image is converted from one form to another some data may be modified, lost or not used. For instance when you load a UIImage from assets it may be larger than the view in which it is displayed, The graphics engine does it's best to display the image as true as possible. However some of the underlying image data may not be used, this is especially true for compressed jpeg images. Instead of converting the image back and forth consider transforming the current context the image resides in:
ViewController.swift
import UIKit
class ViewController: UIViewController {
lazy var imageView = UIImageView(frame: self.view.frame)
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(imageView)
let tap = UITapGestureRecognizer(target: self, action: #selector(imageViewTapped))
imageView.addGestureRecognizer(tap)
imageView.isUserInteractionEnabled = true
imageView.contentMode = .scaleAspectFit
// https://en.wikipedia.org/wiki/File:Meisje_met_de_parel.jpg
imageView.image = UIImage(named: "Meisje_met_de_parel.jpg")
}
func invert(image: UIImage) -> UIImage? {
let ciImage = CIImage(image: image)
var newImage:UIImage? = nil
guard let filter = CIFilter(name: "CIColorInvert") else {return image}
filter.setValue(ciImage, forKey: kCIInputImageKey)
let context = CIContext(options: nil)
if let outputImage = filter.outputImage, let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
newImage = UIImage(cgImage: cgImage)
}
return newImage
}
#objc func imageViewTapped() {
if let image = self.imageView.image {
let invertedImage = self.invert(image: image)
DispatchQueue.main.async {
self.imageView.image = invertedImage
}
}
}
}

Converting UIImage to CIImage Returns nil

I'm trying to convert the UIImage from an imageView into a CIImage for the purpose of filtering it. However, I cannot get the CIImage to have a value.
In the simplest form, here's what I am trying:
let ciInput = CIImage(image: imageView.image!)
but the ciInput always is nil.
I have also tried
let ciInput = CIImage(cgImage: imageView.image!.cgImage)
but also returns nil.
(imageView.image is not nil, but imageView.image!.cgImage and imageView.image!.ciImage are both nil)
I need to convert the UIImage from the imageView into a valid CIImage. Any help is appreciated, thanks!
EDIT: Here is the full function code
func makeWhiteTransparent(imageView: UIImageView) {
let invertFilter = CIFilter(name: "CIColorInvert")
let ciContext = CIContext(options: nil)
let ciInput = CIImage(image: imageView.image!) //This is nil
invertFilter?.setValue(ciInput, forKey: "inputImage")
let ciOutput = invertFilter?.outputImage
let cgImage = ciContext.createCGImage(ciOutput!, from: (ciOutput?.extent)!)
imageView.image = UIImage(cgImage: cgImage!)
}
When running this function, I get a fatal unwrapping nil error on the last line. Using the debugger, I discovered that the ciInput is nil, which it should not be.
EDIT 2:
The image on the imageView before calling makeWhiteTransparent is a QR code generated with this function:
func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 12, y: 12)
if let output = filter.outputImage?.applying(transform) {
return UIImage(ciImage: output)
}
}
return nil
}
So the problem was in my QR Code generation. The code returned a UIImage from a CIImage without properly utilizing CGContext to return the UIImage. Here is the corrected QR Code function that fixed the issue.
func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 12, y: 12)
if let output = filter.outputImage?.applying(transform) {
let context = CIContext()
let cgImage = context.createCGImage(output, from: output.extent)
return UIImage(cgImage: cgImage!)
}
}
return nil
}

Ambigous use of 'init(CIImage:)'

I have an error - Ambigous use of 'init(CIImage:)' on the last line. Can anyone help me fix it?
let origImage = CIImage(image: img)
let filter = CIFilter(name: "CIColorInvert")
filter?.setValue(origImage, forKey: kCIInputImageKey)
let invertedImage = UIImage(CIImage: (filter?.outputImage)!)
In Swift 3, UIImage(CIImage: ...) constructor was renamed to:
let invertedImage = UIImage(ciImage: ...)

Core Image and memory leak, swift 3.0

i have problem i try use filter at some images which have extension 3000x2000 , when i do it RAM upper and app have fatal error the "didReceiveMemoryWarning".
func setFilters(images: [UIImage]) -> [UIImage] {
let filter = CIFilter(name: "CIColorControls")!
filter.setValue(2.0, forKey: kCIInputContrastKey)
let context = CIContext(options: nil)
var result = [UIImage]()
for img in images {
let newImage = autoreleasepool(invoking: { () -> UIImage in
filter.setValue(CIImage(image: img)!, forKey: kCIInputImageKey)
let ciImage = filter.outputImage!
let cgImage = context.createCGImage(ciImage, from: ciImage.extent)
return UIImage(cgImage: cgImage!, scale: img.scale, orientation: img.imageOrientation)
})
result.append(newImage)
}
return result
}
It's not a memory leak; it's that you are in fact using too much memory. And it's not the use of CIFilter that's causing the problem; it's the fact that you are trying to keep all of these huge UIImage objects in memory in a single array:
var result = [UIImage]()
// ...
result.append(newImage)
Don't do that.

Image roates after CIFilter applied

I'm applying a CIFilter to an image but it gets rotated after the filter is applied. I found a solution here in objective-c, how could I do this in swift? My code is below.
let originalImage = CIImage(image: cameraStill.image)
var filter = CIFilter(name: "CIPhotoEffect"+x)
filter.setDefaults()
filter.setValue(originalImage, forKey: kCIInputImageKey)
var outputImage = filter.outputImage
var newImage = UIImage(CIImage: outputImage)
v.setImage(newImage, forState: .Normal)
The code below worked fine for me:
var image = UIImage(named: "Turtle")
let ciImage = CIImage(image: image)
let filter = CIFilter(name: "CISepiaTone")
filter.setValue(ciImage, forKey: kCIInputImageKey)
filter.setValue(1.5, forKey: kCIInputIntensityKey)
let newImage = UIImage(CIImage: filter.outputImage)
let imageView = UIImageView(image: newImage)
self.view.addSubview(imageView)
Let me know how you go.