Запись части Objective C
Ядро, несмотря на то, что это - основа фильтра обработки изображений, становится модулем изображения только после того, как это должным образом упаковывается как плагин. Ваши самые важные задачи в упаковочном процессе состоят в том, чтобы скопировать Ваш kernel
подпрограмма (или подпрограммы) в ядро скелетный файл, предоставленный XCode и изменить код в в реализации и интерфейсных файлах для фильтра. Существует несколько других задач по обслуживанию, которые необходимо будет выполнить, чтобы правильно категоризировать фильтр и идентифицировать модуль изображения как продукт. Необходимо будет также описать его входные параметры.
Эта глава обеспечивает обзор для шаблона модуля изображения в XCode и описывает содержание файлов фильтра. Затем это показывает, как создать эти модули изображения:
Цветная инверсия отображает модуль, использующий
kernel
подпрограмма обсудила в цвете Инверсию. Это использует тотsampler
возразите и не требуйте метода области интереса.Пикселизировать модуль изображения, использующий
kernel
подпрограмма обсуждена в Pixellate. Это использует тотsampler
возразите и требует одного метода области интереса.Детективная линза отображает модуль, использующий два
kernel
подпрограммы обсуждены в записи Подпрограмм Ядра для Детективной Линзы. Это использует, требует несколькихsampler
объекты и два область интереса методы.
Прежде чем Вы будете следовать инструкциям в этой главе для записи части Objective C модуля изображения, необходимо понять как kernel
подпрограммы обсуждены в записи работы Ядер.
Шаблон модуля изображения в XCode
XCode обеспечивает шаблон, упрощающий упаковочный процесс. Чтобы помочь Вам упаковать модуль изображения как плагин, XCode обеспечивает скелетные файлы и методы, которые необходимы, и называет файлы соответственно. Рисунок 3-1 показывает файлы, автоматически создаваемые XCode для названного проекта модуля изображения DetectiveLens
.
XCode автоматически называет файлы с помощью названия проекта, которое Вы предоставляете. Это файлы по умолчанию, предоставленные XCode:
<ProjectName>Filter.m
файл реализации для фильтра. Необходимо будет изменить этот файл.<ProjectName>Filter.h
интерфейсный файл для фильтра. Необходимо будет изменить этот файл.<ProjectName>FilterKernel.cikernel
файл, содержащийkernel
подпрограмма (или подпрограммы) и любые подпрограммы необходимы ядру. Код по умолчанию является afunHouse
подпрограмма ядра и asmoothstep
подпрограмма это используетсяfunHouse
. (Эта подпрограмма не является тем же как тем, предоставленным OpenGl, Заштриховывающим Язык.) Все, что необходимо сделать, полностью заменить этот кодkernel
подпрограмма (или подпрограммы), что Вы записали (а также протестировали и отладили), и любые требуемые подпрограммы.<ProjectName>PlugInLoader.m
файл, реализующий сменный протокол, должен был загрузить модуль изображения. Вы не должны делать модификации к этому файлу, если Ваш продукт не требует пользовательских задач на загрузке. Эта глава не предоставляет информации о настройке процесса загрузки. Это предполагает, что Вы используете файл как есть.<ProjectName>PlugInLoader.h
интерфейсный файл для протокола загрузки плагина.<ProjectName>.plugin
плагин, который Вы распределите. При создании проекта это имя файла, кажется, в красном тексте указывает, что еще не существует файл. После того, как Вы разработаете проект, изменения имени файла в черном тексте, чтобы указать, что существует плагин.Description.plist
определяет несколько свойств фильтра: отфильтруйте имя, категории фильтра, локализованное имя дисплея, класс фильтра и информацию о входных параметрах к фильтру. Исполнимые модули изображения (которые являются единственными модулями изображения, которые Вы будете видеть в этом учебном руководстве), возможно, ввели параметры любого класса, но Базовое Изображение не генерирует автоматический пользовательский интерфейс для пользовательских классов (см.CIFilter Image Kit Additions
). Входные параметры для неисполнимых модулей изображения должны быть одним из этих классов:CIColor
,CIVector
,CIImage
, илиNSNumber
. (Для получения дополнительной информации об исполнимых и неисполнимых фильтрах см. Базовое Руководство по программированию Изображения.)Шаблонный файл по умолчанию показан на рисунке 3-2. XCode заполняет имя фильтра для Вас на основе названия проекта, которое Вы обеспечиваете. Необходимо внести изменения в категории фильтра и локализованное имя дисплея. Категории фильтра должны включать все категории, определенные Базовым Изображением API, применяющийся к Вашему фильтру. Для списка возможных категорий см. Ссылку класса CIFilter.
Info.plist
содержит свойства плагина, такие как область разработки, идентификатор пакета, основной класс и название продукта. Вы захотите изменить идентификатор пакета и удостовериться, что Вы определяете переменную названия продукта в XCode.
Код по умолчанию для фильтра, подражающего эффекту забавного зеркала дома. Необходимо распознать подпрограмму ядра как тот же самый обсужденный в Перечислении 2-6. Проект создаст как допустимый модуль изображения без потребности в Вас изменить одну строку кода.
Интерфейс фильтра и файлы реализации, предоставленные XCode, являются теми, что необходимо настроить для Вашего kernel
подпрограмма (или подпрограммы). Интерфейсный файл объявляет подкласс CIFilter
. XCode автоматически называет подкласс <ProjectName>Filter
. Например, если Вы предоставляете InvertColor как название проекта, интерфейсное использование файла InvertColorFilter
как имя подкласса. Интерфейсный файл по умолчанию объявляет четыре переменные экземпляра для фильтра: inputImage
, inputVector
, inputWidth
, и inputAmount
, который, с точки зрения клиента фильтра, входные параметры к фильтру. Вы, возможно, должны удалить один или больше этих переменных экземпляра и добавить любого, которые необходимы Вашему модулю изображения.
Файл реализации содержит четыре метода, которые необходимо будет изменить в целях:
init
получает файл ядра от пакета и загружаетсяkernel
подпрограммы. Если Вы не требуете настройки во время инициализации, Вы, возможно, не должны изменять этот метод.regionOf:destRect:userInfo
функция обратного вызова, определяющая область интереса (ROI). Если Вы пишете фильтр, не требующий ROI, можно удалить этот метод. Если Вы не уверены в том, каков ROI, посмотрите Базовые Методы Руководства по программированию и Области интереса Изображения. В целом фильтры, отображающие один исходный пиксель на один целевой пиксель, не требуют ROI. Примерно все другие типы фильтров потребуют, чтобы Вы обеспечили метод ROI, кроме определенных фильтров генератора.customAttributes
метод, определяющий атрибуты каждого входного параметра. Это требуется так, чтобы узел фильтра мог запросить Ваш фильтр для входных параметров, их типов данных, и их значения по умолчанию, минимума и максимальных значений. Можно также предоставить такую полезную информацию как ползунок минимальные и максимальные значения. Когда узел фильтра вызываетattributes
метод, Базовое Изображение фактически вызывает ВашcustomAttributes
метод. Если Ваш фильтр не требует никаких входных параметров кроме входного изображения, можно удалить этот метод.outputImage
создает один или большеCISampler
объекты, выполняет любые необходимые вычисления, вызовыapply:
методCIFilter
класс и возвраты aCIImage
объект. Точный характер этого метода зависит от сложности фильтра, как Вы будете видеть путем чтения остальной части этой главы.
Следующие разделы показывают, как изменить файлы фильтра для трех типов модулей изображения:
Создание Цветного Модуля Изображения Инверсии использует тот
kernel
подпрограмме, но не нужен метод ROI.Создание Модуля Изображения Pixellate использует тот
kernel
подпрограмма и метод ROI.Создание Детективного Модуля Изображения Линзы является многопроходным фильтром, использующим два
kernel
подпрограммы и метод ROI для каждогоkernel
подпрограмма.
Создание цветного модуля изображения инверсии
Цветной фильтр инверсии представляет один из самых простых модулей изображения, которые можно записать. Это использует kernel
подпрограмма обсудила в цвете Инверсию. Если Вы смотрите на kernel
подпрограмма, показанная в Перечислении 2-1, Вы будете видеть, что подпрограмма не использует входных параметров кроме входного изображения. Таким образом, нет никакой потребности предоставить a customAttributes
метод. kernel
подпрограмма отображает один исходный пиксель на целевой пиксель, который это в тех же координатах как исходный пиксель. В результате нет никакой потребности предоставить метод, вычисляющий ROI. Необходимо будет сделать модификации к файлу интерфейса фильтра и к outputImage
метод в файле реализации фильтра. Значение по умолчанию init
метод будет работать, как, при условии, что Вы не переименовываете ни одного из файлов, которые XCode автоматически называет для Вас.
Упаковывать цветную инверсию kernel
подпрограмма как модуль изображения, выполните эти шаги:
Запустите XCode и выберите File> New Project.
В Окне помощника прокрутите к к Стандарту Плагины Apple, выберите
Image Unit Plug-in for Objective C
и нажмите Далее.Войти
InvertColor
как название проекта и нажимают Finish.Откройтесь
InvertColorFilterKernel.cikernel
файл и замена код с кодом от Перечисления 2-1.Откройтесь
InvertColor.h
файл и удаляет все переменные экземпляра за исключениемinputImage
, поскольку этот фильтр не имеет никаких входных параметров кроме входного изображения. Тогда сохраните и закройте файл.Откройтесь
InvertColor.m
файл и удаляетregionOf:destRect:userInfo:
иcustomAttributes
методы.Измените
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];
}
Сохраните и закройтесь
InvertColor.m
файл.Откройтесь
Description.plist
файл.Изменение
CICategoryDistortionEffect
кCICategoryColorEffect
.Сохраните и закройтесь
Description.plist
файл.Откройтесь
Description.strings
файл.Введите локализованное имя дисплея для фильтра путем добавления следующего:
"InvertColorFilter" = "Invert Color Filter";
Вы захотите обеспечить локализованные имена дисплея для всех входных параметров и для всех языков, представляющих Ваших пользователей модуля изображения.
Сохраните и закройтесь
Description.strings
файл.Разработайте проект.
Это должно успешно выполниться, если Вы не представили некоторые типографские ошибки.
Выйдите из XCode.
Найдите
InvertColor.plugin
файл в Вашем проекте. Если Вы хотите, переместите его в удобное расположение в целях проверки и тестирования.Удостоверьтесь, что модуль изображения допустим. (См. Проверку Модуля Изображения.)
Установите проверенный модуль изображения в
/Library/Graphics/Image Units/
.Протестируйте модуль изображения. (См. Тестирование Модуля Изображения.)
Это - все, которое существует к созданию модуля изображения для простого фильтра! Считайте следующие разделы для создания модулей изображения для более сложных фильтров.
Создание модуля изображения 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 для создания пикселизировать модуля изображения.
Запустите XCode и выберите File> New Project.
В Окне помощника прокрутите к к Стандарту Плагины Apple, выберите
Image Unit Plug-in for Objective C
и нажмите Далее.Войти
Pixellate
как название проекта и нажимают Finish.Откройтесь
PixellateFilterKernel.cikernel
файл и замена код с кодом от Перечисления 2-4.Откройтесь
Pixellate.h
файл и изменяет интерфейс так, чтобы фильтр имел две переменные экземпляра:inputImage
иinputScale
. Тогда сохраните и закройте файл.Откройтесь
Pixellate.m
файл и изменяетregionOf:destRect:userInfo:
так, чтобы это совпало с методом в Перечислении 3-1.Измените
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];
}
Измените
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];
}
Обратите внимание на то, что необходимо установить домен определения так, чтобы конечное изображение было вставлено радиусом точки. Иначе, Вы получите непрозрачный край вокруг конечного изображения. (См. Методы Области интереса и Базовое Руководство по программированию Изображения.)
Сохраните и закройтесь
Pixellate.m
файл.Откройтесь
Description.plist
файл.Изменение
CICategoryDistortionEffect
кCICategoryStylizeEffect
.Сохраните и закройтесь
Description.plist
файл.Разработайте проект.
Это должно успешно выполниться, если Вы не представили некоторые типографские ошибки.
Выйдите из XCode.
Найдите
Pixellate.plugin
файл в Вашем проекте. Если Вы хотите, переместите его в удобное расположение в целях проверки и тестирования.Удостоверьтесь, что модуль изображения допустим. (См. Проверку Модуля Изображения.)
Установите проверенный модуль изображения в
/Library/Graphics/Image Units/
.Можно дополнительно установить модуль изображения в
"User"/Library/Graphics/Image Units/
несмотря на то, что Вы, возможно, должны создать/Graphics/Image Units/
папка, потому что это не создается по умолчанию..Протестируйте модуль изображения. (См. Тестирование Модуля Изображения.)
Создание детективного модуля изображения линзы
Детективный модуль изображения линзы является самым сложным модулем изображения в этой главе, потому что это объединяет два kernel
подпрограммы и используют их вместе с Базовым Изображением встроенный фильтр. Этот модуль изображения требует четыре CISampler
объекты и два метода области интереса (один на kernel
подпрограмма).
Этот раздел предполагает чтение Подпрограмм Ядра Записи для Детективной Линзы. Удостоверьтесь, что Вы понимаете детективное определение линзы (см. Детективную Анатомию Линзы), и kernel
подпрограммам было нужно для этого модуля изображения (см. Перечисление 2-7 и Перечисление 2-8).
Детективный фильтр линзы является многопроходным фильтром. Вы должны будете сначала применить линзу kernel
подпрограмма к входному изображению. Тогда необходимо применить держателя линзы kernel
подпрограмма. Наконец, необходимо будет составить выходные изображения от каждого kernel
подпрограмма. Для этого Вы будете использовать Базовый фильтр Изображения CISourceOverCompositing
.
Для создания детективного модуля изображения линзы выполните эти шаги:
Запустите XCode и выберите File> New Project.
В Окне помощника прокрутите к к Стандарту Плагины Apple, выберите
Image Unit Plug-in for Objective C
и нажмите Далее.Войти
DetectiveLens
как название проекта и нажимают Finish.Откройтесь
DetectiveLensFilterKernel.cikernel
файл и замена код с кодом от Перечисления 2-7 и Перечисления 2-8.Откройтесь
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
}
Откройтесь
DetectiveLens.m
файл. Существует много модификаций, которые необходимо будет сделать к этому файлу.Добавьте следующие статические объявления сразу после
@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
подпрограмма использует материальную карту. Входное изображение является частью объявления интерфейса для фильтра, потому что это предоставлено клиентом фильтра. Напротив, выделение и материальные изображения должны быть включены как часть модуля изображения.Измените
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];
Измените
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
класс, и сохраняет изображение так, чтобы это могло использоваться позже.Измените
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];
}
Запишите метод области интереса для держателя линзы
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;
}
Запишите метод области интереса для линзы
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.
}
Запишите
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. Обратите внимание на то, что домен определения указан как aCIFilterShape
объект, который является объединением ранее расчетного прямоугольника (см. e), и домен определенияCISampler
объект для исходного изображения.11. Создает a
CISampler
объект для материальной карты необходим держателю линзыkernel
подпрограмма.12. Извлекает ширину держателя линзы как a
float
значение.13. Вычисляет, вместе со следующими тремя строками кода, прямоугольник, использующийся для домена определения. Заметьте, что этот прямоугольник включает держателя линзы. Базовое Изображение будет использовать эту информацию для ограничения вычислений. Держатель линзы
kernel
подпрограмму не вызовут ни для какого пикселя, выходящего за пределы этого прямоугольника.14. Получает размер материальной карты.
15. Создает a
CIVector
объект, представляющий ширину и высоту материальной карты.16. Устанавливает метод области интереса для держателя линзы
CIKernel
объект. Это - метод, который Базовое Изображение вызывает каждый раз, когда Ваш держатель линзыkerne
l подпрограмма требует выборки.17. Применяет держателя линзы
kernel
подпрограмма к материальной карте, предоставляя необходимые входные переменные, прямоугольник определение домена определения, иCISampler
объект для материальной карты (передал какuserInfo
параметр).18. Создает объект фильтра для Базового Изображения
CISourceOverCompositing
фильтр, предоставляя изображение производится len держателемkernel
подпрограмма как изображение переднего раздела и изображение производится линзойkernel
подпрограмма как фоновое изображение.19. Возвращает значение, связанное с
outputImage
ключ для фильтра.
Сохраните и закройтесь
DetectiveLens.m
файл.Выберите Project> Add to Project для добавления файла образа выделения (
myHighlight.tiff
) к проекту.Имя и тип файла должны соответствовать то, что Вы обеспечиваете в
init
метод.Выберите Project> Add to Project для добавления материального файла карты (
myMaterialMap.tiff
) к проекту.Имя и тип файла должны соответствовать то, что Вы обеспечиваете в
init
метод.Откройтесь
Description.plist
файл.Измените имя дисплея (ищите ключ
CIAttributeFilterDisplayName
) отDetectiveLens
кDetective Lens
.Сохраните и закройтесь
Description.plist
файл.Разработайте проект.
Это должно успешно выполниться, если Вы не представили некоторые типографские ошибки.
Выйдите из XCode.
Найдите
DetectiveLens.plugin
файл в Вашем проекте. Если Вы хотите, переместите его в удобное расположение для проверки и тестирования.Удостоверьтесь, что модуль изображения допустим и работает должным образом путем следования инструкциям в Проверке Модуля Изображения и Тестировании Модуля Изображения.
Следующие шаги
При успешном создании всех модулей изображения в этой главе Вы могли бы попытаться изменить детективный модуль изображения линзы путем добавления дескриптора, это типично для детективной линзы!