Правильная фильтрация NSImage / CIImage с использованием CIFilter и CISpotColor

Обратите внимание: это для приложения командной строки Cocoa, работающего в Mac OSX, а НЕ для приложения iOS

У меня проблемы с пониманием Ограниченная документация, предоставленная Apple для фильтра CISpotColor (с использованием CIFilter).


TL DR;

1) Есть ли еще документация о CIFilter, в частности о CISpotColor, которую мне где-то не хватает?

2) Учитывая то, чего я пытаюсь достичь (описывается ниже в виде иллюстраций, но кратко: замените все, что не «выглядит красным» на белое, и заставьте все, что «выглядит красным (иш)», либо сплошным красным, либо просто черным) , подходит ли CISpotColor фильтр, который мне следует использовать?

3) Если нет, то какие фильтры вы предлагаете (или я должен попробовать создать собственный?)

4) Если CISSpotColor - правильный фильтр, какие параметры мне следует использовать для достижения того, чего я пытаюсь достичь. Если мне нужно использовать несколько проходов CISpotColor CIFilter, ничего страшного, я не ожидаю, что вы напишете его для меня, просто укажите правильное направление.


Более подробная информация и справочная информация по вышеуказанным вопросам:

ссылка выше дает список параметров, некоторые значения по умолчанию, а также пример изображения до и после изображения, но без образца кода, который генерировал образец после изображения, и без объяснения того, что на самом деле означают параметры или каковы их допустимые диапазоны.

Честно говоря, я не совсем уверен, является ли CISpotColor тем фильтром, который мне нужен, поскольку кроме его имени и предложения «Заменяет один или несколько цветовых диапазонов на плашечные цвета» нет никаких объяснений. о том, как он делает то, что делает.

Поскольку это фильтр, который, кажется, описывает то, что мне нужно, я выбрал его в качестве отправной точки, чтобы понять, как работать с фильтрами таким образом.

Введите изображение (кадр из видео) введите описание изображения здесь

Желаемый результат (вариант 1 - сплошной красный - создано с помощью GIMP) введите описание изображения здесь

Желаемый результат (вариант 2 - сплошной черный - также создается с помощью GIMP) введите здесь описание изображения

Что я получаю с помощью своего кода (список см. ниже) введите описание изображения здесь

Это близко к тому, что мне нужно, но, похоже, не учитывается тот факт, что области, которые являются серыми или «белыми» на исходном изображении, будут иметь одинаковое количество красного, зеленого и синего, а не преимущественно красного, что сделало бы его "красным". Я мог бы работать с ним, если бы он отфильтровал область, которую вы видите в правом нижнем углу, которая явно просто включена, потому что там есть некоторые красные пиксели (а также некоторые зеленые и синие, что делает его обычно серым в оригинале) .

Вот полный файл main.m для приложения командной строки какао (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;
}

person unsynchronized    schedule 25.05.2014    source источник
comment
Я нашел обходной путь, который, кажется, работает, но неясно, почему - если вы установите одинаковые настройки для всех inputCenterColor1, inputCenterColor2 и inputCenterColor1 (используя color = [1.0,0.0,0.0], closeness = 0.5 и Contrast = 1.0), все работает. Не уверен, почему вам нужно делать все 3, если у вас есть какие-то идеи, было бы полезно. он также позволяет вам делать то же самое для зеленого и синего, и, кажется, он правильно фильтрует по желанию (для моего случая использования). Я оставлю этот вопрос открытым для других поисковиков / авторов.   -  person unsynchronized    schedule 25.05.2014


Ответы (2)


CISpotColor по сути выполняет четыре операции с цветом:

  1. замените все цвета, близкие к inputCenterColor1, на inputReplacementColor1.
  2. замените все цвета, близкие к inputCenterColor2, на inputReplacementColor2.
  3. замените все цвета, близкие к inputCenterColor3, на inputReplacementColor3.
  4. все остальное заменить на белое.

По умолчанию для входных цветов заданы различные красноватые / розоватые оттенки. Вы можете найти их, изучив эти значения фильтра в коде после его создания и вызова setDefaults, но для простоты иллюстрации здесь все значения по умолчанию на снимке экрана из Core Image Fun House пример кода приложения:

Значения по умолчанию CISpotColor

Применив фильтр с параметрами по умолчанию, вы получите следующее:

отфильтровано по умолчанию

Обратите внимание, что красное кольцо (часть, которую вы пытаетесь сделать единственным оставшимся элементом изображения) выглядит как inputReplacementColor3 по умолчанию, а освещенные области в правом нижнем углу выглядят как _10 _... по умолчанию, точно так же, как и в ваше выходное изображение. Это потому, что вы настроили только первую пару центральных / замещающих цветов, а для остальных двух оставили красноватые / розоватые значения по умолчанию.

Если вы хотите отключить замену второго и третьего цветов, уменьшите их параметр Closeness до 0,0 и / или их параметр Contrast до 1,0. На всякий случай можно также установить для их Цвет центра то, чего нет на вашем изображении. Я считаю, что на вашем тестовом изображении достаточно просто уменьшить значение Closeness:

новые настройки

Это дает следующий результат:

новый вывод

Между прочим, подобная замена плашечных цветов - это своего рода простая форма операции Color LookUp Table (CLUT), которая реализуется с помощью _ 11_ фильтр. Если вы хотите иметь возможность тонко настраивать замену цвета сверх того, что предоставляет CISpotColor, вариант цветового куба может быть хорошей ставкой. Есть руководство по его использованию для эффекта зеленого экрана в руководстве по программированию Apple.

TL; DR:

  1. Установите соответствующие значения для всех параметров фильтра, а не только для первых нескольких, или другие значения по умолчанию могут сделать то, чего вы не ожидаете. Установка inputCloseness2 и inputCloseness3 на ноль и оставление всего остального по умолчанию (но для input...1 параметров, которые вы уже установили), похоже, работает для вашего тестового изображения.

  2. Наличие живой тестовой среды для ваших фильтров действительно поможет вам точно настроить параметры (и убедиться, что значения по умолчанию соответствуют вашим ожиданиям). Для этого отлично подходит Core Image Fun House.

person rickster    schedule 22.02.2016

Вы правы, документации по-прежнему нет. например, использование просто «дома забавы с основным изображением» в качестве источника информации не даст вам указания на то, что чрезвычайно важно, какой цвет вы добавляете во входную точку 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"];
person hokkuk    schedule 22.02.2016