Convert UIImage to grayscale keeping image quality

前端 未结 7 1176
难免孤独
难免孤独 2020-12-08 19:42

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

public fun         


        
相关标签:
7条回答
  • 2020-12-08 20:22

    As per Joe answer we easily converted Original to B&W . But back to Original image refer these code :

    var context = CIContext(options: nil)
    var startingImage : UIImage = UIImage()
    
    func Noir() {     
        startingImage = imgView.image!
        var inputImage = CIImage(image: imgView.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.imgView.image =  UIImage(cgImage: cgImage!)
    
        //Filter Logic
        let currentFilter = CIFilter(name: "CIPhotoEffectNoir")
        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!)
        imgView.image = processedImage
    }
    
    func Original(){ 
        imgView.image = startingImage
    }
    
    0 讨论(0)
  • 2020-12-08 20:23

    Joe's answer as an UIImage exension for Swift 4 working correctly for different scales:

    extension UIImage {
        var noir: UIImage {
            let context = CIContext(options: nil)
            let currentFilter = CIFilter(name: "CIPhotoEffectNoir")!
            currentFilter.setValue(CIImage(image: self), forKey: kCIInputImageKey)
            let output = currentFilter.outputImage!
            let cgImage = context.createCGImage(output, from: output.extent)!
            let processedImage = UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)
    
            return processedImage
        }
    }
    
    0 讨论(0)
  • 2020-12-08 20:24

    save curent orientation and scale:

    extension UIImage {
    
    func noir() -> UIImage {
        let context = CIContext(options: nil)
    
        let currentFilter = CIFilter(name: "CIPhotoEffectNoir")
        currentFilter!.setValue(CIImage(image: self), forKey: kCIInputImageKey)
        let output = currentFilter!.outputImage
        let cgimg = context.createCGImage(output!, from: output!.extent)
        let processedImage = UIImage(cgImage: cgimg!, scale: scale, orientation: imageOrientation)
        return processedImage
    }}
    
    0 讨论(0)
  • 2020-12-08 20:27

    I'd use CoreImage, which may keep the quality.

    func convertImageToBW(image:UIImage) -> UIImage {
    
        let filter = CIFilter(name: "CIPhotoEffectMono")
    
        // convert UIImage to CIImage and set as input
    
        let ciInput = CIImage(image: image)
        filter?.setValue(ciInput, forKey: "inputImage")
    
        // get output CIImage, render as CGImage first to retain proper UIImage scale
    
        let ciOutput = filter?.outputImage
        let ciContext = CIContext()
        let cgImage = ciContext.createCGImage(ciOutput!, from: (ciOutput?.extent)!)
    
        return UIImage(cgImage: cgImage!)
    }
    

    Depending on how you use this code, you may want to create the CIContext outside of it for performance reasons.

    0 讨论(0)
  • 2020-12-08 20:28

    Here's a category in objective c. Note that, critically, this version takes scale into consideration.

    - (UIImage *)grayscaleImage{
        return [self imageWithCIFilter:@"CIPhotoEffectMono"];
    }
    
    - (UIImage *)imageWithCIFilter:(NSString*)filterName{
        CIImage *unfiltered = [CIImage imageWithCGImage:self.CGImage];
        CIFilter *filter = [CIFilter filterWithName:filterName];
        [filter setValue:unfiltered forKey:kCIInputImageKey];
        CIImage *filtered = [filter outputImage];
        CIContext *context = [CIContext contextWithOptions:nil];
        CGImageRef cgimage = [context createCGImage:filtered fromRect:CGRectMake(0, 0, self.size.width*self.scale, self.size.height*self.scale)];
        // Do not use initWithCIImage because that renders the filter each time the image is displayed.  This causes slow scrolling in tableviews.
        UIImage *image = [[UIImage alloc] initWithCGImage:cgimage scale:self.scale orientation:self.imageOrientation];
        CGImageRelease(cgimage);
        return image;
    }
    
    0 讨论(0)
  • 2020-12-08 20:32

    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:

    Output from Answer 2:

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

    0 讨论(0)
提交回复
热议问题