Запись ядер
Основа любого фильтра обработки изображений является файлом ядра. Файл ядра содержит один или больше kernel подпрограммы и любые требуемые подпрограммы. A kernel подпрограмму вызывают один раз для каждого пикселя для конечного изображения. Подпрограмма должна возвратить a vec4 тип данных. Несмотря на то, что этот вектор с четырьмя элементами обычно содержит пиксельные данные, вектор не требуется, чтобы представлять пиксель. Однако kernel подпрограммы в этой главе производят только пиксельные данные, потому что это - наиболее распространенные данные, возвращенные a kernel подпрограмма.
A kernel подпрограмма может:
Произведите данные. Например, подпрограмма может произвести случайные пиксельные значения, генерировать сплошной цвет или произвести градиент. Это может генерировать образцы, такие как дорожки, шахматная доска, starburst или цветные полосы.
Измените единственный пиксель из исходного изображения. A
kernelподпрограмма может скорректировать оттенок, воздействие, значения белой точки, цвета замены, и т.д.Демонстрационные несколько пикселей из исходного изображения для создания выходного пикселя. Стилизуйте фильтры, такие как граничное обнаружение, пикселизируйте, pointillize, мрак, и цветок использует этот метод.
Используйте информацию о расположении от одного или более пикселей в исходном изображении для создания выходного пикселя. Эффекты искажения, такие как удар, повышение и искажения дыры создаются этот путь.
Произведите выходной пиксель при помощи данных от маски, текстуры или другого источника для изменения одного или более пикселей в исходном изображении. Базовое Изображение стилизовало фильтры — поле высоты от маски, теневого материала, и разлагать с переходом маски — является примерами фильтров, использующих этот метод.
Объедините пиксели от двух изображений для создания выходного пикселя. Режим смешивания, составление композита и фильтры перехода прокладывают себе путь.
Эта глава показывает, как записать множество kernel подпрограммы. Сначала Вы будете видеть, каковы ограничения программирования или правила. Тогда Вы изучите, как записать простой фильтр, воздействующий на один входной пиксель для создания одного выходного пикселя. В то время как глава развивается, Вы изучите, как записать более сложный kernel подпрограммы, включая используемых для многопроходного фильтра.
Несмотря на то, что kernel подпрограмма - то, где обработка на пиксель происходит, это - только одна часть модуля изображения. Также необходимо записать код, предоставляющий входные данные kernel подпрограмма и выполняет много других задач, как описано в письменной форме Часть Objective C. Тогда необходимо будет связать весь код путем следования инструкциям в Подготовке Модуля Изображения для Распределения.
Прежде, чем продолжаться в этой главе, посмотрите Базовую Ссылку Языка Ядра Изображения для описания языка, который Вы используете для записи kernel подпрограммы. Удостоверьтесь, что Вы знакомы с ограничениями, обсужденными в Правилах Подпрограммы Ядра.
Запись простых подпрограмм ядра
A kernel подпрограмма, воздействующая на цвет исходного пикселя в расположении (x, y) для создания пикселя в том же расположении в конечном изображении, является довольно прямой для записи. В целом, a kernel подпрограмма, воздействующая на цвет, выполняет эти шаги:
Получает пиксель из исходного изображения, которое является в том же расположении как пиксель, который Вы хотите произвести в выходном изображении. Базовая функция Языка Ядра Изображения
sampleвозвращает пиксельное значение, произведенное указаннымsamplerв указанной точке. Для понимания указанной мысли используйте функциюsamplerCoord, то, которое возвращает позицию в пространстве сэмплера, связанном с пикселем текущей производительности после того, как любая матрица преобразования связалась с сэмплером, применяется. Это означает, преобразовывается ли изображение в некотором роде (например, вращение или масштабирующийся),samplerгарантирует, что трансформация отражается в выборке, которую она выбирает.Воздействует на значения цвета.
Возвращает измененный пиксель.
Уравнения для этого вида фильтра принимают следующую форму:

В зависимости от работы Вам, возможно, понадобятся к unpremultiply значения цвета до работы на них и предварительно умножения значений цвета прежде, чем возвратить измененный пиксель. Базовый Язык Ядра Изображения обеспечивает unpremultiply и premultiply функции с этой целью.
Цветная инверсия
Значения компонента цвета для пикселей в Базовом Изображении являются значениями с плавающей точкой тот диапазон от 0.0 (отсутствующий компонент цвета) к 1.0 (компонент цвета представляет в 100%). Инвертирование цвета выполняется путем переприсвоения каждого компонента цвета значения 1.0 – component_value, таким образом, что:
red_value = 1.0 - red_value |
blue_value = 1.0 - blue_value |
green_value = 1.0 - green_value |
Рисунок 2-1 показывает сетку пикселей. При инвертировании цвета каждого пикселя путем применения этих уравнений Вы получаете получающуюся сетку пикселей, показанных на рисунке 2-2.


Смотрите на kernel подпрограмма в Перечислении 2-1, чтобы видеть, как реализовать цветную инверсию. Подробное объяснение каждой пронумерованной строки кода появляется после перечисления. Вы будете видеть, как записать, что Objective C делит на части, это упаковывает эту подпрограмму как модуль изображения путем чтения Создания Цветного Модуля Изображения Инверсии.
Перечисление 2-1 A kernel подпрограмма, инвертирующая цвет
kernel vec4 _invertColor(sampler source_image) // 1 |
{ |
vec4 pixValue; // 2 |
pixValue = sample(source_image, samplerCoord(source_image)); // 3 |
unpremultiply(pixValue); // 4 |
pixValue.r = 1.0 - pixValue.r; // 5 |
pixValue.g = 1.0 - pixValue.g; |
pixValue.b = 1.0 - pixValue.b; |
return premultiply(pixValue); // 6 |
} |
Вот то, что делает код:
Берет a
samplerвозразите как входной параметр. Вспомните (см. Правила Подпрограммы Ядра), этоkernelподпрограммы не берут изображения в качестве входных параметров. Вместо этогоsamplerобъект отвечает за доступ к данным изображения и если это кkernelподпрограмма.Подпрограмма, изменяющая единственное пиксельное значение, будет всегда иметь a
samplerвозразите как входной параметр.samplerобъект для этой категорииkernelподпрограмма передается в от aCISamplerобъект создается в части Objective C модуля изображения. (См. Разделение труда.)samplerобъект просто получает пиксельные значения от исходное изображение. Можно думатьsamplerвозразите как источник данных.Объявляет a
vec4тип данных для содержания красного, зеленого, синего цвета, и альфа-значения компонентов пикселя. Вектор с четырьмя элементами обеспечивает удобный способ сохранить пиксельные данные.Выбирает пиксельное значение из исходного изображения. Давайте бросим более внимательный взгляд на этот оператор, особенно
sampleиsamplerCoordфункции, предоставленные Базовым Языком Ядра Изображения.samplerCoordфункционируйте возвращает позицию, в пространстве сэмплера, связанном с текущим целевым пикселем после того, как любые трансформации связались с источником изображения, или сэмплер применяются к данным изображения. Какkernelподпрограмма не имеет никакого способа знать, были ли какие-либо трансформации применены, лучше использоватьsamplerCoordфункция для получения позиции. При чтении Записи Части Objective C, Вы будете видеть, что это возможно, и часто необходимо, для применения трансформаций в части Objective C модуля изображения.sampleфункционируйте возвращает пиксельное значение, полученноеsamplerобъект от указанной позиции. Эта функция предполагает, что позиция находится в пространстве сэмплера, которое является, почему необходимо вложить вызов кsamplerCoordполучать позицию.Unpremultiplies пиксельные данные. Если Ваша подпрограмма воздействует на цветные данные, которые могли бы иметь альфа-значение другой тогда
1.0(полностью непрозрачный), необходимо вызвать Базовую функцию Языка Ядра Изображенияunpremultiply(или предпримите подобные шаги — посмотрите усовершенствованную подсказку ниже) до работы на значениях цветаИнвертирует красный компонент цвета. Следующие две строки инвертируют зеленые и синие компоненты цвета. Обратите внимание на то, что можно получить доступ к отдельным компонентам пикселя при помощи
.r,.g,.b, и.aвместо числового индекса. Тем путем Вы никогда не должны интересоваться порядком компонентов. (Можно также использовать.x,.y,.z, и.wкак полевые средства доступа.)Предварительно умножает данные и возвращает a
vec4тип данных, содержащий инвертированные значения для компонентов цвета целевого пикселя. Функцияpremultiplyопределяется Базовым Языком Ядра Изображения.
Когда Вы применяете цветную инверсию kernel подпрограмма к изображению, показанному на рисунке 2-3, Вы показали результат на рисунке 2-4.


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


Как Вы видите, подпрограмма в Перечислении 2-2 очень подобна Перечислению 2-1. Это kernel подпрограмма, однако, использует два вектора, один для пикселя, предоставленного из исходного изображения и другого для содержания измененных значений. Альфа-значение остается неизменным, но смещаются красные, зеленые, и синие значения.
Перечисление 2-2 A kernel подпрограмма, помещающая значения RGB в каналы GBR
kernel vec4 RGB_to_GBR(sampler source_image) |
{ |
vec4 originalColor, twistedColor; |
originalColor = sample(source_image, samplerCoord(source_image)); |
twistedColor.r = originalColor.g; |
twistedColor.g = originalColor.b; |
twistedColor.b = originalColor.r ; |
twistedColor.a = originalColor.a; |
return twistedColor; |
} |
Цветное умножение
Цветное умножение является истиной к своему имени; это умножает каждый пиксель в исходном изображении указанным цветом. Рисунок 2-7 показывает, что эффект применения цвета умножает фильтр к изображению, показанному на рисунке 2-5.

Перечисление 2-3 показывает kernel подпрограмма раньше производила этот эффект. Так, чтобы Вы не получали идею, что ядро может взять только один входной параметр, обратите внимание на то, что эта подпрограмма берет два входных параметра — один a sampler возразите и другой a __color тип данных. __color тип данных является одним из двух типов данных, определенных Базовым языком ядра Изображения; другой тип данных sampler, о котором Вы уже знаете. Эти два типа данных не являются единственными, что можно использовать входные параметры для a kernel подпрограмма. Можно также использовать эти типы данных, определяющиеся Открыть GL Shading Language (glslang) —float, vec2, vec3, vec4.
Цвет, предоставленный a kernel подпрограмма будет соответствующей Базовым Изображением к рабочему цветовому пространству Базового контекста Изображения, связанного с ядром. Нет ничего, относительно чего необходимо сделать, раскрашивают ядро. Просто имейте в виду это, к kernel подпрограмма, __color a vec4 тип данных в предварительно умноженном формате RGBA, так же, как пиксельные значения, выбранные sampler .
Перечисление 2-3 указывает на важный аспект вычислений ядра — использование векторной математики. Выборка выбирается Базовой функцией Языка Ядра Изображения sample вектор с четырьмя элементами. Поскольку это - вектор, можно умножить его непосредственно на multiplyColor; нет никакой потребности получить доступ к каждому компоненту отдельно.
К настоящему времени необходимо привыкнуть видеть samplerCoord функция, вложенная с sample функционируйте!
Перечисление 2-3 подпрограмма ядра, производящая умножить эффект
kernel vec4 multiplyEffect (sampler image_source, __color multiplyColor) |
{ |
return sample (image_source, samplerCoord (image_source)) * multiplyColor; |
} |
Проблема ядра
Теперь, когда Вы видели, как записать kernel подпрограммы, воздействующие на единственный пиксель, пора бросить вызов себе. Запишите a kernel подпрограмма, производящая монохромное изображение, подобное тому, что показано на рисунке 2-8. Фильтр должен взять два входных параметра, a sampler и a __color. Используйте Кварцевого Композитора, чтобы протестировать и отладить Вашу подпрограмму. Можно найти решение в Решении проблемы Ядра.

Тестирование подпрограмм ядра в кварцевом композиторе
kernel подпрограмма, как Вы знаете, является одной частью Базового фильтра Изображения. Существует все еще много кода, который необходимо записать на уровне выше, чем kernel подпрограмма и немного больше работы кроме того для упаковки кода обработки изображений как модуля изображения. К счастью, Вы не должны писать этот дополнительный код для тестирования простой kernel подпрограммы. Можно вместо этого использовать Кварцевого Композитора.
Кварцевый Композитор является средством разработки для обработки и рендеринга графических данных. Это доступно на любом компьютере, которому установили инструменты Developer. Можно найти его в /Developer/Applications. Следующие шаги покажут Вам, как использовать Кварцевого Композитора для тестирования каждого из kernel подпрограммы Вы читали о до сих пор.
Кварцевый Композитор запуска путем двойного щелчка по его значку в
/Developer/Applications.В листе, появляющемся, выберите Blank Composition.
Откройте Patch Creator и поиск Базового Фильтра Изображения.
Добавьте Базовый патч Фильтра Изображения к рабочей области.
Используйте поле поиска, чтобы определить местоположение патча Billboard, затем добавить что патч к рабочей области.
Подобным образом найдите патч Средства импорта Изображения и добавьте его к рабочей области.
Соедините выходной порт Изображения на патче Средства импорта Изображения к входному порту Изображения на Базовом патче Фильтра Изображения.
Соедините выходной порт Изображения на Базовом патче Фильтра Изображения к входному порту Изображения на Billboard.
Щелкните по патчу Средства импорта Изображения и затем нажмите кнопку Inspector на панели инструментов.
Выберите Settings из всплывающего меню инспектора. Тогда нажмите Import From File и выберите изображение.
Нажмите Viewer на панели инструментов, чтобы удостовериться, что окно Viewer видимо.
Необходимо видеть изображение, которое Вы импортировали представленный к окну Viewer.
Щелкните по Базовому патчу Фильтра Изображения и откройте инспектора для области Settings.
Обратите внимание на то, что уже существует a
kernelподпрограмма ввела для умножить эффекта. Если Вы хотите видеть, как это работает, выберите Input Parameters из всплывающего меню инспектора и затем щелкните по цвету хорошо для выбирания цвета. Вы сразу видите результаты в окне Viewer.
Скопируйте
kernelподпрограмма, показанная в Перечислении 2-1 и замене умножить подпрограмма эффекта, это находится в области Settings Базового Патча ядра Изображения.Заметьте, что не только делает изображение на изменении окна Viewer (его цвет должен быть инвертирован), но Базовый Патч ядра Изображения автоматически изменяется для соответствия входных параметров подпрограммы ядра. Ядро цвета инвертирования имеет только один входной параметр, тогда как умножить эффект, предоставленный как значение по умолчанию, имел два параметра.
Выполните ту же процедуру для тестирования
kernelподпрограмма, показанная в Перечислении 2-2.
Запись усовершенствованных подпрограмм ядра
До сих пор Вы видели, как записать несколько простые kernel подпрограммы, воздействующие на пиксель из исходного изображения для создания пикселя в конечном изображении, которое это в той же координате рабочей области как пиксель из исходного изображения. Некоторые самые интересные и полезные фильтры, однако, не используют это непосредственное отображение. Они более усовершенствованные kernel подпрограммы - то, о чем Вы узнаете в этом разделе.
Вспомните из Модуля Изображения и Его Частей это kernel подпрограммы, не использующие непосредственное отображение, требуют метода области интереса, определяющего область от который a sampler объект может выбрать пиксели. kernel подпрограмма ничего не знает об этом методе. Подпрограмма просто берет данные, передающиеся ей, воздействующие на нее и вычисляющие vec4 тип данных, что kernel стандартные возвраты. В результате этот раздел не показывает Вам, как установить метод ROI. Вы будете видеть, как выполнить ту задачу в письменной форме Часть Objective C. На данный момент предположите что каждый sampler переданный a kernel данные плановых поставок от надлежащей области интереса.
Пример изображения производится усовершенствованным kernel подпрограмма показана на рисунке 2-9. Данные показывают сетку пикселей, произведенных «цветовым блоком» kernel подпрограмма. Вы заметите, что блоки цвета 4 пикселя шириной и 4 пикселя высотой. Пиксели, отмеченные с «S», обозначают расположение пикселя в исходном изображении, из которого 4 4 блоками наследовал его цвет. Как Вы видите, kernel подпрограмма должна выполнить отображение one-many. Это - просто вид работы что пикселизирование kernel подпрограмма, обсужденная подробно в Pixellate, выполняет.

Вы будете видеть, как записать две других усовершенствованных подпрограммы ядра в Усилении контуров и Забавном Искажении Зеркала Дома.
Pixellate
Пикселизировать фильтр использует ограниченное количество пикселей из исходного изображения для создания конечного изображения, как описано в ранее. Сравните рисунок 2-3 с рисунком 2-10. Заметьте, что обработанное изображение выглядит глыбовым; это составлено из точек сплошного цвета. Размер точек определяется масштабным коэффициентом, это передается kernel подпрограмма как входной параметр.

Прием любому пикселизирует подпрограмму, должен использовать оператора модуля на координатах для деления координат на дискретные шаги. Это заставляет Ваш код читать тот же исходный пиксель, пока Ваша выходная координата не постепенно увеличилась вне порога масштаба, произведя эффект, подобный показанному на рисунке 2-10. Код, показанный в Перечислении 2-4, создает круглые точки вместо квадратов путем создания сглаженного края, производящего точечный эффект, показанный на рисунке 2-11. Заметьте, что каждый 4 4 блокирует, представляет единственный цвет, но альфа-компонент варьируется от 0,0 до 1,0. Сглаживающиеся эффекты используются во многих фильтрах, таким образом, стоит изучить код, показанный в Перечислении 2-4, выполняющем это.

Пикселизирование kernel подпрограмма берет два входных параметра: a sampler объект для выбирающих выборок из исходного изображения и значения с плавающей точкой, указывающего диаметр точек. Подробное объяснение каждой пронумерованной строки кода появляется после перечисления.
Перечисление 2-4 A kernel пикселизирующая подпрограмма
kernel vec4 roundPixellate(sampler src, float scale)// 1 |
{ |
vec2 positionOfDestPixel, centerPoint; // 2 |
float d, radius; |
vec4 outValue; |
float smooth = 0.5; |
radius = scale / 2.0; |
positionOfDestPixel = destCoord();// 3 |
centerPoint = positionOfDestPixel; |
centerPoint.x = centerPoint.x - mod(positionOfDestPixel.x, scale) + radius; // 4 |
centerPoint.y = centerPoint.y - mod(positionOfDestPixel.y, scale) + radius; // 5 |
d = distance(centerPoint, positionOfDestPixel); // 6 |
outValue = sample(src, samplerTransform(src, centerPoint)); // 7 |
outValue.a = outValue.a * smoothstep((d - smooth), d, radius); // 8 |
return premultiply(outValue); // 9 |
} |
Вот то, что делает код:
Берет a
samplerи масштабирующееся значение. Обратите внимание на то, что масштабирующееся значение объявляется как afloatтип данных здесь, но когда Вы пишете часть Objective C фильтра, необходимо передатьfloatкакNSNumberобъект. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.Объявляет два
vec2типы данных.centerPointпеременная содержит координату пикселя, определяющего цвет блока; это - «S», показанный на рисунке 2-11.positionOfDestPixelпеременная занимает позицию целевого пикселя.Получает позицию, в координатах рабочей области, пикселя, в настоящее время будучи вычисленным. Функция
destCoordопределяется Базовым Языком Ядра Изображения. (См. Базовую Ссылку Языка Ядра Изображения.)Вычисляет x-координату для пикселя, определяющего цвет целевого пикселя.
Вычисляет y-координату для пикселя, определяющего цвет целевого пикселя.
Вычисляет, как далеко целевой пиксель от центральной точки («S»). Это расстояние определяет значение альфа-компонента.
Выбирает пиксельное значение из исходного изображения, в расположении, указанном
centerPointвектор.Вспомните что
sampleфункционируйте возвращает пиксельное значение, произведенноеsamplerв указанной позиции. Эта функция предполагает, что позиция находится в пространстве сэмплера, которое является, почему необходимо вложить вызов кsamplerCoordполучать позицию.Создает сглаженный край путем умножения альфа-компонента целевого пикселя
smoothstepфункция, определяемая glslang. (См., что OpenGL Заштриховывает Спецификацию языка.)Предварительно умножает результат прежде, чем возвратить значение.
Вы будете видеть, как записать, что Objective C делит на части, это упаковывает эту подпрограмму как модуль изображения путем чтения Создания Модуля Изображения Pixellate.
Усиление контуров
Усиление контуров kernel подпрограмма, обсужденная в этом разделе, выполняет две задачи. Это обнаруживает края в изображении с помощью шаблона Sobel. Это также улучшает края. Несмотря на то, что kernel подпрограмма воздействует на все компоненты цвета, можно понять то, что, делает путем сравнения рисунка 2-12 с рисунком 2-13.


_EdgyFilter ядро показано в Перечислении 2-5. Требуется два параметра, a sampler для выборки данных изображения из исходного изображения и a power параметр это используется, чтобы украсить или затемнить изображение. Подробное объяснение каждой пронумерованной строки кода появляется после перечисления.
Перечисление 2-5 A kernel подпрограмма, улучшающая края
kernel vec4 _EdgyFilter(sampler image, float power) // 1 |
{ |
const vec2 xy = destCoord(); // 2 |
vec4 p00,p01,p02, p10,p12, p20,p21,p22; // 3 |
vec4 sumX, sumY, computedPixel; // 4 |
float edgeValue; |
p00 = sample(image, samplerTransform(image, xy+vec2(-1.0, -1.0))); // 5 |
p01 = sample(image, samplerTransform(image, xy+vec2( 0.0, -1.0))); |
p02 = sample(image, samplerTransform(image, xy+vec2(+1.0, -1.0))); |
p10 = sample(image, samplerTransform(image, xy+vec2(-1.0, 0.0))); |
p12 = sample(image, samplerTransform(image, xy+vec2(+1.0, 0.0))); |
p20 = sample(image, samplerTransform(image, xy+vec2(-1.0, +1.0))); |
p21 = sample(image, samplerTransform(image, xy+vec2( 0.0, +1.0))); |
p22 = sample(image, samplerTransform(image, xy+vec2(+1.0, +1.0))); |
sumX = (p22+p02-p20-p00) + 2.0*(p12-p10); // 6 |
sumY = (p20+p22-p00-p02) + 2.0*(p21-p01); // 7 |
edgeValue = sqrt(dot(sumX,sumX) + dot(sumY,sumY)) * power; // 8 |
computedPixel = sample(image, samplerCoord(image)); // 9 |
computedPixel.rgb = computedPixel.rgb * edgeValue; // 10 |
return computedPixel; // 11 |
} |
Вот то, что делает код:
Берет a
samplerи apowerзначение. Обратите внимание на то, чтоpowerзначение объявляется как afloatтип данных здесь, но когда Вы пишете часть Objective C фильтра, необходимо передатьfloatкакNSNumberобъект. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.Получает позицию, в координатах рабочей области, пикселя, в настоящее время будучи вычисленным. Функция
destCoordопределяется Базовым Языком Ядра Изображения. (См. Базовую Ссылку Языка Ядра Изображения.)Объявляет 8 векторов с четырьмя элементами. Эти векторы будут содержать значения 8 пикселей, которые являются соседями целевого пикселя что
kernelподпрограмма является вычислительной.Объявляет, что векторы содержат промежуточные результаты, и финал вычислил пиксель.
Это и следующие семь строк кода выбирают 8 соседних пикселей.
Вычисляет сумму x значений соседних пикселей, взвешенных шаблоном Sobel.
Вычисляет сумму y значений соседних пикселей, взвешенных шаблоном Sobel.
Вычисляет величину, затем масштабируется
powerпараметр. Величина обеспечивает граничную часть обнаружения/улучшения фильтра, и питание имеет прояснение (или затемнение) эффект.Получает пиксель, целевое значение которого должно быть вычислено.
Изменяет цвет целевого пикселя граничным значением.
Возвращает вычисленный пиксель.
Когда Вы применяетесь _EdgyFilter ядро к изображению, показанному на рисунке 2-3, Вы показали получающееся изображение на рисунке 2-14.

Забавное искажение зеркала дома
Забавный дом зеркально отражает искажение kernel подпрограмма предоставлена как значение по умолчанию kernel подпрограмма для модуля изображения обрабатывает по шаблону в XCode. (Вы изучите, как использовать шаблон модуля изображения в письменной форме Часть Objective C.) Подобный зеркалу в доме забавы карнавала, этот фильтр искажает изображение путем протяжения и увеличения вертикальной полосы изображения. Сравните рисунок 2-15 с рисунком 2-3.

Забавный дом kernel подпрограмма, показанная в Перечислении 2-6, берет следующие параметры:
srcsamplerэто выбирает данные изображения из исходного изображения.center_xкоордината x, определяющая центр вертикальной полосы, в которой имеет место деформирование.inverse_radiusинверсия радиуса. Можно избежать операции деления вkernelподпрограмма путем выполнения этого вычисления вне подпрограммы, в части Objective C фильтра.radiusстепень эффекта.scaleуказывает сумму деформирования.
mySmoothstep подпрограмма в Перечислении 2-6 является пользовательской функцией сглаживания, чтобы гарантировать, чтобы пиксели в краю эффекта смешались с остальной частью изображения.
Код перечисления 2-6, создающий забавное искажение зеркала дома
float mySmoothstep(float x) |
{ |
return (x * -2.0 + 3.0) * x * x; |
} |
kernel vec4 funHouse(sampler src, float center_x, float inverse_radius, |
float radius, float scale) // 1 |
{ |
float distance; |
vec2 myTransform1, adjRadius; |
myTransform1 = destCoord(); // 2 |
adjRadius.x = (myTransform1.x - center_x) * inverse_radius; // 3 |
distance = clamp(abs(adjRadius.x), 0.0, 1.0); // 4 |
distance = mySmoothstep(1.0 - distance) * (scale - 1.0) + 1.0; // 5 |
myTransform1.x = adjRadius.x * distance * radius + center_x; // 6 |
return sample(src, samplerTransform(src, myTransform1)); // 7 |
} |
Вот то, что делает код:
Берет a
samplerи четыреfloatзначения как параметры. Обратите внимание на то, что, когда Вы пишете часть Objective C фильтра, необходимо передать каждогоfloatоцените какNSNumberобъект. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.Выбирает позицию, в координатах рабочей области, пикселя, в настоящее время будучи вычисленным.
Вычисляет координату x, это корректируется, поскольку это - расстояние от центра эффекта.
Вычисляет значение расстояния на основе скорректированной координаты x, и это варьируется между
0и1. По существу это нормализует расстояние.Корректирует нормализованное значение расстояния так, чтобы был, варьируется вдоль кривой.
scaleзначение определяет высоту кривой. Значение радиуса, используемое ранее для вычисления расстояния, определяет ширину кривой.Вычисляет вектор трансформации.
Возвращает пиксель, расположенный в позиции в координатном пространстве после того, как координатное пространство будет преобразовано
myTransform1вектор.
Смотрите на модуль изображения по умолчанию в XCode для наблюдения то, что требуется для части Objective C модуля изображения. (См. Шаблон Модуля Изображения в XCode.) Вы будете видеть, что требуется метод области интереса. Вы также заметите, что обратное вычисление радиуса вычислено в outputImage метод.
Запись подпрограмм ядра для детективной линзы
В этом разделе описываются более сложное использование kernel подпрограммы. Вы будете видеть, как создать два kernel подпрограммы, которые могли стоять самостоятельно, но позже, в Создании Детективного Модуля Изображения Линзы, Вы будете видеть, как объединить их для создания фильтра, который, пользователю, будет выглядеть подобным физической увеличивающей линзе, как показано на рисунке 2-16.

Для создания этого эффекта необходимо выполнить задачи вне kernel подпрограмма. Вам будет нужен код Objective C, чтобы установить подпрограммы области интереса, установить входные параметры для каждого kernel подпрограмма, и передать выходное изображение, произведенное каждым kernel подпрограмма к составляющему композит фильтру. Вы будете видеть, как выполнить эти задачи позже. После обсуждения проблемы и компонентов детективной линзы, Вы будете видеть, как записать каждый из kernel подпрограммы.
Проблема: почему детективная линза?
Разрешение изображений, взятых сегодняшними цифровыми фотоаппаратами, опередило разрешение экранов компьютера. Изображения обычно субдискретизируются приложениями редактирования изображение, чтобы позволить пользователю видеть все изображение на экране. К сожалению, субдискретизация скрывает подробные данные в изображении. Одно решение состоит в том, чтобы показать изображение с помощью 1:1 отношение между разрешением экрана и разрешением изображения. Это решение не идеально, потому что только часть изображения выведена на экран на экране, заставив пользователя прокрутить для просмотра других частей изображения.
Это - то, где входит детективный фильтр линзы. Фильтр позволяет пользователю проверять подробные данные части изображения высокого разрешения, подобного тому, что показано на рисунке 2-17. Фильтр фактически не увеличивает исходное изображение. Вместо этого это выводит на экран субдискретизируемое изображение для пикселей, которые не являются под линзой, и выбирает пиксели от немасштабированного исходного изображения для пикселей, которые являются под линзой.

Детективная анатомия линзы
Прежде, чем записать любому kernel подпрограмма, полезно понять параметры, управляющие эффектом обработки изображений, которого Вы хотите достигнуть. Рисунок 2-18 показывает схему вида сверху линзы. Линза, имеет центр и диаметр. У держателя линзы есть ширина. Линза также имеет:
Непрозрачность. Сравните цвета под линзой с теми вне линзы на рисунке 2-17.
Отражающая способность, которая может вызвать солнечный спот на линзе, если линза не имеет современного покрытия без отражений.

Рисунок 2-19 показывает другую характеристику линзы, влияющей на ее эффект — округлость. Эта линза выпукла, но высота, показанная в схеме (вместе с диаметром линзы) средства управления, насколько кривой линза.

У держателя линзы есть дополнительные характеристики, как Вы видите на рисунке 2-20. У этого определенного держателя линзы есть сопряжение. Сопряжение является полосой материала, округляющего внутренний угол между двумя разделами. Путем рассмотрения сечения Вы будете видеть, что у держателя линзы может быть три части к нему — внутренний скошенный раздел, внешний скошенный раздел и стрижка под ежика. Радиус сопряжения определяет, существует ли стрижка под ежика, как показано в числе. Если радиус сопряжения является половиной ширины держателя линзы, нет никакой стрижки под ежика. Если радиус сопряжения будет меньше чем половиной ширины держателя линзы, то будет сглаженный раздел как показано в числе.

Затем Вы будете смотреть на kernel подпрограммы должны были произвести характеристики держателя линзы и линзы.
Подпрограмма ядра линзы
Линза kernel подпрограмма должна произвести эффект, подобный физической линзе. Мало того, что подпрограмма, должно казаться, увеличивает то, что под нею, но это должно быть немного непрозрачно и отразить некоторый свет. Рисунок 2-21 показывает линзу с теми характеристиками.

В предыдущих разделах Вы видели, как записать подпрограммы, требующие только одного sampler. kernel подпрограмма, произведшая эффект, показанный на рисунке 2-21, требует три sampler объекты для выбирающих пикселей от:
Изображение с высокой разрешающей способностью. Вспомните, что цель линзы состоит в том, чтобы позволить пользователю проверять подробные данные в изображении, которому это является слишком большим для адаптации на экране. Это
samplerвозразите выбирает пиксели для показа под линзой — часть изображения, которое будет казаться увеличенным. В зависимости от суммы увеличения, желаемого клиентом фильтра,samplerвозможно, должен был бы субдискретизировать изображение высокого разрешения.Субдискретизируемая версия изображения с высокой разрешающей способностью. Это
samplerвозразите выбирает пиксели для показа вне линзы — часть изображения, которое, будет казаться, не будет увеличено.Изображение выделения. Эти выборки используются для генерации выделений в линзе для предоставления появления линзы, являющейся отражающим. Рисунок 2-22 показывает изображение выделения. Выделения являются столь тонкими, что для репродуцирования изображения для этого документа прозрачные пиксели представлены как черные. Белые пиксели непрозрачны. Выделение, показанное в числе, преувеличено так, чтобы оно могло быть замечено здесь.
Вспомните, что установка работает на sampler объекты сделаны в части Objective C модуля изображения. Посмотрите Разделение труда. Вы будете видеть, как установить CISampler объекты в Создании Детективного Модуля Изображения Линзы.

Линза kernel подпрограмма (см. Перечисление 2-7) берет девять входных параметров:
downsampled_srcsamplerсвязанный с субдискретизируемой версией изображения.hires_srcsamplerсвязанный с изображением высокого разрешения.highlightssamplerсвязанный с изображением выделения.centerвектор с двумя элементами, указывающий центр увеличивающей линзы.radiusрадиус увеличивающей линзы.roundnessзначение, указывающее, насколько выпуклый линза.opacityуказывает, насколько непрозрачный стекло увеличивающей линзы. Если линза имеет покрытие без отражений, это значение0.0. Если это является максимально отражающим, значение1.0.highlight sizeвектор с двумя элементами, указывающий высоту и ширину изображения выделения.
Теперь, когда Вы знаете немного о характеристиках линзы и входных параметрах, необходимых для kernel подпрограмма, смотрите на Перечисление 2-7. После необходимых объявлений подпрограмма начинается путем вычисления нормализованного расстояния. Три строки кода, выполняющие это вычисление, типичны для подпрограмм, работающих в части изображения. Часть подпрограммы посвящена вычислению и применению преобразования, определяющего, какой пиксель от выделения отображают для выборки, и затем изменение увеличенного пикселя пикселем выделения. Вы найдете больше информации в подробном объяснении каждой пронумерованной строки кода, следующего за перечислением.
Перечисление 2-7 A kernel подпрограмма для линзы
kernel vec4 lens(sampler downsampled_src, sampler highres_src, sampler highlights, |
vec2 center, float radius, float magnification, |
float roundness, float opacity, vec2 highlightsSize) // 1 |
{ |
float dist, mapdist; // 2 |
vec2 v0; // 3 |
vec4 pix, pix2, mappix; // 4 |
v0 = destCoord() - center; // 5 |
dist = length(v0); // 6 |
v0 = normalize(v0); // 7 |
pix = sample(downsampled_src, samplerCoord(downsampled_src)); // 8 |
mapdist = (dist / radius) * roundness; // 9 |
mappix = sample(highlights, samplerTransform(highlights, |
highlightsSize * (v0 * mapdist + 1.0) * 0.5)); // 10 |
mappix *= opacity; // 11 |
pix2 = sample(highres_src, samplerCoord(highres_src)); // 12 |
pix2 = mappix + (1.0 - mappix.a) * pix2; // 13 |
return mix(pix, pix2, clamp(radius - dist, 0.0, 1.0)); // 14 |
} |
Вот то, что делает код:
Берет три
samplerобъекты, четыреfloatзначения, и дваvec2типы данных как параметры. Обратите внимание на то, что, когда Вы пишете часть Objective C фильтра, необходимо передать каждогоfloatиvec2значения какNSNumberобъекты. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.Объявляет две переменные:
distобеспечивает промежуточное хранение для вычисления amapdistрасстояние.mapdistиспользуется для определения, какой пиксель выбрать от выделения отображают.Объявляет вектор с двумя элементами для хранения нормализованного расстояния.
Объявляет три вектора с четырьмя элементами для хранения пиксельных значений, связанных с тремя
samplerисточники.Вычитает вектор, представляющий центральную точку линзы от вектора, представляющего координату назначения.
Вычисляет длину вектора различия.
Нормализует вектор расстояния.
Выбирает пиксель от субдискретизируемого изображения. Вспомните, что это изображение представляет пиксели, появляющиеся вне линзы — «неувеличенные» пиксели.
Вычисляет значение расстояния, которое необходимо для определения, какой пиксель выбрать от выделения отображают. Это вычисление необходимо, потому что размер изображения выделения независим от диаметра линзы. Вычисление гарантирует, чтобы выделение отобразило фрагменты или уменьшения для адаптации области линзы.
Выбирает пиксель от изображения выделения путем применения преобразования на основе функции расстояния и размера выделения.
Изменяет пиксель, выбранный от изображения выделения для учета непрозрачности линзы.
Выбирает пиксель от изображения высокого разрешения. Вы будете видеть позже (Создающий Детективный Модуль Изображения Линзы), что увеличение применяется в части Objective C модуля изображения.
Изменяет пиксель от изображения высокого разрешения скорректированным непрозрачностью пикселем выделения.
Смягчает край между увеличенным (изображение высокого разрешения) и неувеличенный (субдискретизируемое изображение) пиксели.
mixиclampфункции, предоставленные Языком Штриховки OpenGL, имеют поддержку оборудования и, в результате намного более эффективны для Вас для использования, чем реализовать собственное.clampфункцияgenType clamp (genType x, float minValue, float maxValue)возвраты:
min(max(x, minValue), maxValue)Если координата назначения находится в пределах области линзы, значения
xвозвращается; иначеclampвозвраты0.0.mixфункцияgenType mix (genType x, genType y,float a)возвращает линейное смешение между первыми двумя параметрами (x, y) передал функции:
x * (1 - a) + y * aЕсли координата назначения падает за пределами области линзы (
a = 0.0),mixвозвращает неувеличенный пиксель. Если координата назначения падает на края линзы (a = 1.0),mixвозвращает линейное смешение увеличенных и неувеличенных пикселей. Если координата назначения в области линзы,mixвозвраты увеличили пиксель.
Подпрограмма ядра держателя линзы
Держатель линзы kernel подпрограмма является подпрограммой генератора в этом, не воздействует ни на какие пиксели из исходного изображения. kernel подпрограмма генерирует изображение из материальной карты, и то изображение находится поверх исходного изображения. Посмотрите рисунок 2-23.

Материальная карта для держателя линзы показана на рисунке 2-24. Это - цифровая фотография очень отражающего шара. Можно так же, как легко использовать другое изображение отражающего материала.

kernel подпрограмма выполняет несколько вычислений для определения который пиксель выбрать из материальной карты для каждого расположения на держателе линзы. Подпрограмма деформирует материальную карту для адаптации внутренней части держателя линзы и деформирует его наоборот так, чтобы это соответствовало внешней части держателя линзы. Если радиус сопряжения является меньше, чем половина радиуса держателя линзы, подпрограмма окрашивает плоскую часть держателя линзы при помощи пикселей от центральной части материальной карты. Это может быть немного проще для наблюдения результатов деформирования путем рассмотрения держателя линзы на рисунке 2-25, создававшемся из настроечной таблицы. Число также демонстрирует, что, если Вы не используете изображение, имеющее отражения в нем, держатель линзы не будет выглядеть реалистичным.

Держатель линзы kernel подпрограмма (см. Перечисление 2-8) берет шесть входных параметров:
materialasamplerвозразите что выборки выборок из материальной карты, показанной на рисунке 2-24.centerвектор с двумя элементами, указывающий центр линзы, которую держатель линзы разработан для содержания.innerRadiusрасстояние от центра линзы к внутреннему краю держателя линзы.outerRadiusрасстояние от центра линзы к внешнему краю держателя линзы.filletRadiusрасстояние от края держателя линзы к центру держателя линзы. Это значение должно быть меньше чем половиной радиуса держателя линзы.materialSizeвектор с двумя элементами, указывающий высоту и ширину материальной карты.
Подпрограмма, показанная в Перечислении 2-8, запускается с необходимых объявлений. Подобный линзе kernel подпрограмма, держатель линзы kernel подпрограмма вычисляет нормализованное расстояние. Его эффект ограничивается кольцевой формой, таким образом, нормализованное расстояние необходимо для определения, где применить эффект. Подпрограмма также вычислила, является ли координата назначения на внутренней или внешней части кольца (т.е. держатель линзы). Часть подпрограммы создает преобразование, тогда использующееся для выборки пикселя из материальной карты. Материальный размер карты независим от внутреннего и внешнего диаметра держателя линзы, таким образом, преобразование необходимо для выполнения деформирования, требуемого отобразить материал на держателя линзы. Вы найдете больше информации в подробном объяснении каждой пронумерованной строки кода, следующего за перечислением.
Перечисление 2-8 A kernel подпрограмма, генерирующая держателя увеличивающей линзы
kernel vec4 ring(sampler material, vec2 center, float innerRadius, |
float outerRadius, float filletRadius, vec2 materialSize) // 1 |
{ |
float dist, f, d0, d1, alpha; |
vec2 t0, v0; |
vec4 pix; |
t0 = destCoord() - center; // 2 |
dist = length(t0);// 3 |
v0 = normalize(t0);// 4 |
d0 = dist - (innerRadius + filletRadius); // 5 |
d1 = dist - (outerRadius - filletRadius); // 6 |
f = (d1 > 0.0) ? (d1 / filletRadius) : min(d0 / filletRadius, 0.0); // 7 |
v0 = v0 * f; // 8 |
alpha = clamp(dist - innerRadius, 0.0, 1.0) * clamp(outerRadius - dist, 0.0, 1.0); // 9 |
v0 = materialSize * (v0 + 1.0) * 0.5; // 10 |
pix = sample(material, samplerTransform(material, v0)); // 11 |
return pix * alpha; // 11 |
} |
Вот то, что делает код:
Берет тот
samplerобъект, триfloatзначения, и дваvec2типы данных как параметры. Обратите внимание на то, что, когда Вы пишете часть Objective C фильтра, необходимо передать каждогоfloatиvec2значение какNSNumberобъекты. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.Вычитает вектор, представляющий центральную точку линзы от вектора, представляющего координату назначения.
Вычисляет длину вектора различия.
Нормализует длину.
Вычисляет, является ли координата назначения на внутренней части держателя линзы.
Вычисляет, является ли координата назначения на внешней части держателя линзы.
Вычисляет значение формирования, зависящее от расположения координаты назначения:
[-1...0]во внутренней части держателя линзы,[0...1]во внешней части держателя линзы, и0иначе.Изменяет нормализованное расстояние для учета сопряжения держателя линзы. Это значение сформирует держателя линзы.
Вычисляет альфа-значение для пикселя в координате назначения. Если расположение далеко от внутреннего радиуса, альфа-значение фиксируется к
0.0. Точно так же, если расположение промахивается по внешнему радиусу, результат фиксируется к0.0. Альфа-значения в держателе линзы фиксируются к1.0. Пиксели не на держателе линзы прозрачны.Изменяет
v0вектор шириной и высотой материальной карты. Тогда масштабирует вектор для учета размера материальной карты.Выбирает пиксель из материальной карты путем применения
v0вектор как преобразование.Применяет альфу к пикселю до возврата его.
Решение проблемы ядра
kernel подпрограмма для монохромного фильтра должна выглядеть подобной тому, что показано в Перечислении 2-9.
Перечисление 2-9 решение монохромной проблемы фильтра
kernel vec4 monochrome(sampler image, __color color) |
{ |
vec4 pixel; |
pixel = sample(image, samplerCoord(image)); |
pixel.g = pixel.b = pixel.r; |
return pixel * color; |
} |
Следующие шаги
Теперь, когда Вы видели, как записать множество kernel подпрограммы, Вы готовы идти дальше к записи части Objective C модуля изображения. Следующая глава показывает, как создать проект из шаблона модуля изображения XCode. Вы будете видеть, как создать модуль изображения для нескольких из kernel подпрограммы описаны в этой главе.