5

I am building a scanner component for an iOS app so far I have the result image cropped and in the correct perspective. Now I need to turn the color image into Black and white "Scanned" document.

I tried to use - "CIPhotoEffectNoir" but it more grayscale then totally black and white. I wish to get a full contrast image with 100% black and 100% white.

How can I achieve that? Thanks

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
shannoga
  • 19,649
  • 20
  • 104
  • 169
  • Check this post may help http://stackoverflow.com/questions/40178846/convert-uiimage-to-grayscale-keeping-image-quality/40182080#40182080 – Joe Mar 25 '17 at 00:57
  • I think you need to explain the difference between *grayscale* and *totally black and white*. @Joe basically gave you **CIPhotoEffectNoir** - which works for many cases (and is a very good answer). But by using "Scanned", are you saying you need a threshold "clamp" value that says make this pixel **either** black or white? It can be done, but only with (1) a custom CI kernel written that (2) allows for either a hard-coded or parameterized "clamp" value. –  Mar 25 '17 at 02:22

3 Answers3

15

You can use CIColorControls and set Contrast Key kCIInputContrastKey to increase the black/white contrast as follow:

Xcode 9 • Swift 4

extension String {
    static let colorControls = "CIColorControls"
}

extension UIImage {
    var coreImage: CIImage? { return CIImage(image: self) }
}

extension CIImage {
    var uiImage: UIImage? { return UIImage(ciImage: self) }
    func applying(contrast value: NSNumber) -> CIImage? {
        return applyingFilter(.colorControls, parameters: [kCIInputContrastKey: value])
    }
    func renderedImage() -> UIImage? {
        guard let image = uiImage else { return nil }
        return UIGraphicsImageRenderer(size: image.size,
                                       format: image.imageRendererFormat).image { _ in
            image.draw(in: CGRect(origin: .zero, size: image.size))
        }
    }
}

let url = URL(string: "https://i.stack.imgur.com/Xs4RX.jpg")!
do {
    if let coreImage = UIImage(data: try Data(contentsOf: url))?.coreImage,
        let increasedContrast = coreImage.applying(contrast: 1.5) {
        imageView.image = increasedContrast.uiImage
        // if you need to convert your image to data (JPEG/PNG) you would need to render the ciimage using renderedImage method on CIImage   
    }
} catch {
    print(error)
}

To convert from colors to grayscale you can set the Saturation Key kCIInputSaturationKey to zero:

extension CIImage {
    func applying(saturation value: NSNumber) -> CIImage? {
        return applyingFilter(.colorControls, parameters: [kCIInputSaturationKey: value])
    }
    var grayscale: CIImage? { return applying(saturation: 0) }
}

let url = URL(string: "https://i.stack.imgur.com/Xs4RX.jpg")!
do {
    if let coreImage = UIImage(data: try Data(contentsOf: url))?.coreImage, 
        let grayscale = coreImage.grayscale {
        // use  grayscale image here
        imageView.image = grayscale.uiImage
    }
} catch { 
    print(error) 
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
8
  1. Desaturate will convert your image to grayscale
  2. Increasing the contrast will push those grays out to the extremes, i.e. black and white.

You can CIColorControls:

let ciImage = CIImage(image: image)!
let blackAndWhiteImage = ciImage.applyingFilter("CIColorControls", withInputParameters: ["inputSaturation": 0, "inputContrast": 5])

Original:

Original

With inputContrast = 1 (default):

inputContrast = 1

With inputContrast = 5:

inputContrast = 5

Code Different
  • 90,614
  • 16
  • 144
  • 163
0

In Swift 5.1 I have written an extension method for OSX which also converts to and from NSImage. It uses saturation and input contrast to convert the image. I have abstracted a func for black and white.

extension NSImage {

    func blackAndWhite () -> NSImage?
    {
        return applying(saturation: 0,inputContrast: 5,image: self)
    }

    func applying(saturation value: NSNumber, inputContrast inputContrastValue: NSNumber, image:NSImage) -> NSImage? {

        let ciImage = CIImage(data: image.tiffRepresentation!)!
        let blackAndWhiteImage = ciImage.applyingFilter("CIColorControls", parameters: ["inputSaturation": value, "inputContrast": inputContrastValue])
        let rep: NSCIImageRep = NSCIImageRep(ciImage: blackAndWhiteImage)
        let nsImage: NSImage = NSImage(size: rep.size)
        nsImage.addRepresentation(rep)

        return nsImage
    }

}

RichIntellect
  • 191
  • 2
  • 4