Запись ядер

Основа любого фильтра обработки изображений является файлом ядра. Файл ядра содержит один или больше kernel подпрограммы и любые требуемые подпрограммы. A kernel подпрограмму вызывают один раз для каждого пикселя для конечного изображения. Подпрограмма должна возвратить a vec4 тип данных. Несмотря на то, что этот вектор с четырьмя элементами обычно содержит пиксельные данные, вектор не требуется, чтобы представлять пиксель. Однако kernel подпрограммы в этой главе производят только пиксельные данные, потому что это - наиболее распространенные данные, возвращенные a kernel подпрограмма.

A kernel подпрограмма может:

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

Несмотря на то, что kernel подпрограмма - то, где обработка на пиксель происходит, это - только одна часть модуля изображения. Также необходимо записать код, предоставляющий входные данные kernel подпрограмма и выполняет много других задач, как описано в письменной форме Часть Objective C. Тогда необходимо будет связать весь код путем следования инструкциям в Подготовке Модуля Изображения для Распределения.

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

Запись простых подпрограмм ядра

A kernel подпрограмма, воздействующая на цвет исходного пикселя в расположении (x, y) для создания пикселя в том же расположении в конечном изображении, является довольно прямой для записи. В целом, a kernel подпрограмма, воздействующая на цвет, выполняет эти шаги:

  1. Получает пиксель из исходного изображения, которое является в том же расположении как пиксель, который Вы хотите произвести в выходном изображении. Базовая функция Языка Ядра Изображения sample возвращает пиксельное значение, произведенное указанным sampler в указанной точке. Для понимания указанной мысли используйте функцию samplerCoord, то, которое возвращает позицию в пространстве сэмплера, связанном с пикселем текущей производительности после того, как любая матрица преобразования связалась с сэмплером, применяется. Это означает, преобразовывается ли изображение в некотором роде (например, вращение или масштабирующийся), sampler гарантирует, что трансформация отражается в выборке, которую она выбирает.

  2. Воздействует на значения цвета.

  3. Возвращает измененный пиксель.

Уравнения для этого вида фильтра принимают следующую форму:

A general equation

В зависимости от работы Вам, возможно, понадобятся к 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.

Рисунок 2-1  сетка
A grid of pixels
pixelsFigure 2-2
  сетка пикселей после инвертирования цвета
A grid of pixels after inverting the color

Смотрите на 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
}

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

  1. Берет a sampler возразите как входной параметр. Вспомните (см. Правила Подпрограммы Ядра), это kernel подпрограммы не берут изображения в качестве входных параметров. Вместо этого sampler объект отвечает за доступ к данным изображения и если это к kernel подпрограмма.

    Подпрограмма, изменяющая единственное пиксельное значение, будет всегда иметь a sampler возразите как входной параметр. sampler объект для этой категории kernel подпрограмма передается в от a CISampler объект создается в части Objective C модуля изображения. (См. Разделение труда.) sampler объект просто получает пиксельные значения от исходное изображение. Можно думать sampler возразите как источник данных.

  2. Объявляет a vec4 тип данных для содержания красного, зеленого, синего цвета, и альфа-значения компонентов пикселя. Вектор с четырьмя элементами обеспечивает удобный способ сохранить пиксельные данные.

  3. Выбирает пиксельное значение из исходного изображения. Давайте бросим более внимательный взгляд на этот оператор, особенно sample и samplerCoord функции, предоставленные Базовым Языком Ядра Изображения. samplerCoord функционируйте возвращает позицию, в пространстве сэмплера, связанном с текущим целевым пикселем после того, как любые трансформации связались с источником изображения, или сэмплер применяются к данным изображения. Как kernel подпрограмма не имеет никакого способа знать, были ли какие-либо трансформации применены, лучше использовать samplerCoord функция для получения позиции. При чтении Записи Части Objective C, Вы будете видеть, что это возможно, и часто необходимо, для применения трансформаций в части Objective C модуля изображения.

    sample функционируйте возвращает пиксельное значение, полученное sampler объект от указанной позиции. Эта функция предполагает, что позиция находится в пространстве сэмплера, которое является, почему необходимо вложить вызов к samplerCoord получать позицию.

  4. Unpremultiplies пиксельные данные. Если Ваша подпрограмма воздействует на цветные данные, которые могли бы иметь альфа-значение другой тогда 1.0 (полностью непрозрачный), необходимо вызвать Базовую функцию Языка Ядра Изображения unpremultiply (или предпримите подобные шаги — посмотрите усовершенствованную подсказку ниже) до работы на значениях цвета

  5. Инвертирует красный компонент цвета. Следующие две строки инвертируют зеленые и синие компоненты цвета. Обратите внимание на то, что можно получить доступ к отдельным компонентам пикселя при помощи .r, .g, .b, и .a вместо числового индекса. Тем путем Вы никогда не должны интересоваться порядком компонентов. (Можно также использовать .x, .y, .z, и .w как полевые средства доступа.)

  6. Предварительно умножает данные и возвращает a vec4 тип данных, содержащий инвертированные значения для компонентов цвета целевого пикселя. Функция premultiply определяется Базовым Языком Ядра Изображения.

Когда Вы применяете цветную инверсию kernel подпрограмма к изображению, показанному на рисунке 2-3, Вы показали результат на рисунке 2-4.

Рисунок 2-3  изображение
An image of a gazelle
gazelleFigure 2-4
  изображение газели после инвертирования цветов
A gazelle image after inverting the colors

Перестановка компонента цвета

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

Рисунок 2-5  изображение
An image of a ladybug
ladybugFigure 2-6
  изображение божьей коровки после реконструкции пиксельных компонентов
A ladybug image after rearranging pixel components

Как Вы видите, подпрограмма в Перечислении 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-7  изображение божьей коровки после применения умножить фильтра
A ladybug image after applying a multiply filter

Перечисление 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. Используйте Кварцевого Композитора, чтобы протестировать и отладить Вашу подпрограмму. Можно найти решение в Решении проблемы Ядра.

Рисунок 2-8  монохромное изображение божьей коровки
A monochrome image of a ladybug

Тестирование подпрограмм ядра в кварцевом композиторе

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

Кварцевый Композитор является средством разработки для обработки и рендеринга графических данных. Это доступно на любом компьютере, которому установили инструменты Developer. Можно найти его в /Developer/Applications. Следующие шаги покажут Вам, как использовать Кварцевого Композитора для тестирования каждого из kernel подпрограммы Вы читали о до сих пор.

  1. Кварцевый Композитор запуска путем двойного щелчка по его значку в /Developer/Applications.

  2. В листе, появляющемся, выберите Blank Composition.

  3. Откройте Patch Creator и поиск Базового Фильтра Изображения.

  4. Добавьте Базовый патч Фильтра Изображения к рабочей области.

  5. Используйте поле поиска, чтобы определить местоположение патча Billboard, затем добавить что патч к рабочей области.

  6. Подобным образом найдите патч Средства импорта Изображения и добавьте его к рабочей области.

  7. Соедините выходной порт Изображения на патче Средства импорта Изображения к входному порту Изображения на Базовом патче Фильтра Изображения.

  8. Соедините выходной порт Изображения на Базовом патче Фильтра Изображения к входному порту Изображения на Billboard.

  9. Щелкните по патчу Средства импорта Изображения и затем нажмите кнопку Inspector на панели инструментов.

  10. Выберите Settings из всплывающего меню инспектора. Тогда нажмите Import From File и выберите изображение.

  11. Нажмите Viewer на панели инструментов, чтобы удостовериться, что окно Viewer видимо.

    Необходимо видеть изображение, которое Вы импортировали представленный к окну Viewer.

  12. Щелкните по Базовому патчу Фильтра Изображения и откройте инспектора для области Settings.

    Обратите внимание на то, что уже существует a kernel подпрограмма ввела для умножить эффекта. Если Вы хотите видеть, как это работает, выберите Input Parameters из всплывающего меню инспектора и затем щелкните по цвету хорошо для выбирания цвета. Вы сразу видите результаты в окне Viewer.

    The default kernel routine in the Core Image Kernel patch
  13. Скопируйте kernel подпрограмма, показанная в Перечислении 2-1 и замене умножить подпрограмма эффекта, это находится в области Settings Базового Патча ядра Изображения.

    Заметьте, что не только делает изображение на изменении окна Viewer (его цвет должен быть инвертирован), но Базовый Патч ядра Изображения автоматически изменяется для соответствия входных параметров подпрограммы ядра. Ядро цвета инвертирования имеет только один входной параметр, тогда как умножить эффект, предоставленный как значение по умолчанию, имел два параметра.

  14. Выполните ту же процедуру для тестирования 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, выполняет.

Рисунок 2-9  Цветные блоки пикселей
Colored blocks of pixels

Вы будете видеть, как записать две других усовершенствованных подпрограммы ядра в Усилении контуров и Забавном Искажении Зеркала Дома.

Pixellate

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

Рисунок 2-10  изображение газели после растрирования
A gazelle image after pixellation

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

Рисунок 2-11  Цветные блоки пикселей с непрозрачностью добавил
Colored blocks of pixels with opacity added

Пикселизирование 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
 
}

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

  1. Берет a sampler и масштабирующееся значение. Обратите внимание на то, что масштабирующееся значение объявляется как a float тип данных здесь, но когда Вы пишете часть Objective C фильтра, необходимо передать float как NSNumber объект. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.

  2. Объявляет два vec2 типы данных. centerPoint переменная содержит координату пикселя, определяющего цвет блока; это - «S», показанный на рисунке 2-11. positionOfDestPixel переменная занимает позицию целевого пикселя.

  3. Получает позицию, в координатах рабочей области, пикселя, в настоящее время будучи вычисленным. Функция destCoord определяется Базовым Языком Ядра Изображения. (См. Базовую Ссылку Языка Ядра Изображения.)

  4. Вычисляет x-координату для пикселя, определяющего цвет целевого пикселя.

  5. Вычисляет y-координату для пикселя, определяющего цвет целевого пикселя.

  6. Вычисляет, как далеко целевой пиксель от центральной точки («S»). Это расстояние определяет значение альфа-компонента.

  7. Выбирает пиксельное значение из исходного изображения, в расположении, указанном centerPoint вектор.

    Вспомните что sample функционируйте возвращает пиксельное значение, произведенное sampler в указанной позиции. Эта функция предполагает, что позиция находится в пространстве сэмплера, которое является, почему необходимо вложить вызов к samplerCoord получать позицию.

  8. Создает сглаженный край путем умножения альфа-компонента целевого пикселя smoothstep функция, определяемая glslang. (См., что OpenGL Заштриховывает Спецификацию языка.)

  9. Предварительно умножает результат прежде, чем возвратить значение.

Вы будете видеть, как записать, что Objective C делит на части, это упаковывает эту подпрограмму как модуль изображения путем чтения Создания Модуля Изображения Pixellate.

Усиление контуров

Усиление контуров kernel подпрограмма, обсужденная в этом разделе, выполняет две задачи. Это обнаруживает края в изображении с помощью шаблона Sobel. Это также улучшает края. Несмотря на то, что kernel подпрограмма воздействует на все компоненты цвета, можно понять то, что, делает путем сравнения рисунка 2-12 с рисунком 2-13.

Рисунок 2-12  настроечная таблица прежде
A checkerboard pattern before edge enhancement
ограничивает enhancementFigure 2-13
  настроечную таблицу после усиления контуров
A checkerboard pattern after edge enhancement

_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
}

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

  1. Берет a sampler и a power значение. Обратите внимание на то, что power значение объявляется как a float тип данных здесь, но когда Вы пишете часть Objective C фильтра, необходимо передать float как NSNumber объект. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.

  2. Получает позицию, в координатах рабочей области, пикселя, в настоящее время будучи вычисленным. Функция destCoord определяется Базовым Языком Ядра Изображения. (См. Базовую Ссылку Языка Ядра Изображения.)

  3. Объявляет 8 векторов с четырьмя элементами. Эти векторы будут содержать значения 8 пикселей, которые являются соседями целевого пикселя что kernel подпрограмма является вычислительной.

  4. Объявляет, что векторы содержат промежуточные результаты, и финал вычислил пиксель.

  5. Это и следующие семь строк кода выбирают 8 соседних пикселей.

  6. Вычисляет сумму x значений соседних пикселей, взвешенных шаблоном Sobel.

  7. Вычисляет сумму y значений соседних пикселей, взвешенных шаблоном Sobel.

  8. Вычисляет величину, затем масштабируется power параметр. Величина обеспечивает граничную часть обнаружения/улучшения фильтра, и питание имеет прояснение (или затемнение) эффект.

  9. Получает пиксель, целевое значение которого должно быть вычислено.

  10. Изменяет цвет целевого пикселя граничным значением.

  11. Возвращает вычисленный пиксель.

Когда Вы применяетесь _EdgyFilter ядро к изображению, показанному на рисунке 2-3, Вы показали получающееся изображение на рисунке 2-14.

Рисунок 2-14  изображение газели после усиления контуров
A gazelle image after edge enhancement

Забавное искажение зеркала дома

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

Рисунок 2-15  изображение газели, искаженное забавным домом, зеркально отражает подпрограмму
A  gazelle image distorted by a fun house mirror routine

Забавный дом 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
}

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

  1. Берет a sampler и четыре float значения как параметры. Обратите внимание на то, что, когда Вы пишете часть Objective C фильтра, необходимо передать каждого float оцените как NSNumber объект. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.

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

  3. Вычисляет координату x, это корректируется, поскольку это - расстояние от центра эффекта.

  4. Вычисляет значение расстояния на основе скорректированной координаты x, и это варьируется между 0 и 1. По существу это нормализует расстояние.

  5. Корректирует нормализованное значение расстояния так, чтобы был, варьируется вдоль кривой. scale значение определяет высоту кривой. Значение радиуса, используемое ранее для вычисления расстояния, определяет ширину кривой.

  6. Вычисляет вектор трансформации.

  7. Возвращает пиксель, расположенный в позиции в координатном пространстве после того, как координатное пространство будет преобразовано myTransform1 вектор.

Смотрите на модуль изображения по умолчанию в XCode для наблюдения то, что требуется для части Objective C модуля изображения. (См. Шаблон Модуля Изображения в XCode.) Вы будете видеть, что требуется метод области интереса. Вы также заметите, что обратное вычисление радиуса вычислено в outputImage метод.

Запись подпрограмм ядра для детективной линзы

В этом разделе описываются более сложное использование kernel подпрограммы. Вы будете видеть, как создать два kernel подпрограммы, которые могли стоять самостоятельно, но позже, в Создании Детективного Модуля Изображения Линзы, Вы будете видеть, как объединить их для создания фильтра, который, пользователю, будет выглядеть подобным физической увеличивающей линзе, как показано на рисунке 2-16.

Рисунок 2-16  идеальная детективная линза
The ideal detective lens

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

Проблема: почему детективная линза?

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

Это - то, где входит детективный фильтр линзы. Фильтр позволяет пользователю проверять подробные данные части изображения высокого разрешения, подобного тому, что показано на рисунке 2-17. Фильтр фактически не увеличивает исходное изображение. Вместо этого это выводит на экран субдискретизируемое изображение для пикселей, которые не являются под линзой, и выбирает пиксели от немасштабированного исходного изображения для пикселей, которые являются под линзой.

Рисунок 2-17  детективная линза, увеличивающая часть изображения с высокой разрешающей способностью
A detective lens that enlarges a portion of a high resolution image

Детективная анатомия линзы

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

  • Непрозрачность. Сравните цвета под линзой с теми вне линзы на рисунке 2-17.

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

Рисунок 2-18  параметры детективной линзы
The parameters of a detective lens

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

Рисунок 2-19  вид сбоку детективной линзы
A side view of a detective lens

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

Рисунок 2-20  сечение держателя линзы
A cross section of the lens holder

Затем Вы будете смотреть на kernel подпрограммы должны были произвести характеристики держателя линзы и линзы.

Подпрограмма ядра линзы

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

Рисунок 2-21  настроечная таблица увеличен фильтром линзы
A checkerboard pattern magnified by a lens filter

В предыдущих разделах Вы видели, как записать подпрограммы, требующие только одного sampler. kernel подпрограмма, произведшая эффект, показанный на рисунке 2-21, требует три sampler объекты для выбирающих пикселей от:

  • Изображение с высокой разрешающей способностью. Вспомните, что цель линзы состоит в том, чтобы позволить пользователю проверять подробные данные в изображении, которому это является слишком большим для адаптации на экране. Это sampler возразите выбирает пиксели для показа под линзой — часть изображения, которое будет казаться увеличенным. В зависимости от суммы увеличения, желаемого клиентом фильтра, sampler возможно, должен был бы субдискретизировать изображение высокого разрешения.

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

  • Изображение выделения. Эти выборки используются для генерации выделений в линзе для предоставления появления линзы, являющейся отражающим. Рисунок 2-22 показывает изображение выделения. Выделения являются столь тонкими, что для репродуцирования изображения для этого документа прозрачные пиксели представлены как черные. Белые пиксели непрозрачны. Выделение, показанное в числе, преувеличено так, чтобы оно могло быть замечено здесь.

Вспомните, что установка работает на sampler объекты сделаны в части Objective C модуля изображения. Посмотрите Разделение труда. Вы будете видеть, как установить CISampler объекты в Создании Детективного Модуля Изображения Линзы.

Рисунок 2-22  изображение раньше генерировал выделения линзы
An image used to generate lens highlights

Линза 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
}

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

  1. Берет три sampler объекты, четыре float значения, и два vec2 типы данных как параметры. Обратите внимание на то, что, когда Вы пишете часть Objective C фильтра, необходимо передать каждого float и vec2 значения как NSNumber объекты. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.

  2. Объявляет две переменные: dist обеспечивает промежуточное хранение для вычисления a mapdist расстояние. mapdist используется для определения, какой пиксель выбрать от выделения отображают.

  3. Объявляет вектор с двумя элементами для хранения нормализованного расстояния.

  4. Объявляет три вектора с четырьмя элементами для хранения пиксельных значений, связанных с тремя sampler источники.

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

  6. Вычисляет длину вектора различия.

  7. Нормализует вектор расстояния.

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

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

  10. Выбирает пиксель от изображения выделения путем применения преобразования на основе функции расстояния и размера выделения.

  11. Изменяет пиксель, выбранный от изображения выделения для учета непрозрачности линзы.

  12. Выбирает пиксель от изображения высокого разрешения. Вы будете видеть позже (Создающий Детективный Модуль Изображения Линзы), что увеличение применяется в части Objective C модуля изображения.

  13. Изменяет пиксель от изображения высокого разрешения скорректированным непрозрачностью пикселем выделения.

  14. Смягчает край между увеличенным (изображение высокого разрешения) и неувеличенный (субдискретизируемое изображение) пиксели.

    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-23  держатель увеличивающей линзы поместил по настроечной таблице
A magnifying lens holder placed over a checkerboard pattern.

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

Рисунок 2-24  материальное изображение карты
A material map image

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

Рисунок 2-25  держатель линзы сгенерирован от изображения шахматной доски
A lens holder generated from a checkerboard image

Держатель линзы kernel подпрограмма (см. Перечисление 2-8) берет шесть входных параметров:

  • material a sampler возразите что выборки выборок из материальной карты, показанной на рисунке 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
}

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

  1. Берет тот sampler объект, три float значения, и два vec2 типы данных как параметры. Обратите внимание на то, что, когда Вы пишете часть Objective C фильтра, необходимо передать каждого float и vec2 значение как NSNumber объекты. Иначе, фильтр не будет работать. См. Правила Подпрограммы Ядра.

  2. Вычитает вектор, представляющий центральную точку линзы от вектора, представляющего координату назначения.

  3. Вычисляет длину вектора различия.

  4. Нормализует длину.

  5. Вычисляет, является ли координата назначения на внутренней части держателя линзы.

  6. Вычисляет, является ли координата назначения на внешней части держателя линзы.

  7. Вычисляет значение формирования, зависящее от расположения координаты назначения: [-1...0] во внутренней части держателя линзы, [0...1] во внешней части держателя линзы, и 0 иначе.

  8. Изменяет нормализованное расстояние для учета сопряжения держателя линзы. Это значение сформирует держателя линзы.

  9. Вычисляет альфа-значение для пикселя в координате назначения. Если расположение далеко от внутреннего радиуса, альфа-значение фиксируется к 0.0. Точно так же, если расположение промахивается по внешнему радиусу, результат фиксируется к 0.0. Альфа-значения в держателе линзы фиксируются к 1.0. Пиксели не на держателе линзы прозрачны.

  10. Изменяет v0 вектор шириной и высотой материальной карты. Тогда масштабирует вектор для учета размера материальной карты.

  11. Выбирает пиксель из материальной карты путем применения v0 вектор как преобразование.

  12. Применяет альфу к пикселю до возврата его.

Решение проблемы ядра

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 подпрограммы описаны в этой главе.