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)

¿Qué tal un enlace al hilo separado de la rutina del kernel? – JWWalker
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
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