CI过滤器创建黑白图像?

时间:2021-04-14 00:24:07

I have a CIImage I need to convert from color to Black and White within my Cocoa / objective C program. Peter H. previously pointed me to this link http://www.codingadventures.com/2008/06/threshold-filter-in-glsl/ as a potential solution ... but I am having trouble compiling the kernel routine there (see separate thread, if interested).

我有一个CIImage我需要在我的Cocoa / Objective C程序中从颜色转换为Black和White。 Peter H.之前向我指出了这个链接http://www.codingadventures.com/2008/06/threshold-filter-in-glsl/作为一种潜在的解决方案......但是我在那里编译内核例程时遇到了问题(参见单独的线程,如果感兴趣)。

So I am wondering if one of the other built-in CIFilters will accomplish what I'm trying to do. I don't want a grayscale image ... I want each pixel in the Result image to be either Black or White -- I just need to be able to tell the filter how to determine which pixels should become black and which should become white. The "Threshold" filter in Photoshop does exactly this -- it lets me specify the "threshold" and then it uses this value to decide which pixels become white and which become black. This is what I am trying to "replicate" via code in my Xcode project.

所以我想知道其他一个内置的CIFilter是否会完成我想要做的事情。我不想要灰度图像...我希望结果图像中的每个像素都是黑色或白色 - 我只需要能够告诉过滤器如何确定哪些像素应该变成黑色哪个像素应该变成白色。 Photoshop中的“阈值”滤镜就是这样 - 它让我指定“阈值”,然后使用此值来确定哪些像素变为白色,哪些像素变为黑色。这就是我试图通过我的Xcode项目中的代码“复制”的内容。

Any ideas if one of the other built in filters can be used for this? Thanks.

如果其中一个内置过滤器可以用于此任何想法?谢谢。

3 个解决方案

#1


10  

You can use the CIColorMap filter. Give it a 20(w) by 1(h) jpg where the left half is white and the right half is black (or the other way around) and use that as your color map gradient. That seems to hammer down the colors nicely. I originally tried a 2x1 image with 1 white pixel and one black, but it looked like it got interpolated a bit. I went up to 20x1 and it worked fine.

您可以使用CIColorMap过滤器。给它一个20(w)乘1(h)的jpg,其中左半部分是白色而右半部分是黑色(或者相反),并将其用作颜色图渐变。这似乎很好地打破了颜色。我最初尝试使用1个白色像素和一个黑色的2x1图像,但看起来它有点内插。我上升到20x1,它工作正常。

Hint: I used Core Image Funhouse (not Quartz Composer) to experiment.

提示:我使用Core Image Funhouse(不是Quartz Composer)进行实验。

#2


6  

Took some time to figure out the code for CIColorMap so i wanted to post this. Joshua has the answer above. This is just an example of implementation...

花了一些时间来弄清楚CIColorMap的代码,所以我想发布这个。约书亚有上面的答案。这只是实施的一个例子......

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);

#3


5  

Many solutions on the internet create grayscale values. There is no need for filters. If you need such than use code such as

互联网上的许多解决方案都会创建灰度值。不需要过滤器。如果你需要使用这样的代码,比如

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

Proper threshold filter follows: inputThreshold can be float value from 0.0f to 0.5f

正确的阈值过滤器如下:inputThreshold可以是从0.0f到0.5f的浮点值

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

Detailed recipe can be found at https://developer.apple.com/library/ios/documentation/graphicsimaging/Conceptual/CoreImaging/ci_custom_filters/ci_custom_filters.html#//apple_ref/doc/uid/TP30001185-CH6-CJBEDHHH

详细的食谱可以在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

Updated with visual difference between black&white(left) and grayscale(right)

更新了黑白(左)和灰度(右)之间的视觉差异

CI过滤器创建黑白图像?

#1


10  

You can use the CIColorMap filter. Give it a 20(w) by 1(h) jpg where the left half is white and the right half is black (or the other way around) and use that as your color map gradient. That seems to hammer down the colors nicely. I originally tried a 2x1 image with 1 white pixel and one black, but it looked like it got interpolated a bit. I went up to 20x1 and it worked fine.

您可以使用CIColorMap过滤器。给它一个20(w)乘1(h)的jpg,其中左半部分是白色而右半部分是黑色(或者相反),并将其用作颜色图渐变。这似乎很好地打破了颜色。我最初尝试使用1个白色像素和一个黑色的2x1图像,但看起来它有点内插。我上升到20x1,它工作正常。

Hint: I used Core Image Funhouse (not Quartz Composer) to experiment.

提示:我使用Core Image Funhouse(不是Quartz Composer)进行实验。

#2


6  

Took some time to figure out the code for CIColorMap so i wanted to post this. Joshua has the answer above. This is just an example of implementation...

花了一些时间来弄清楚CIColorMap的代码,所以我想发布这个。约书亚有上面的答案。这只是实施的一个例子......

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);

#3


5  

Many solutions on the internet create grayscale values. There is no need for filters. If you need such than use code such as

互联网上的许多解决方案都会创建灰度值。不需要过滤器。如果你需要使用这样的代码,比如

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

Proper threshold filter follows: inputThreshold can be float value from 0.0f to 0.5f

正确的阈值过滤器如下:inputThreshold可以是从0.0f到0.5f的浮点值

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

Detailed recipe can be found at https://developer.apple.com/library/ios/documentation/graphicsimaging/Conceptual/CoreImaging/ci_custom_filters/ci_custom_filters.html#//apple_ref/doc/uid/TP30001185-CH6-CJBEDHHH

详细的食谱可以在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

Updated with visual difference between black&white(left) and grayscale(right)

更新了黑白(左)和灰度(右)之间的视觉差异

CI过滤器创建黑白图像?