objective-c uiimage ciimage

objective c - Aplicar filtro blanco y negro a UIImage



objective-c ciimage (10)

Swift3 + GPUImage

import GPUImage extension UIImage { func blackWhite() -> UIImage? { guard let image: GPUImagePicture = GPUImagePicture(image: self) else { print("unable to create GPUImagePicture") return nil } let filter = GPUImageAverageLuminanceThresholdFilter() image.addTarget(filter) filter.useNextFrameForImageCapture() image.processImage() guard let processedImage: UIImage = filter.imageFromCurrentFramebuffer(with: UIImageOrientation.up) else { print("unable to obtain UIImage from filter") return nil } return processedImage } }

Necesito aplicar un filtro en blanco y negro en un UIImage. Tengo una vista en la que el usuario toma una foto, pero no tengo ninguna idea sobre cómo transformar los colores de la imagen.

- (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title = NSLocalizedString(@"#Paint!", nil); imageView.image = image; }

¿Cómo puedo hacer eso?


A juzgar por la etiqueta ciimage , ¿quizás el OP estaba pensando (correctamente) que Core Image proporcionaría una forma rápida y fácil de hacer esto?

Aquí está eso, tanto en ObjC:

- (UIImage *)grayscaleImage:(UIImage *)image { CIImage *ciImage = [[CIImage alloc] initWithImage:image]; CIImage *grayscale = [ciImage imageByApplyingFilter:@"CIColorControls" withInputParameters: @{kCIInputSaturationKey : @0.0}]; return [UIImage imageWithCIImage:grayscale]; }

y Swift:

func grayscaleImage(image: UIImage) -> UIImage { let ciImage = CIImage(image: image) let grayscale = ciImage.imageByApplyingFilter("CIColorControls", withInputParameters: [ kCIInputSaturationKey: 0.0 ]) return UIImage(CIImage: grayscale) }

CIColorControls es solo uno de los varios filtros de imagen central integrados que pueden convertir una imagen a escala de grises. CIPhotoEffectMono , CIPhotoEffectNoir y CIPhotoEffectTonal son diferentes ajustes preestablecidos de mapeo de tonos (cada uno no tiene parámetros), y puedes hacer tu propio mapeo de tonos con filtros como CIColorMap .

A diferencia de las alternativas que implican crear y dibujar en el propio CGBitmapContext , estas conservan el tamaño / escala y el alfa de la imagen original sin trabajo adicional.


Aquí está la versión rápida de 1.2

/// convert background image to gray scale /// /// param: flag if true, image will be rendered in grays scale func convertBackgroundColorToGrayScale(flag: Bool) { if flag == true { let imageRect = self.myImage.frame let colorSpace = CGColorSpaceCreateDeviceGray() let width = imageRect.width let height = imageRect.height let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.None.rawValue) var context = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, colorSpace, bitmapInfo) let image = self.musicBackgroundColor.image!.CGImage CGContextDrawImage(context, imageRect, image) let imageRef = CGBitmapContextCreateImage(context) let newImage = UIImage(CGImage: CGImageCreateCopy(imageRef)) self.myImage.image = newImage } else { // do something else } }


Este código (objetivo c) funciona:

CIImage * ciimage = ...; CIFilter * filter = [CIFilter filterWithName:@"CIColorControls" withInputParameters:@{kCIInputSaturationKey : @0.0,kCIInputContrastKey : @10.0,kCIInputImageKey : ciimage}]; CIImage * grayscale = [filtre outputImage];

El kCIInputContrastKey : @10.0 es para obtener una imagen casi en blanco y negro.


La versión de @rickster se ve bien considerando el canal alfa. Pero un UIImageView sin .AspectFit o Fill contentMode no puede mostrarlo. Por lo tanto, el UIImage tiene que ser creado con un CGImage. Esta versión implementada como extensión Swift UIImage mantiene la escala actual y proporciona algunos parámetros de entrada opcionales:

import CoreImage extension UIImage { /// Applies grayscale with CIColorControls by settings saturation to 0.0. /// - Parameter brightness: Default is 0.0. /// - Parameter contrast: Default is 1.0. /// - Returns: The grayscale image of self if available. func grayscaleImage(brightness: Double = 0.0, contrast: Double = 1.0) -> UIImage? { if let ciImage = CoreImage.CIImage(image: self, options: nil) { let paramsColor: [String : AnyObject] = [ kCIInputBrightnessKey: NSNumber(double: brightness), kCIInputContrastKey: NSNumber(double: contrast), kCIInputSaturationKey: NSNumber(double: 0.0) ] let grayscale = ciImage.imageByApplyingFilter("CIColorControls", withInputParameters: paramsColor) let processedCGImage = CIContext().createCGImage(grayscale, fromRect: grayscale.extent) return UIImage(CGImage: processedCGImage, scale: self.scale, orientation: self.imageOrientation) } return nil } }

La forma más larga pero más rápida es la versión modificada de la respuesta de @ChrisStillwells. Implementado como una extensión UIImage considerando el canal alfa y la escala actual en Swift:

extension UIImage { /// Create a grayscale image with alpha channel. Is 5 times faster than grayscaleImage(). /// - Returns: The grayscale image of self if available. func convertToGrayScale() -> UIImage? { // Create image rectangle with current image width/height * scale let pixelSize = CGSize(width: self.size.width * self.scale, height: self.size.height * self.scale) let imageRect = CGRect(origin: CGPointZero, size: pixelSize) // Grayscale color space if let colorSpace: CGColorSpaceRef = CGColorSpaceCreateDeviceGray() { // Create bitmap content with current image size and grayscale colorspace let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.None.rawValue) if let context: CGContextRef = CGBitmapContextCreate(nil, Int(pixelSize.width), Int(pixelSize.height), 8, 0, colorSpace, bitmapInfo.rawValue) { // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) CGContextDrawImage(context, imageRect, self.CGImage) // Create bitmap image info from pixel data in current context if let imageRef: CGImageRef = CGBitmapContextCreateImage(context) { let bitmapInfoAlphaOnly = CGBitmapInfo(rawValue: CGImageAlphaInfo.Only.rawValue) if let contextAlpha = CGBitmapContextCreate(nil, Int(pixelSize.width), Int(pixelSize.height), 8, 0, nil, bitmapInfoAlphaOnly.rawValue) { CGContextDrawImage(contextAlpha, imageRect, self.CGImage) if let mask: CGImageRef = CGBitmapContextCreateImage(contextAlpha) { // Create a new UIImage object if let newCGImage = CGImageCreateWithMask(imageRef, mask) { // Return the new grayscale image return UIImage(CGImage: newCGImage, scale: self.scale, orientation: self.imageOrientation) } } } } } } // A required variable was unexpected nil return nil } }


Mientras la solución de PiratM funciona, se pierde el canal alfa. Para preservar el canal alfa necesitas hacer algunos pasos adicionales.

+(UIImage *)convertImageToGrayScale:(UIImage *)image { // Create image rectangle with current image width/height CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height); // Grayscale color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); // Create bitmap content with current image size and grayscale colorspace CGContextRef context = CGBitmapContextCreate(nil, image.size.width, image.size.height, 8, 0, colorSpace, kCGImageAlphaNone); // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) CGContextDrawImage(context, imageRect, [image CGImage]); // Create bitmap image info from pixel data in current context CGImageRef imageRef = CGBitmapContextCreateImage(context); // Release colorspace, context and bitmap information CGColorSpaceRelease(colorSpace); CGContextRelease(context); context = CGBitmapContextCreate(nil,image.size.width, image.size.height, 8, 0, nil, kCGImageAlphaOnly ); CGContextDrawImage(context, imageRect, [image CGImage]); CGImageRef mask = CGBitmapContextCreateImage(context); // Create a new UIImage object UIImage *newImage = [UIImage imageWithCGImage:CGImageCreateWithMask(imageRef, mask)]; CGImageRelease(imageRef); CGImageRelease(mask); // Return the new grayscale image return newImage; }


Versión Swift 3.0:

extension UIImage { func convertedToGrayImage() -> UIImage? { let width = self.size.width let height = self.size.height let rect = CGRect(x: 0.0, y: 0.0, width: width, height: height) let colorSpace = CGColorSpaceCreateDeviceGray() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue) guard let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else { return nil } guard let cgImage = cgImage else { return nil } context.draw(cgImage, in: rect) guard let imageRef = context.makeImage() else { return nil } let newImage = UIImage(cgImage: imageRef.copy()!) return newImage } }


en swift 3.0

func convertImageToGrayScale(image: UIImage) -> UIImage { // Create image rectangle with current image width/height let imageRect = CGRect(x: 0, y: 0,width: image.size.width, height : image.size.height) // Grayscale color space let colorSpace = CGColorSpaceCreateDeviceGray() // Create bitmap content with current image size and grayscale colorspace let context = CGContext(data: nil, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.none.rawValue) // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) context?.draw(image.cgImage!, in: imageRect) // Create bitmap image info from pixel data in current context let imageRef = context!.makeImage() // Create a new UIImage object let newImage = UIImage(cgImage: imageRef!) // Release colorspace, context and bitmap information //MARK: ToolBar Button Methods // Return the new grayscale image return newImage }


C objetivo

- (UIImage *)convertImageToGrayScale:(UIImage *)image { // Create image rectangle with current image width/height CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height); // Grayscale color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); // Create bitmap content with current image size and grayscale colorspace CGContextRef context = CGBitmapContextCreate(nil, image.size.width, image.size.height, 8, 0, colorSpace, kCGImageAlphaNone); // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) CGContextDrawImage(context, imageRect, [image CGImage]); // Create bitmap image info from pixel data in current context CGImageRef imageRef = CGBitmapContextCreateImage(context); // Create a new UIImage object UIImage *newImage = [UIImage imageWithCGImage:imageRef]; // Release colorspace, context and bitmap information CGColorSpaceRelease(colorSpace); CGContextRelease(context); CFRelease(imageRef); // Return the new grayscale image return newImage; }

Rápido

func convertToGrayScale(image: UIImage) -> UIImage { // Create image rectangle with current image width/height let imageRect:CGRect = CGRect(x:0, y:0, width:image.size.width, height: image.size.height) // Grayscale color space let colorSpace = CGColorSpaceCreateDeviceGray() let width = image.size.width let height = image.size.height // Create bitmap content with current image size and grayscale colorspace let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue) // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) context?.draw(image.cgImage!, in: imageRect) let imageRef = context!.makeImage() // Create a new UIImage object let newImage = UIImage(cgImage: imageRef!) return newImage }


Solución Swift 4

extension UIImage { var withGrayscale: UIImage { guard let ciImage = CIImage(image: self, options: nil) else { return self } let paramsColor: [String: AnyObject] = [kCIInputBrightnessKey: NSNumber(value: 0.0), kCIInputContrastKey: NSNumber(value: 1.0), kCIInputSaturationKey: NSNumber(value: 0.0)] let grayscale = ciImage.applyingFilter("CIColorControls", parameters: paramsColor) guard let processedCGImage = CIContext().createCGImage(grayscale, from: grayscale.extent) else { return self } return UIImage(cgImage: processedCGImage, scale: scale, orientation: imageOrientation) } }