Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert UIImage to grayscale keeping image quality

I have this extension (found in obj-c and I converted it to Swift3) to get the same UIImage but grayscaled:

public func getGrayScale() -> UIImage {     let imgRect = CGRect(x: 0, y: 0, width: width, height: height)      let colorSpace = CGColorSpaceCreateDeviceGray()      let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).rawValue)     context?.draw(self.cgImage!, in: imgRect)      let imageRef = context!.makeImage()     let newImg = UIImage(cgImage: imageRef!)      return newImg } 

I can see the gray image but its quality is pretty bad... The only thing I can see that's related to the quality is bitsPerComponent: 8 in the context contructor. However looking at Apple's doc, here is what I get:

enter image description here

It shows that iOS only supports 8bpc... Thus why can't I improve the quality ?

like image 441
Dliix Avatar asked Oct 21 '16 14:10

Dliix


1 Answers

Try below code:

Note: code Updated and error been fixed...

  • Code tested in Swift 3.
  • originalImage is the image that you trying to convert.

Answer 1:

     var context = CIContext(options: nil) 

Update: CIContext is the Core Image component that handles rendering and All of the processing of a core image is done in a CIContext. This is somewhat similar to a Core Graphics or OpenGL context.For more info available in Apple Doc.

     func Noir() {          let currentFilter = CIFilter(name: "CIPhotoEffectNoir")          currentFilter!.setValue(CIImage(image: originalImage.image!), forKey: kCIInputImageKey)         let output = currentFilter!.outputImage          let cgimg = context.createCGImage(output!,from: output!.extent)         let processedImage = UIImage(cgImage: cgimg!)         originalImage.image = processedImage       } 

Also you need to Considered following filter that can produce similar effect

  • CIPhotoEffectMono
  • CIPhotoEffectTonal

Output from Answer 1:

enter image description here

Output from Answer 2:

enter image description here

Improved answer :

Answer 2: Auto adjusting input image before applying coreImage filter

var context = CIContext(options: nil)  func Noir() {       //Auto Adjustment to Input Image     var inputImage = CIImage(image: originalImage.image!)     let options:[String : AnyObject] = [CIDetectorImageOrientation:1 as AnyObject]     let filters = inputImage!.autoAdjustmentFilters(options: options)      for filter: CIFilter in filters {        filter.setValue(inputImage, forKey: kCIInputImageKey)    inputImage =  filter.outputImage       }     let cgImage = context.createCGImage(inputImage!, from: inputImage!.extent)     self.originalImage.image =  UIImage(cgImage: cgImage!)      //Apply noir Filter     let currentFilter = CIFilter(name: "CIPhotoEffectTonal")      currentFilter!.setValue(CIImage(image: UIImage(cgImage: cgImage!)), forKey: kCIInputImageKey)      let output = currentFilter!.outputImage      let cgimg = context.createCGImage(output!, from: output!.extent)     let processedImage = UIImage(cgImage: cgimg!)     originalImage.image = processedImage  } 

Note: If you want to see the better result.You should be testing your code on real device not in the simulator...

like image 91
Joe Avatar answered Sep 21 '22 08:09

Joe