Image roates after CIFilter applied - swift

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.

Related

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

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
}
}

CIFilter can't be applied to SCNMaterial [duplicate]

This question already has an answer here:
Why can't I invert my image back to original with CIFilter in my Swift iOS app
(1 answer)
Closed 2 years ago.
Any CIFilter works fine when it's applied to UIImageView.
import UIKit
import CoreImage
#IBOutlet var imageView: UIImageView!
let ciBlurFilter = CIFilter(name: "CIGaussianBlur")!
func gaussianBlur() -> UIImage? {
let uiImage = UIImage(named: "texture.png")!
let ciImage = CIImage(image: uiImage)
ciBlurFilter.setValue(ciImage, forKey: "inputImage")
let resultedImage = ciBlurFilter.value(forKey: "outputImage") as! CIImage
let blurredImage = UIImage(ciImage: resultedImage)
return blurredImage
}
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = self.gaussianBlur()
}
But it doesn't work if it's applied to SceneKit's material:
import SceneKit
#IBOutlet var sceneView: SCNView!
let ciBlurFilter = CIFilter(name: "CIGaussianBlur")!
func gaussianBlur() -> UIImage? {
let uiImage = UIImage(named: "texture.png")!
let ciImage = CIImage(image: uiImage)
ciBlurFilter.setValue(ciImage, forKey: "inputImage")
let resultedImage = ciBlurFilter.value(forKey: "outputImage") as! CIImage
let blurredImage = UIImage(ciImage: resultedImage)
return blurredImage
}
override func viewDidLoad() {
super.viewDidLoad()
sceneView.scene = SCNScene()
let sphereNode = SCNNode(geometry: SCNSphere(radius: 0.1))
sphereNode.geometry?.firstMaterial?.diffuse.contents = self.gaussianBlur()
sceneView.scene?.rootNode.addChildNode(sphereNode)
}
Why SCNMaterial with CIFilter is invisible (although it supports UIImages)?
What's the matter?
The UIImage you create with that constructor is not actually rendered at that moment. The receiver of the image needs to know that the image needs to be rendered before use, which is seemingly not handled by SceneKit.
Please see my answer here for details.
Here's how you render the CIImage in Swift:
// ideally you create this once and re-use it;
// you should not create a new context for every draw call
let ciContext = CIContext()
let cgImage = ciContext.createCGImage(ciImage, from: ciImage.extent)
let uiImage = cgImage.flatMap({ UIImage.init(cgImage: $0) })
You can pass the CGImage to the material or wrap it into a UIImage, both should work.

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: ...)