Запись ядер
Основа любого фильтра обработки изображений является файлом ядра. Файл ядра содержит один или больше 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, берет следующие параметры:
src
sampler
это выбирает данные изображения из исходного изображения.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_src
sampler
связанный с субдискретизируемой версией изображения.hires_src
sampler
связанный с изображением высокого разрешения.highlights
sampler
связанный с изображением выделения.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) берет шесть входных параметров:
material
asampler
возразите что выборки выборок из материальной карты, показанной на рисунке 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
подпрограммы описаны в этой главе.