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

uns*_*zed 5 macos xcode image-processing objective-c cifilter

请注意:这适用于在Mac OSX上运行的Cocoa命令行应用程序,而不是iOS应用程序

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


TL DR;

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

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

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

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


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

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

说实话,我不完全确定CISpotColor是否是我所追求的过滤器,除了它的名称,以及句子" 用专色替换一个或多个颜色范围 ",没有解释它是如何做的. .

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

输入图片(视频中的帧) 在此输入图像描述

期望的输出(选项1 - 纯红色 - 使用GIMP创建) 在此输入图像描述

期望的输出(选项2 - 纯黑色 - 也使用GIMP创建) 在此输入图像描述

我的代码得到了什么(见下面的列表) 在此输入图像描述

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

这是cocoa命令行应用程序(Mac OSX)的完整"main.m"

#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;
}
Run Code Online (Sandbox Code Playgroud)

hok*_*kuk -1

你是对的,仍然没有文档。例如,仅使用“核心图像有趣的房子”作为您的信息源不会向您表明在输入点 1 中放置哪种颜色以及在输入点 2 中放置哪种颜色极其重要...切换它们会给您一个结果截然不同,而且我在这个特定的过滤器中发现了更多问题。就像某些参数的“最大值”一样,代码更像是您所说的......“指南”而不是实际规则。:) 使用“fun house”作为来源,会让你进入一个大约有 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"];
Run Code Online (Sandbox Code Playgroud)