【问题标题】:Correctly filtering NSImage/CIImage using CIFilter and CISpotColor使用 CIFilter 和 CISpotColor 正确过滤 NSImage/CIImage
【发布时间】:2014-07-14 03:22:34
【问题描述】:

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

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


TL 博士;

1) 我在某处缺少关于 CIFilter 的更多文档,特别是 CISpotColor?

2) 鉴于我想要实现的目标(如下图所示,但简要描述:用白色替换所有不“看起来红色”的东西,并将所有“看起来红色(ish)”的东西强制为纯红色,或只是黑色),CISpotColor 是我应该使用的正确滤镜吗?

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

4) 如果 CISSpotColor 是正确的过滤器,我应该使用什么参数来实现我想要实现的目标。如果我需要使用 CISpotColor CIFilter 的多次传递,那很好,我不希望您为我编写代码,只需为我指明正确的方向即可。


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

link above 给出了参数列表、一些默认值和图片前后的示例,但没有生成后图片示例的示例代码,也没有解释参数的实际含义或它们的有效性范围是。

说实话,我不完全确定 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;
}

【问题讨论】:

  • 我找到了一个似乎可行的解决方法,但不清楚为什么 - 如果您设置为所有 inputCenterColor1、inputCenterColor2 和 inputCenterColor1 定义相同的设置(使用 color=[1.0,0.0,0.0 ],closeness = 0.5 and contrast=1.0),它有效。不知道为什么你需要做所有 3,如果你有任何见解,会有所帮助。它还可以让您对绿色和蓝色执行相同的操作,并且它似乎可以根据需要正确过滤(供我使用)。我将把这个问题留给其他搜索者/发帖者。

标签: objective-c xcode macos image-processing cifilter


【解决方案1】:

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

  1. 将所有接近inputCenterColor1 的颜色替换为inputReplacementColor1
  2. 将所有接近inputCenterColor2 的颜色替换为inputReplacementColor2
  3. 将所有靠近inputCenterColor3 的颜色替换为inputReplacementColor3
  4. 用白色替换其他所有内容。

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

使用默认选项应用过滤器可以得到:

请注意,红色圆环(您试图成为图像中唯一剩余元素的部分)看起来像默认的inputReplacementColor3,右下角的亮区看起来像默认的inputReplacementColor2。 .. 就像他们在your output image 中所做的一样。这是因为您只配置了第一对中心/替换颜色,而将其他两个保留为红色/粉红色默认值。

如果您想禁用第二和第三颜色替换,请将它们的 Closeness 参数调低到 0.0 和/或将它们的 Contrast 参数调高到 1.0。为了安全起见,您还可以将它们的 Center Color 设置为不会出现在图像中的颜色。在您的测试图像中,我发现只需调低 Closeness 就足够了:

这会得到以下输出:

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

TLDR:

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

  2. 为您的过滤器提供实时测试环境确实可以帮助您微调参数(并确保默认值符合您的预期)。 Core Image Fun House 非常适合。

【讨论】:

    【解决方案2】:

    你是对的,仍然没有文档。例如,仅使用“core image fun house”作为您的信息来源不会告诉您在输入点 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"];
    

    【讨论】:

      猜你喜欢
      • 2023-03-17
      • 2011-09-01
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-13
      • 2010-11-27
      相关资源
      最近更新 更多