首页 文章

使用CIFilter和CISpotColor正确过滤NSImage / CIImage

提问于
浏览
5

Please note: 这适用于在Mac OSX上运行的Cocoa命令行应用程序,并且 NOT an iOS app

我在尝试理解Apple为 CISpotColor 过滤器(使用 CIFilter )提供的Limited Documentation时遇到了一些麻烦 .


TL DR;

1)是否有更多关于CIFilter遗漏的文档,特别是CISpotColor?

2)考虑到我想要实现的目标(如下图所示,但简要说明:用白色替换所有不“看起来红”的东西,并将“看起来很红(ish)”的所有东西强制为纯红色或简单的黑色) ,CISpotColor是我应该使用的正确过滤器吗?

3)如果没有,你建议使用什么过滤器(或者我应该尝试编写自定义过滤器?)

4)如果CISSpotColor是正确的过滤器,我应该使用什么参数来实现我想要实现的目标 . 如果我需要使用CISpotColor CIFilter的几个通道,那很好,我不指望你为我编码,只是指出我正确的方向 .


以上问题的更多细节和背景:

link above给出了一个参数列表,一些默认值,以及图片之前和之后的示例,但没有在图像之后生成样本的示例代码,也没有解释参数实际意味着什么,或者它们的有效范围是什么 .

老实说,我不完全确定CISpotColor是否是我所追求的过滤器,除了它的名称和句子“ Replaces one or more color ranges with spot colors ”之外,没有解释它是如何做到的 .

因为它似乎描述了我所追求的过滤器,所以我选择它作为一个起点,让我以这种方式处理过滤器 .

Input picture (a frame from a video)
enter image description here

Desired output (option 1 - solid red - created using GIMP)
enter image description here

Desired output (option 2 - solid black - also created using GIMP)
enter image description here

What I am getting with my code (see below for listing)
enter image description here

这接近我所需要的,但它似乎没有考虑到原始图像中灰色或“白色”的区域具有相似数量的红色,绿色和蓝色,而不是主要是红色的事实 . 这将使它“看起来红” . 如果它过滤掉你在右下角看到的区域,我可以使用它,这显然只是包括在内,因为那里有一些红色像素(以及一些绿色和蓝色,使其在原始时通常为灰色) .

Here is the complete "main.m" for the cocoa command line app (Mac OSX)

#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <AppKit/AppKit.h>
#import <QuartzCore/QuartzCore.h>



@interface NSImage(saveAsJpegWithName)
- (void) saveAsPNGWithName:(NSString*) fileName;
- (NSImage*) filterEverythingButRed ;
@end

@implementation NSImage(saveAsJpegWithName)

- (void) saveAsPNGWithName:(NSString*) fileName
{
    NSData *imageData = [self TIFFRepresentation];
    NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
    NSDictionary *imageProps = nil;
    imageData = [imageRep representationUsingType:NSPNGFileType properties:imageProps];
    [imageData writeToFile:fileName atomically:NO];
}

-(NSImage*) filterEverythingButRed {

    CIImage *inputImage = [[CIImage alloc] initWithData:[self TIFFRepresentation]];

    CIFilter *hf = [CIFilter filterWithName:@"CISpotColor"];
    [hf setDefaults];
    [hf setValue:inputImage forKey:@"inputImage"];
    [hf setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"inputCenterColor1"];
    [hf setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"inputReplacementColor1"];
    [hf setValue:[NSNumber numberWithFloat:0.1] forKey: @"inputCloseness1"];
    [hf setValue:[NSNumber numberWithFloat:1.0] forKey: @"inputContrast1"];

    CIImage *outputImage = [hf valueForKey: @"outputImage"];

    NSImage *resultImage = [[NSImage alloc] initWithSize:[outputImage extent].size];
    NSCIImageRep *rep = [NSCIImageRep imageRepWithCIImage:outputImage];
    [resultImage addRepresentation:rep];

    return resultImage;
}

@end


int main(int argc, const char * argv[]) {


    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    if (argc == 1) {

        NSString * appname = [NSString stringWithFormat: @"%s", argv[0]];

        NSLog(@"Usage: %@ filename", appname);

    }  else {

        NSString * filename = [NSString stringWithFormat: @"%s", argv[1]];

        NSFileManager *fm = [NSFileManager defaultManager];

        if ([fm fileExistsAtPath:filename]) {

            NSLog(@"opening file:%@", filename);


            NSImage *img = [[NSImage alloc] initWithContentsOfFile:filename];

            [[img filterEverythingButRed]
             saveAsPNGWithName:[[filename stringByDeletingPathExtension] stringByAppendingString:@"-red.png"]];




        } else {

            NSLog(@"file not found:%@", filename);
        }

    }


    [pool release];
    return 0;
}

2 回答

  • -1

    CISpotColor 基本上做了四种颜色操作:

    • inputReplacementColor1 替换 inputCenterColor1 附近的所有颜色 .

    • inputReplacementColor2 替换 inputCenterColor2 附近的所有颜色 .

    • inputReplacementColor3 替换 inputCenterColor3 附近的所有颜色 .

    • 用白色替换其他所有东西 .

    默认情况下,输入颜色设置为各种偏红/粉红色调 . 您可以通过在构造它之后检查代码中的那些过滤器值并调用 setDefaults 来找到这些 - 但为了便于说明,这里是Core Image Fun House示例代码应用程序的屏幕截图中的所有默认值:

    CISpotColor defaults

    使用默认选项应用过滤器可以获得以下结果:

    filtered with defaults

    请注意,红色环(您试图成为图像中唯一剩余元素的部分)看起来像默认 inputReplacementColor3 ,右下方的亮起区域看起来像默认 inputReplacementColor2 ...就像它们在your output image . 那个's because you' ve只配置了第一对中心/替换颜色,你已经将其他两个颜色保留为红色/粉红色默认值 .

    如果要禁用第二和第三种颜色替换,请将其Closeness参数向下调整为0.0和/或将其Contrast参数调高至1.0 . 为安全起见,您还可以将其中心颜色设置为图像中未显示的内容 . 在您的测试图像中,我发现仅仅调低Closeness就足够了:

    new settings

    这得到以下输出:

    new output

    顺便说一下,像这样的专色替换是一种简单形式的Color LookUp Table(CLUT)操作,它由CIColorCube过滤器实现 . 如果您希望能够在 CISpotColor 提供的范围内微调颜色替换,那么颜色立方体选项可能是一个不错的选择 . 有一个关于将它用于绿屏效果的教程in Apple's programming guide .

    TLDR:

    • 为所有过滤器参数设置适当的值,而不仅仅是前几个,或者其他默认值可能会执行您不期望的事情 . 将 inputCloseness2inputCloseness3 设置为零并保留其他所有默认值(但对于您已设置的 input...1 参数)似乎适用于您的测试图像 .

    • 进行实时测试过滤器的环境确实可以帮助您微调参数(并确保默认值是您所期望的) . Core Image Fun House非常棒 .

  • 1

    你是对的,仍然没有文件 . 例如,使用“核心图像娱乐屋”作为您的信息来源不会给您一个指示,您输入点1中的颜色,以及输入点2中的哪种颜色非常重要...切换它们会给你一个结果差异很大,我在这个特殊的过滤器中发现了更多的问题 . 就像某些参数的“最大”值一样,代码更像是你所谓的“指南”而非实际规则 . :)使用“有趣的房子”作为一个来源,将让你走下一个有大约10个出口的兔子洞,没有迹象告诉你这些出口在哪里 .

    这里有一些笔记,我把疯狂的数字扔进这个过滤器,看看什么“卡在墙上” . (如果有人选择,需要更多)

    //-------------------------  picked up a red ski helmet in full sun,  included all shadows on helmet, and some yellow from sun..  near perfect mask,  but also picked up most skin tones.
            //--------------------------  used a color from the helmet color: 0.662745 0.188235 0.223529 1.0  then stretched values to normalize to have one color 1.0 --------------
            CIFilter *clampFilter1 = [CIFilter filterWithName:@"CISpotColor"];
    
    
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.09 blue:0.33] forKey: @"inputCenterColor1"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor1"];
            [clampFilter1 setValue:@(0.86) forKey: @"inputCloseness1"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast1"];
    
            [clampFilter1 setValue:@(0.00) forKey: @"inputCloseness2"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast2"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:0.00 green:1.0 blue:0.56] forKey: @"inputCenterColor3"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0] forKey: @"inputReplacementColor3"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputCloseness3"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast3"];
    
    
            //---------------------------- picked up a blue jacket total, including all the shadows, a near perfect mask of a fairly blue jacket all ranges  ---------------------------
            [clampFilter1 setValue:[CIColor colorWithRed:0.01 green:0.165 blue:1.0] forKey: @"inputCenterColor1"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:1.0] forKey: @"inputReplacementColor1"];
            [clampFilter1 setValue:@(0.86) forKey: @"inputCloseness1"];
            [clampFilter1 setValue:@(1.0) forKey: @"inputContrast1"];
    
            //---------------------------- did not need this input but experimenting and left it in to add other changes,  same with below experiments  ---------------------------
            [clampFilter1 setValue:[CIColor colorWithRed:0.01 green:0.165 blue:1.0] forKey: @"inputCenterColor2"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:1.0] forKey: @"inputReplacementColor2"];
            [clampFilter1 setValue:@(0.86) forKey: @"inputCloseness2"];
            [clampFilter1 setValue:@(1.0) forKey: @"inputContrast2"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.5 blue:0.5] forKey: @"inputCenterColor3"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0] forKey: @"inputReplacementColor3"];
            [clampFilter1 setValue:@(0.99) forKey: @"inputCloseness3"];
            [clampFilter1 setValue:@(0.99) forKey: @"inputContrast3"];
    
    
    
            //---------------------------- picked up all reds,  total,  including some purples,  also picked up all skin tones  -----------------------------------------------------------
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"inputCenterColor1"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor1"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness1"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast1"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"inputCenterColor2"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor2"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness2"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast2"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"inputCenterColor3"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor3"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness3"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast3"];
    
    
            //---------------------------- removed all reds,  total,  turned all blues all ranges.. to green  -----------------------------------------------------------
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor1"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor1"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness1"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast1"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor2"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor2"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness2"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast2"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor3"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor3"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness3"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast3"];
    
    
            //---------------------------- removed most reds,   but skin still some tint,  turned all blues all ranges to green  -----------------------------------------------------------
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor1"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor1"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness1"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast1"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor2"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor2"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness2"];
            [clampFilter1 setValue:@(0.80) forKey: @"inputContrast2"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor3"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor3"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness3"];
            [clampFilter1 setValue:@(0.99) forKey: @"inputContrast3"];
    
    
            //---------------------------- picked up  shadow blue/purple replaced with green  -----------------------------------------------------------
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor1"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor1"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness1"];
            [clampFilter1 setValue:@(1.00) forKey: @"inputContrast1"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0] forKey: @"inputCenterColor2"];
            [clampFilter1 setValue:[CIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor2"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness2"];
            [clampFilter1 setValue:@(0.80) forKey: @"inputContrast2"];
    
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"inputCenterColor3"];
            [clampFilter1 setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] forKey: @"inputReplacementColor3"];
            [clampFilter1 setValue:@(0.90) forKey: @"inputCloseness3"];
            [clampFilter1 setValue:@(0.99) forKey: @"inputContrast3"];
    

相关问题