2010-06-27 13 views
9

Tengo un CIImage que necesito para convertir de color a blanco y negro en mi programa Cocoa/Object C. Peter H. anteriormente me señaló este enlace http://www.codingadventures.com/2008/06/threshold-filter-in-glsl/ como una posible solución ... pero estoy teniendo problemas para compilar la rutina del núcleo allí (ver hilo separado, si está interesado).Filtro CI para crear una imagen en blanco y negro?

Así que me pregunto si uno de los otros CIFilters incorporados logrará lo que estoy tratando de hacer. No quiero una imagen en escala de grises ... Quiero que cada píxel en la imagen de resultados sea negro o blanco; solo necesito poder decirle al filtro cómo determinar qué píxeles se volverán negros y cuáles se volverán blancos. . El filtro "Umbral" en Photoshop hace exactamente esto: me permite especificar el "umbral" y luego usa este valor para decidir qué píxeles se vuelven blancos y cuáles se vuelven negros. Esto es lo que trato de "replicar" a través del código en mi proyecto de Xcode.

¿Alguna idea de si uno de los otros filtros incorporados se puede utilizar para esto? Gracias.

+0

¿Qué tal un enlace al hilo separado de la rutina del kernel? – JWWalker

+0

Aquí hay un enlace al otro hilo: http://stackoverflow.com/questions/2963218/applying-transformations-to-nsbitmapimagerep Siga el hipervínculo detrás del "filtro de umbral" – Adam

+0

Quartz Composer es un gran lugar para experimentar con Core Image filtros. Lo usé para probar el filtro de umbral dado por el enlace. Hubo un error de compilación, causado por lo que parecía ser un signo menos pero en realidad era un personaje en el tablero. Una vez que lo arreglé, funcionó. – JWWalker

Respuesta

10

Puede usar el CIColorMap filter. Dale un 20 (w) por 1 (h) jpg donde la mitad izquierda es blanca y la mitad derecha es negra (o al revés) y úsala como el degradado del mapa de color. Eso parece reducir los colores muy bien. Originalmente probé una imagen de 2x1 con 1 píxel blanco y uno negro, pero parecía que se interpolaba un poco. Subí a 20x1 y funcionó bien.

Sugerencia: utilicé Core Image Funhouse (no Quartz Composer) para experimentar.

+0

Hmmm. He estado jugando con la técnica sugerida y no está produciendo los resultados que esperaba. He intentado 1x2 blanco-negro y blanco-negro (intercambiando el orden) --- y 1x20 negro-blanco y negro-blanco ¿Hay alguna documentación en línea disponible que describa cómo debería funcionar el mapa de degradado? O ejemplos? – Adam

+0

Publique el código que está utilizando para configurar todo esto. Funciona bien en Core Image Fun House, que es solo un contenedor GUI básico para probar los filtros de CI existentes –

+0

Después de una experimentación adicional, creo que el problema puede ser con mi filtro de gradiente de imagen fuente, en lugar de mi código. Usando FunHouse, si aplico mi filtro de degradado al incluida la imagen Copenhagen.jpg .. .hecho exactamente lo que quiero. Sin embargo, si aplico el mismo filtro a mi propia imagen (la que necesito modificar en mi programa) ... no se comporta de la misma manera. La transformación hace que mi imagen sea completamente blanca o totalmente negra (dependiendo de si el lado izquierdo de mi degradado de 1x20 es blanco o negro). para continuar ... – Adam

6

Tomó algo de tiempo para descubrir el código de CIColorMap, así que quería publicar esto. Joshua tiene la respuesta anterior. Este es solo un ejemplo de implementación ...

CIImage *beginImage = [CIImage imageWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"wedding" ofType:@"jpg"]]]; 
CIImage *inputGradientImage = [CIImage imageWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"grad" ofType:@"png"]]]; 
CIContext *context = [CIContext contextWithOptions:nil]; 
CIFilter *filter = [CIFilter filterWithName:@"CIColorMap" keysAndValues:kCIInputImageKey, beginImage, @"inputGradientImage",inputGradientImage, nil]; 
CIImage *outputImage = [filter outputImage]; 
CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]]; 
UIImage *newImage = [UIImage imageWithCGImage:cgimg]; 
self.imageView.image = newImage; 
CGImageRelease(cgimg); 
5

Muchas soluciones en Internet crean valores de escala de grises. No hay necesidad de filtros. Si necesita tal que el código de uso, tales como

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); 
CGImageRef greyImage = CGImageCreateCopyWithColorSpace(backingImage, colorSpace); 
CGColorSpaceRelease(colorSpace); 

filtro de umbral adecuado sigue: inputThreshold puede ser de valor flotante 0.0f a 0.5f

https://gist.github.com/xhruso00/a3f8a9c8ae7e33b8b23d

receta detallada se puede encontrar en https://developer.apple.com/library/ios/documentation/graphicsimaging/Conceptual/CoreImaging/ci_custom_filters/ci_custom_filters.html#//apple_ref/doc/uid/TP30001185-CH6-CJBEDHHH

#import "BlackAndWhiteThresholdFilter.h" 



@interface BlackAndWhiteThresholdFilter() 
{ 
    CIKernel *_kernel; 
} 

@end 

@implementation BlackAndWhiteThresholdFilter { 
    NSNumber *inputThreshold; 
    CIImage *inputImage; 
} 


//more https://developer.apple.com/library/ios/documentation/graphicsimaging/Conceptual/CoreImaging/ci_image_units/ci_image_units.html#//apple_ref/doc/uid/TP30001185-CH7-SW8 
+ (void)registerFilter 
{ 
    NSDictionary *attributes = @{ 
           kCIAttributeFilterCategories: @[ 
            kCICategoryVideo, 
            kCICategoryStillImage, 
            kCICategoryCompositeOperation, 
            kCICategoryInterlaced, 
            kCICategoryNonSquarePixels 
            ], 
           kCIAttributeFilterDisplayName: @"Black & White Threshold", 

           }; 

    [CIFilter registerFilterName:@"BlackAndWhiteThreshold" 
        constructor:(id <CIFilterConstructor>)self 
       classAttributes:attributes]; 
} 


+ (CIFilter *)filterWithName:(NSString *)aName 
{ 
    CIFilter *filter; 
    filter = [[self alloc] init]; 

    return filter; 
} 

- (instancetype)init { 
    self = [super init]; 
    if (self) { 
    NSString *kernelText = @"kernel vec4 thresholdKernel(sampler image, float inputThreshold)\n" 
    "{\n" 
    " float pass = 1.0;\n" 
    " float fail = 0.0;\n" 
    " const vec4 vec_Y = vec4(0.299, 0.587, 0.114, 0.0);\n" 
    " vec4  src = unpremultiply(sample(image, samplerCoord(image)));\n" 
    " float  Y = dot(src, vec_Y);\n" 
    " src.rgb = vec3(compare(Y - inputThreshold, fail, pass));\n" 
    " return premultiply(src);\n" 
    "}"; 

     _kernel = [[CIKernel kernelsWithString:kernelText] objectAtIndex:0]; 
    } 

    return self; 
} 

- (NSArray *)inputKeys { 
    return @[@"inputImage",@"inputThreshold"]; 
} 

- (NSArray *)outputKeys { 
    return @[@"outputImage"]; 
} 


- (NSDictionary *)customAttributes 
{ 
    NSDictionary *thresholDictionary = @{ 
             kCIAttributeType: kCIAttributeTypeScalar, 
             kCIAttributeMin: @0.0f, 
             kCIAttributeMax: @1.0f, 
             kCIAttributeIdentity : @0.00, 
             kCIAttributeDefault: @0.5f, 
             }; 

    return @{ 
      @"inputThreshold": thresholDictionary, 
      // This is needed because the filter is registered under a different name than the class. 
      kCIAttributeFilterName : @"BlackAndWhiteThreshold" 
      }; 
} 

- (CIImage *)outputImage { 
    if (inputImage == nil) { 
    return nil; 
    } 

    CISampler *sampler; 

    sampler = [CISampler samplerWithImage:inputImage]; 

    NSArray * outputExtent = [NSArray arrayWithObjects: 
          [NSNumber numberWithInt:[inputImage extent].origin.x], 
          [NSNumber numberWithInt:[inputImage extent].origin.y], 
          [NSNumber numberWithFloat:[inputImage extent].size.width], 
          [NSNumber numberWithFloat:[inputImage extent].size.height],nil]; 


    CIImage *outputImage = [self apply: _kernel, 
      sampler, 
      inputThreshold, 
      kCIApplyOptionExtent, outputExtent, 
      kCIApplyOptionDefinition, [sampler definition], 
      nil]; 


    return outputImage; 
} 

@end 

actualiza con diferencia visual entre negro & WH ite (izquierda) y en escala de grises (derecha)

enter image description here

+0

"No hay necesidad de filtros". Su solución * usa * filtros. ¿Qué me estoy perdiendo? –

+0

Tienes razón. Me expresé algo mal. Las primeras tres líneas con el "CGImageCreateCopyWithColorSpace" son para crear una imagen en escala de grises, que es lo que hacen muchas soluciones en Internet. El código a continuación es CIFilter para crear una imagen en blanco negro adecuada de acuerdo con los valores de umbral. –

Cuestiones relacionadas