Запись части Objective C

Ядро, несмотря на то, что это - основа фильтра обработки изображений, становится модулем изображения только после того, как это должным образом упаковывается как плагин. Ваши самые важные задачи в упаковочном процессе состоят в том, чтобы скопировать Ваш kernel подпрограмма (или подпрограммы) в ядро скелетный файл, предоставленный XCode и изменить код в в реализации и интерфейсных файлах для фильтра. Существует несколько других задач по обслуживанию, которые необходимо будет выполнить, чтобы правильно категоризировать фильтр и идентифицировать модуль изображения как продукт. Необходимо будет также описать его входные параметры.

Эта глава обеспечивает обзор для шаблона модуля изображения в XCode и описывает содержание файлов фильтра. Затем это показывает, как создать эти модули изображения:

Прежде чем Вы будете следовать инструкциям в этой главе для записи части Objective C модуля изображения, необходимо понять как kernel подпрограммы обсуждены в записи работы Ядер.

Шаблон модуля изображения в XCode

XCode обеспечивает шаблон, упрощающий упаковочный процесс. Чтобы помочь Вам упаковать модуль изображения как плагин, XCode обеспечивает скелетные файлы и методы, которые необходимы, и называет файлы соответственно. Рисунок 3-1 показывает файлы, автоматически создаваемые XCode для названного проекта модуля изображения DetectiveLens.

Рисунок 3-1  файлы в проекте модуля изображения
The files in an image unit project

XCode автоматически называет файлы с помощью названия проекта, которое Вы предоставляете. Это файлы по умолчанию, предоставленные XCode:

Код по умолчанию для фильтра, подражающего эффекту забавного зеркала дома. Необходимо распознать подпрограмму ядра как тот же самый обсужденный в Перечислении 2-6. Проект создаст как допустимый модуль изображения без потребности в Вас изменить одну строку кода.

Рисунок 3-2  файл списка свойств по умолчанию
The default property list file

Интерфейс фильтра и файлы реализации, предоставленные XCode, являются теми, что необходимо настроить для Вашего kernel подпрограмма (или подпрограммы). Интерфейсный файл объявляет подкласс CIFilter. XCode автоматически называет подкласс <ProjectName>Filter. Например, если Вы предоставляете InvertColor как название проекта, интерфейсное использование файла InvertColorFilter как имя подкласса. Интерфейсный файл по умолчанию объявляет четыре переменные экземпляра для фильтра: inputImage, inputVector, inputWidth, и inputAmount, который, с точки зрения клиента фильтра, входные параметры к фильтру. Вы, возможно, должны удалить один или больше этих переменных экземпляра и добавить любого, которые необходимы Вашему модулю изображения.

Файл реализации содержит четыре метода, которые необходимо будет изменить в целях:

Следующие разделы показывают, как изменить файлы фильтра для трех типов модулей изображения:

Создание цветного модуля изображения инверсии

Цветной фильтр инверсии представляет один из самых простых модулей изображения, которые можно записать. Это использует kernel подпрограмма обсудила в цвете Инверсию. Если Вы смотрите на kernel подпрограмма, показанная в Перечислении 2-1, Вы будете видеть, что подпрограмма не использует входных параметров кроме входного изображения. Таким образом, нет никакой потребности предоставить a customAttributes метод. kernel подпрограмма отображает один исходный пиксель на целевой пиксель, который это в тех же координатах как исходный пиксель. В результате нет никакой потребности предоставить метод, вычисляющий ROI. Необходимо будет сделать модификации к файлу интерфейса фильтра и к outputImage метод в файле реализации фильтра. Значение по умолчанию init метод будет работать, как, при условии, что Вы не переименовываете ни одного из файлов, которые XCode автоматически называет для Вас.

Упаковывать цветную инверсию kernel подпрограмма как модуль изображения, выполните эти шаги:

  1. Запустите XCode и выберите File> New Project.

  2. В Окне помощника прокрутите к к Стандарту Плагины Apple, выберите Image Unit Plug-in for Objective C и нажмите Далее.

    The Xcode template for an image unit
  3. Войти InvertColor как название проекта и нажимают Finish.

    The project name for an image unit plug-in
  4. Откройтесь InvertColorFilterKernel.cikernel файл и замена код с кодом от Перечисления 2-1.

  5. Откройтесь InvertColor.h файл и удаляет все переменные экземпляра за исключением inputImage, поскольку этот фильтр не имеет никаких входных параметров кроме входного изображения. Тогда сохраните и закройте файл.

  6. Откройтесь InvertColor.m файл и удаляет regionOf:destRect:userInfo: и customAttributes методы.

  7. Измените outputImage метод так, чтобы это посмотрело следующим образом:

    - (CIImage *)outputImage
    {
        CISampler *src;
       // Create a sampler from the input image because a kernel routine takes
       // a sampler, not an image, as input
        src = [CISampler samplerWithImage:inputImage];
        // Use the apply: method on the CIFilter object
        return [self apply:_InvertColorFilterKernel, src, nil];
    }
  8. Сохраните и закройтесь InvertColor.m файл.

  9. Откройтесь Description.plist файл.

  10. Изменение CICategoryDistortionEffect к CICategoryColorEffect.

  11. Сохраните и закройтесь Description.plist файл.

  12. Откройтесь Description.strings файл.

  13. Введите локализованное имя дисплея для фильтра путем добавления следующего:

    "InvertColorFilter" = "Invert Color Filter";

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

  14. Сохраните и закройтесь Description.strings файл.

  15. Разработайте проект.

    Это должно успешно выполниться, если Вы не представили некоторые типографские ошибки.

  16. Выйдите из XCode.

  17. Найдите InvertColor.plugin файл в Вашем проекте. Если Вы хотите, переместите его в удобное расположение в целях проверки и тестирования.

  18. Удостоверьтесь, что модуль изображения допустим. (См. Проверку Модуля Изображения.)

  19. Установите проверенный модуль изображения в /Library/Graphics/Image Units/.

  20. Протестируйте модуль изображения. (См. Тестирование Модуля Изображения.)

Это - все, которое существует к созданию модуля изображения для простого фильтра! Считайте следующие разделы для создания модулей изображения для более сложных фильтров.

Создание модуля изображения Pixellate

Запись модуля изображения для упаковки пикселизирования kernel подпрограмма (см. Pixellate) немного более сложна, чем упаковка цветной инверсии kernel подпрограмма, потому что необходимо предоставить метод области интереса. Вспомните что пикселизирование kernel подпрограмма использует много пикселей из исходного изображения для вычислений значения каждого целевого пикселя. Число пикселей определяется точечным размером. Например, если точечный размер равняется 4, то kernel подпрограмма использует 16 пикселей из исходного изображения: 4 пикселя 4 пиксельными сетками. Вычисление работает хорошо, если целевой пиксель не в краю, когда не будет достаточного количества пикселей для выборки. Это - то, куда метод области интереса прибывает в игру. Если сетка пикселей будет всегда вставлена радиусом точечного размера, то Вы избежите проблемы не наличия достаточного количества пикселей для выборки.

Код в Перечислении 3-1 является методом области интереса, вызывающим Кварцевую функцию CGRectInset. Эта функция возвращает прямоугольник, который меньше или больше, чем прямоугольник передал ей. В этом случае метод ROI вставляет прямоугольник, переданный ему точечным радиусом.

Перечисление 3-1  метод области интереса для пикселизировать модуля изображения

 
- (CGRect)regionOf: (int)sampler  destRect: (CGRect)rect  userInfo: (NSNumber *)radius
{
    return CGRectInset(rect, -[radius floatValue], -[radius floatValue]);
}

Теперь, когда Вы видели требуемый метод области интереса, Вы готовы использовать XCode для создания пикселизировать модуля изображения.

  1. Запустите XCode и выберите File> New Project.

  2. В Окне помощника прокрутите к к Стандарту Плагины Apple, выберите Image Unit Plug-in for Objective C и нажмите Далее.

  3. Войти Pixellate как название проекта и нажимают Finish.

  4. Откройтесь PixellateFilterKernel.cikernel файл и замена код с кодом от Перечисления 2-4.

  5. Откройтесь Pixellate.h файл и изменяет интерфейс так, чтобы фильтр имел две переменные экземпляра: inputImage и inputScale. Тогда сохраните и закройте файл.

  6. Откройтесь Pixellate.m файл и изменяет regionOf:destRect:userInfo: так, чтобы это совпало с методом в Перечислении 3-1.

  7. Измените customAttributes методы так, чтобы был, имеют только один атрибут: inputScale, и набор надлежащие значения для минимума, минимума ползунка, максимума ползунка, значения по умолчанию, идентификационных данных и атрибутов типа. Метод должен выглядеть подобным следующему:

    - (NSDictionary *)customAttributes
    {
        return [NSDictionary dictionaryWithObjectsAndKeys:
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  1.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble:  200.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble:  4.00], kCIAttributeDefault,
                [NSNumber numberWithDouble:  1.00], kCIAttributeIdentity,
                kCIAttributeTypeScalar,           kCIAttributeType,
                nil],                               @"inputScale",
     
            nil];
    }
  8. Измените outputImage метод так, чтобы это посмотрело следующим образом:

    - (CIImage *)outputImage
    {
        float radius;
        CISampler *src;
        // Set up the sampler to use the input image
        src = [CISampler samplerWithImage:inputImage];
        radius = [inputScale floatValue] * 0.5;
        // Set the region-of-interest method for the kernel routine
        [_PixellateFilterKernel setROISelector:@selector(regionOf:destRect:userInfo:)];
        // Apply the filter to the kernel, passing the sampler and scale
        return [self apply:_PixellateFilterKernel, src,
            inputScale,
        // This option specifies the domain of definition of the destination image
            kCIApplyOptionDefinition, [[src definition] insetByX:-radius Y:-radius],
        // This option sets up the ROI method to gets radius value
            kCIApplyOptionUserInfo, [NSNumber numberWithFloat:radius], nil];
    }

    Обратите внимание на то, что необходимо установить домен определения так, чтобы конечное изображение было вставлено радиусом точки. Иначе, Вы получите непрозрачный край вокруг конечного изображения. (См. Методы Области интереса и Базовое Руководство по программированию Изображения.)

  9. Сохраните и закройтесь Pixellate.m файл.

  10. Откройтесь Description.plist файл.

  11. Изменение CICategoryDistortionEffect к CICategoryStylizeEffect.

  12. Сохраните и закройтесь Description.plist файл.

  13. Разработайте проект.

    Это должно успешно выполниться, если Вы не представили некоторые типографские ошибки.

  14. Выйдите из XCode.

  15. Найдите Pixellate.plugin файл в Вашем проекте. Если Вы хотите, переместите его в удобное расположение в целях проверки и тестирования.

  16. Удостоверьтесь, что модуль изображения допустим. (См. Проверку Модуля Изображения.)

  17. Установите проверенный модуль изображения в /Library/Graphics/Image Units/.

    Можно дополнительно установить модуль изображения в "User"/Library/Graphics/Image Units/ несмотря на то, что Вы, возможно, должны создать /Graphics/Image Units/ папка, потому что это не создается по умолчанию..

  18. Протестируйте модуль изображения. (См. Тестирование Модуля Изображения.)

Создание детективного модуля изображения линзы

Детективный модуль изображения линзы является самым сложным модулем изображения в этой главе, потому что это объединяет два kernel подпрограммы и используют их вместе с Базовым Изображением встроенный фильтр. Этот модуль изображения требует четыре CISampler объекты и два метода области интереса (один на kernel подпрограмма).

Этот раздел предполагает чтение Подпрограмм Ядра Записи для Детективной Линзы. Удостоверьтесь, что Вы понимаете детективное определение линзы (см. Детективную Анатомию Линзы), и kernel подпрограммам было нужно для этого модуля изображения (см. Перечисление 2-7 и Перечисление 2-8).

Детективный фильтр линзы является многопроходным фильтром. Вы должны будете сначала применить линзу kernel подпрограмма к входному изображению. Тогда необходимо применить держателя линзы kernel подпрограмма. Наконец, необходимо будет составить выходные изображения от каждого kernel подпрограмма. Для этого Вы будете использовать Базовый фильтр Изображения CISourceOverCompositing.

Для создания детективного модуля изображения линзы выполните эти шаги:

  1. Запустите XCode и выберите File> New Project.

  2. В Окне помощника прокрутите к к Стандарту Плагины Apple, выберите Image Unit Plug-in for Objective C и нажмите Далее.

  3. Войти DetectiveLens как название проекта и нажимают Finish.

  4. Откройтесь DetectiveLensFilterKernel.cikernel файл и замена код с кодом от Перечисления 2-7 и Перечисления 2-8.

  5. Откройтесь DetectiveLens.h файл и изменяет входные параметры, таким образом, они соответствуют то, что показано в Перечислении 3-2. Тогда сохраните и закройте файл.



    Перечисление 3-2  входные параметры к детективному фильтру линзы

    @interface DetectiveLensFilter : CIFilter
    {
        CIImage      *inputImage;
        CIVector     *inputCenter; // center of the lens
        NSNumber     *inputLensDiameter; // diameter of the lens
        NSNumber     *inputRingWidth; // width of the lens holder
        NSNumber     *inputMagnification; // lens magnification
        NSNumber     *inputRingFilletRadius; // lens holder fillet radius
        NSNumber     *inputRoundness;  // roundness of the lens, range is 0...1
        NSNumber     *inputShineOpacity; // opacity of the lens, range is 0...1
    }
  6. Откройтесь DetectiveLens.m файл. Существует много модификаций, которые необходимо будет сделать к этому файлу.

  7. Добавьте следующие статические объявления сразу после @implementation оператор:

    static CIKernel *_lensKernel = nil; // for the lens kernel routine
    static CIKernel *_ringKernel = nil; // for the lens holder kernel routine
    static CIImage *_ringMaterialImage = nil; // for the material map
    static CIImage *_lensShineImage = nil; // for the highlight image

    Вам нужен тот CIKernel объект для каждого kernel подпрограмма, которую использует модуль изображения.

    Вам нужен тот CIImage объект для каждого изображения. Вспомните что линза kernel подпрограмма использует изображение выделения и держателя линзы kernel подпрограмма использует материальную карту. Входное изображение является частью объявления интерфейса для фильтра, потому что это предоставлено клиентом фильтра. Напротив, выделение и материальные изображения должны быть включены как часть модуля изображения.

  8. Измените init метод так, чтобы это выбрало обоих kernel подпрограммы, с помощью помех CIKernel объекты, которые Вы просто объявили. Замените этот оператор:

    _DectiveLensFilterKernel = [[kernels objectAtIndex:0] retain];

    с этими двумя операторами:

    // Fetch the lens kernel routine
    _lensKernel = [[kernels objectAtIndex:0] retain];
    // Fetch the lens holder kernel routine
    _ringKernel = [[kernels objectAtIndex:1] retain];
  9. Измените init метод так, чтобы это открыло файлы, содержащие изображение выделения, необходимое линзе kernel подпрограмма и материальная карта необходимы для держателя линзы kernel подпрограмма. Добавьте следующие строки кода к init метод.

    Необходимо изменить имена файлов и расширения, если они не соответствуют то, что показало (myMaterial.tiff и myHighlight.tiff).

    NSString    *path = nil;
    NSURL    *url = nil;
    path = [bundle pathForResource:@"myMaterial" ofType:@"tiff"];
    url = [NSURL fileURLWithPath:path];
    _ringMaterialImage = [[CIImage imageWithContentsOfURL:url] retain];
     
    path = [bundle pathForResource:@"myHighlight" ofType:@"tiff"];
    url = [NSURL fileURLWithPath:path];
     _lensShineImage = [[CIImage imageWithContentsOfURL:url] retain];

    Для каждого файла код получает строку, определяющую путь к файлу. Тогда это создает NSURL объект от того пути. Наконец, код предоставляет NSURL возразите против imageWithContentsOfURL: метод CIImage класс, и сохраняет изображение так, чтобы это могло использоваться позже.

  10. Измените customAttributes метод так, чтобы NSDictionary возразите, что это возвращается, содержит релевантную информацию для каждого из входных параметров. Затем когда узел фильтра вызывает метод атрибутов для фильтра, Базовое Изображение вызывает Ваш customAttributes метод и возвраты значение по умолчанию, минимум, максимум, и т.д., оценивают за каждый из входных параметров. После изменения customAttributes метод, это должно появиться следующим образом:

    - (NSDictionary *)customAttributes
    {
        return [NSDictionary dictionaryWithObjectsAndKeys:
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [CIVector vectorWithX:200.0 Y:200.0],  kCIAttributeDefault,
                kCIAttributeTypePosition,              kCIAttributeType,
                nil],                                  @"inputCenter",
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  1.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble:500.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble:250.00], kCIAttributeDefault,
                [NSNumber numberWithDouble:250.00], kCIAttributeIdentity,
                kCIAttributeTypeDistance,           kCIAttributeType,
                nil],                               @"inputLensDiameter",
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  1.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble:500.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble: 22.00], kCIAttributeDefault,
                [NSNumber numberWithDouble:  1.00], kCIAttributeIdentity,
                kCIAttributeTypeDistance,           kCIAttributeType,
                nil],                               @"inputRingWidth",
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  1.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble: 30.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble:  9.20], kCIAttributeDefault,
                [NSNumber numberWithDouble:  7.00], kCIAttributeIdentity,
                kCIAttributeTypeDistance,           kCIAttributeType,
                nil],                               @"inputRingFilletRadius",
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  1.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble: 10.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble:  3.00], kCIAttributeDefault,
                [NSNumber numberWithDouble:  1.00], kCIAttributeIdentity,
                kCIAttributeTypeScalar,             kCIAttributeType,
                nil],                               @"inputMagnification",
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  0.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  0.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble:  0.86], kCIAttributeDefault,
                [NSNumber numberWithDouble:  1.00], kCIAttributeIdentity,
                kCIAttributeTypeScalar,             kCIAttributeType,
                nil],                               @"inputRoundness",
     
            [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithDouble:  0.00], kCIAttributeMin,
                [NSNumber numberWithDouble:  0.00], kCIAttributeSliderMin,
                [NSNumber numberWithDouble:  1.00], kCIAttributeSliderMax,
                [NSNumber numberWithDouble:  0.50], kCIAttributeDefault,
                [NSNumber numberWithDouble:  1.00], kCIAttributeIdentity,
                kCIAttributeTypeScalar,             kCIAttributeType,
                nil],                               @"inputShineOpacity",
     
            nil];
    }
  11. Запишите метод области интереса для держателя линзы kernel подпрограмма.

    Вспомните, что метод области интереса возвращает прямоугольник, указывающий область сэмплера для использования для выборки данных изображения для kernel подпрограмма. Представляющая интерес область для держателя линзы kernel подпрограмма является просто прямоугольником, указывающим размер материальной карты.

    Метод области интереса должен иметь подпись, совместимую со следующим:

    - (CGRect) regionOf:(int)samplerIndex destRect:(CGRect)r userInfo:obj;

    Этот метод является обратным вызовом, это вызывается Базовым Изображением каждый раз, когда Ваш kernel подпрограмме нужна выборка для обработки. Держатель линзы kernel подпрограмма использует только один сэмплер, индекс сэмплера которого 0. (Индексы сэмплера для метода ROI запускаются в 0 и последовательны.), Если индекс сэмплера 0, тогда метод ROI должен возвратить размер материальной карты. Иначе, это должно возвратить целевой прямоугольник, который Базовое Изображение передало подпрограмме.

    userInfo параметр для любого метода области интереса - то, что Вы используете для передачи любых необходимых данных методу. Этот определенный метод области интереса должен иметь сэмплер для материальной карты, переданной ему так, чтобы метод ROI мог определить размер карты. extent метод CISampler класс делает просто это.

    - (CGRect)ringROI:(int)sampler forRect:(CGRect)R userInfo:(CISampler *)material
    {
        if (sampler == 0)
            return [material extent];
        return R;
    }
  12. Запишите метод области интереса для линзы kernel подпрограмма. Этот метод немного более сложен, чем тот для держателя линзы kernel подпрограмма.

    Этот метод должен возвратить представляющую интерес область для три sampler объекты:

    • Сэмплер 0 выборки выборок от субдискретизируемого изображения (т.е. что появляется, как не увеличено — пиксели вне линзы). Область интереса является просто прямоугольником, переданным методу ROI.

    • Сэмплер 1 выборки выборок от изображения высокого разрешения. Область интереса зависит от увеличения и ширины линзы. Число пикселей, необходимых из исходного изображения, определяется шириной линзы, разделенной на увеличение. Источник прямоугольника, определяющего эту область, является центром линзы минус число необходимых пикселей.

    • Сэмплер 2 выборки выборок от изображения выделения. Область интереса является прямоугольником (CGRect тип данных), который описывает размер изображения выделения. Можно получить размер с помощью extent метод CISampler объект.

    userInfo необходимый для этого определенного метода области интереса массив, содержащий три из входных параметров фильтра (центр линзы, ширина линзы, фактора увеличения) и CISampler объект для изображения выделения.

    Линза метод ROI должна выглядеть подобной следующему:

    - (CGRect)lensROI:(int)sampler forRect:(CGRect)R userInfo:(NSArray *)array
    {
        CIVector *oCenter;
        NSNumber *oWidth, *oMagnification;
        CISampler *shine;
     
        // Fetch the necessary input parameters from the userInfo parameter
        oCenter = [array objectAtIndex:0];
        oWidth = [array objectAtIndex:1];
        oMagnification = [array objectAtIndex:2];
        shine = [array objectAtIndex:3];  // shine is a CISampler object
        if (sampler == 2)
            return [shine extent];
     
        // Determine the area of the original image used with the lens where it is
        // currently we only need R, because the lens is a magnifier
        if (sampler == 1)
        {
            float cx, cy, width, mag;
     
            cx = [oCenter X];
            cy = [oCenter Y];
            width = [oWidth floatValue];
            mag = [oMagnification floatValue];
            width /= mag; // calculates the actual pixels needed from the source
            R = CGRectMake(cx - width, cy - width, width*2.0, width*2.0);
        }
        return R; // If the sampler is 0, ROI calculation is not needed.
    }

  13. Запишите outputImage метод.

    Для каждого kernel подпрограмма, этот метод:

    • Создает CISampler объекты, выполняя любой необходимый набор работают на них.

    • Вычисляет любые значения, необходимые методу ROI или kernel подпрограмма. Это включает вычисление прямоугольника, определяющего форму конечного изображения (иначе известный как домен определения).

    • Устанавливает userInfo данные, необходимые методу ROI так, чтобы был, могут быть переданы как опция (kCIApplyOptionUserInfo) к apply: метод CIFilter объект.

    • Устанавливает метод ROI для использования для kernel подпрограмма.

    • Вызовы apply: метод CIFilter объект.

    Тогда метод составляет получающиеся изображения в заключительное изображение при помощи Базового Изображения CISourceOverCompositing фильтр.

    Метод довольно длинен и выполняет много задач, таким образом, Вы захотите считать подробное объяснение каждой начитанной строки (a, b, c, и т.д.), который появляется после кода.

    - (CIImage *)outputImage
    {
        float radius, cx, cy, ringwidth, mag;
        CGRect R, extent;
        CISampler *src, *shine, *material;
        CIImage *lensedImage, *ringImage;
        CIFilter *compositedImage;
        NSArray *array;
        CISampler *magsrc;
        CGAffineTransform CT;
        CIVector *shineSize, *materialSize;
     
        // ********* Lens *********
        src = [CISampler samplerWithImage:inputImage]; // 1
        shine = [CISampler samplerWithImage:_lensShineImage]; // 2
        // Set up work needed for the magnified image sampler
        cx = [inputCenter X];
        cy = [inputCenter Y];
        mag = [inputMagnification floatValue];
        CT = CGAffineTransformTranslate(CGAffineTransformScale(
            CGAffineTransformMakeTranslation(cx, cy), mag, mag), -cx, -cy);
        magsrc = [CISampler samplerWithImage:[inputImage imageByApplyingTransform:CT]]; // 3
     
        radius = [inputLensDiameter floatValue] * 0.5; // 4
        R.origin.x = cx - radius; // 5
        R.origin.y = cy - radius;
        R.size.width = 2.0 * radius;
        R.size.height = 2.0 * radius;
     
        extent = [shine extent]; // 6
        shineSize = [CIVector vectorWithX:extent.size.width Y:extent.size.height]; // 7
     
        array = [NSArray arrayWithObjects:inputCenter, inputLensDiameter,
                    inputMagnification, shine, nil]; // 8
        [_lensKernel setROISelector:@selector(lensROI:forRect:userInfo:)]; // 9
     
        lensedImage = [self apply:_lensKernel, src, magsrc, shine, inputCenter,
                [NSNumber numberWithFloat:radius + 2.0],
                  inputMagnification, inputRoundness,
                  inputShineOpacity, shineSize,
                 kCIApplyOptionDefinition, [[src definition] unionWithRect:R],
                 kCIApplyOptionUserInfo, array, nil];  // 10
     
        // ********* Lens Holder   *********
        material = [CISampler samplerWithImage:_ringMaterialImage]; // 11
        ringwidth = [inputRingWidth floatValue]; // 12
     
        R.origin.x = cx - radius - ringwidth; // 13
        R.origin.y = cy - radius - ringwidth;
        R.size.width = 2.0 * (radius + ringwidth);
        R.size.height = 2.0 * (radius + ringwidth);
        extent = [material extent]; // 14
     
        materialSize = [CIVector vectorWithX:extent.size.width Y:extent.size.height]; // 15
     
        [_ringKernel setROISelector:@selector(ringROI:forRect:userInfo:)]; // 16
     
        ringImage = [self apply:_ringKernel, material, inputCenter,
                    [NSNumber numberWithFloat:radius],
                    [NSNumber numberWithFloat:radius+ringwidth],
                    inputRingFilletRadius,
                      materialSize,
                      kCIApplyOptionDefinition,
                      [CIFilterShape shapeWithRect:R],
                      kCIApplyOptionUserInfo, material, nil]; // 17
     
        // ********* Lens and Lens Holder Composited *********
        compositedImage = [CIFilter filterWithName:@"CISourceOverCompositing"
                keysAndValues:@"inputImage", ringImage,
                @"inputBackgroundImage", lensedImage, nil]; // 18
     
        return [compositedImage valueForKey:@"outputImage"]; // 19
     
    }

    Вот то, что делает код:

    • 1. Создает объект CISampler для исходного изображения.

    • 2. Создает объект CISampler для изображения выделения.

    • 3. Создает объект CISampler для увеличенного источника, с помощью преобразования, вычисленного в предыдущих строках кода.

    • 4. Извлекает диаметр линзы как a float значение, затем вычисляет радиус.

    • 5. Вычисляет, вместе со следующими тремя строками кода, прямоугольник, который будет использоваться позже для вычислений размера конечного изображения — домен определения.

    • 6. Получает размер изображения выделения.

    • 7. Создает a CIVector объект, содержащий размер изображения выделения.

    • 8. Устанавливает массив, это передается как userInput параметр к методу области интереса. Вспомните, что метод ROI берет три из входных параметров фильтра (inputCenter, inputLensDiameter, и inputMagnification) а также CISampler объект для изображения выделения.

    • 9. Устанавливает метод области интереса для линзы CIKernel объект. Это - метод, который Базовое Изображение вызывает каждый раз, когда Ваша линза kernel подпрограмма требует выборки.

    • 10. Применяет линзу kernel подпрограмма к входному изображению, предоставляя необходимые входные переменные, домен определения и массив это необходимо методу ROI. Обратите внимание на то, что домен определения указан как a CIFilterShape объект, который является объединением ранее расчетного прямоугольника (см. e), и домен определения CISampler объект для исходного изображения.

    • 11. Создает a CISampler объект для материальной карты необходим держателю линзы kernel подпрограмма.

    • 12. Извлекает ширину держателя линзы как a float значение.

    • 13. Вычисляет, вместе со следующими тремя строками кода, прямоугольник, использующийся для домена определения. Заметьте, что этот прямоугольник включает держателя линзы. Базовое Изображение будет использовать эту информацию для ограничения вычислений. Держатель линзы kernel подпрограмму не вызовут ни для какого пикселя, выходящего за пределы этого прямоугольника.

    • 14. Получает размер материальной карты.

    • 15. Создает a CIVector объект, представляющий ширину и высоту материальной карты.

    • 16. Устанавливает метод области интереса для держателя линзы CIKernel объект. Это - метод, который Базовое Изображение вызывает каждый раз, когда Ваш держатель линзы kernel подпрограмма требует выборки.

    • 17. Применяет держателя линзы kernel подпрограмма к материальной карте, предоставляя необходимые входные переменные, прямоугольник определение домена определения, и CISampler объект для материальной карты (передал как userInfo параметр).

    • 18. Создает объект фильтра для Базового Изображения CISourceOverCompositing фильтр, предоставляя изображение производится len держателем kernel подпрограмма как изображение переднего раздела и изображение производится линзой kernel подпрограмма как фоновое изображение.

    • 19. Возвращает значение, связанное с outputImage ключ для фильтра.

  14. Сохраните и закройтесь DetectiveLens.m файл.

  15. Выберите Project> Add to Project для добавления файла образа выделения (myHighlight.tiff) к проекту.

    Имя и тип файла должны соответствовать то, что Вы обеспечиваете в init метод.

  16. Выберите Project> Add to Project для добавления материального файла карты (myMaterialMap.tiff) к проекту.

    Имя и тип файла должны соответствовать то, что Вы обеспечиваете в init метод.

  17. Откройтесь Description.plist файл.

  18. Измените имя дисплея (ищите ключ CIAttributeFilterDisplayName) от DetectiveLens к Detective Lens.

  19. Сохраните и закройтесь Description.plist файл.

  20. Разработайте проект.

    Это должно успешно выполниться, если Вы не представили некоторые типографские ошибки.

  21. Выйдите из XCode.

  22. Найдите DetectiveLens.plugin файл в Вашем проекте. Если Вы хотите, переместите его в удобное расположение для проверки и тестирования.

  23. Удостоверьтесь, что модуль изображения допустим и работает должным образом путем следования инструкциям в Проверке Модуля Изображения и Тестировании Модуля Изображения.

Следующие шаги

При успешном создании всех модулей изображения в этой главе Вы могли бы попытаться изменить детективный модуль изображения линзы путем добавления дескриптора, это типично для детективной линзы!