Выполнение операций свертки

Свертка является общим методом обработки изображений, изменяющим интенсивность пикселя для отражения интенсивности окружающих пикселей. Общее использование свертки должно создать фильтры изображения. Используя свертку, можно получить популярные эффекты изображений как размытость, увеличить резкость, и граничное обнаружение — эффекты, используемые приложениями, такими как Фотоавтомат, iPhoto и Апертура.

Если Вы будете интересоваться эффективным применением фильтров изображения к большим или данным изображения в реальном времени, то Вы сочтете функции vImage полезными. С точки зрения фильтрации изображения операции свертки vImage могут выполнить общие эффекты фильтра изображения, такие как придание рельефности, размывание, и, постеризация.

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

В этой главе описываются свертку и показывает, как использовать функции свертки, предоставленные vImage. Путем чтения этой главы Вы будете:

Ядра свертки

Рисунок 2-1 показывает изображение прежде и после обработки с vImage функцией свертки, вызывающей рельефный эффект. Для достижения этого эффекта vImage выполняет свертку с помощью подобной сетке математической конструкции, названной ядром.

Рисунок 2-1  Рельефная свертка использования

Рисунок 2-2 представляет 3 x 3 ядра. Высота и ширина ядра не должны быть тем же, хотя они должны оба быть нечетными числами. Числа в ядре - то, что влияет на полный эффект свертки (в этом случае, ядро кодирует рельефный эффект). Ядро (или более в частности, значения, сохраненные в ядре), - то, что определяет, как преобразовать пиксели от исходного изображения в пиксели обработанного изображения. Может казаться неинтуитивным, как эти девять чисел в этом ядре могут привести к эффекту, такому как предыдущий рельефный пример. Свертка является серией операций, изменяющих интенсивности пикселей в зависимости от интенсивности соседних пикселей. vImage обрабатывает все операции свертки на основе ядра, которое Вы предоставляете. Ядро обеспечивает фактические числа, использующиеся в тех операциях (см. рисунок 2-4 для шагов, вовлеченных в свертку). Используя ядра для выполнения сверток известен как свертка ядра.

  Ядро рисунка 2-2 3 x 3

Свертки являются операциями на пиксель — та же арифметика повторяется для каждого пикселя в изображении. Большие изображения поэтому требуют большего количества арифметики свертки, чем та же работа на меньшем изображении. Ядро может считаться двумерной сеткой чисел, передающей по каждому пикселю изображения в последовательности, выполняя вычисления по пути. Так как изображения могут также считаться двумерными сетками чисел (или интенсивности пикселей — видят рисунок 2-3), применение ядра к изображению может визуализироваться как маленькая сетка (ядро) преодолевание существенно большей сетки (изображение).

Рисунок 2-3  изображение является сеткой чисел

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

  Свертка Ядра рисунка 2-4

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

Тип данных, используемый для представления значений в ядре, должен соответствовать, данные раньше представляли пиксельные значения в изображении. Например, если пиксельный тип float, тогда значения в ядре должны также быть float значения.

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

Развертка

Развертка является работой, приблизительно отменяющей предыдущую свертку — обычно свертка, которая является физической в источнике, такой как дифракционные эффекты в линзе. Обычно, развертка является работой увеличения резкости.

Существует много алгоритмов развертки; одно использование vImage вызывают разверткой Ричардсона-Люси.

Цель развертки Ричардсона-Люси состоит в том, чтобы счесть исходное значение пикселя данным интенсивность пикселей постсвертки и число, на которое это было умножено (значение ядра).

Вследствие этих требований, для использования развертки vImage функционирует, необходимо обеспечить скрученное изображение, и ядро раньше выполняло исходную свертку. Представленный как k в следующем уравнении ядро служит способом сообщить vImage, какую свертку это должно отменить. Например, увеличение резкости изображения (общее использование развертки) может считаться выполнением противоположности свертки размытости. Если ядро, которое Вы предоставляете, не симметрично, необходимо передать второе ядро функции, совпадающей с первым с осями, которыми обмениваются.

Развертка Ричардсона-Люси является итеративной работой; Ваше приложение указывает число желаемых итераций. Чем больше итераций Вы делаете, тем больше эффект увеличения резкости (и время использованный). Как с любой работой увеличения резкости, Ричардсон-Люси усиливает шум, и в некотором числе итераций шум становится примечательным как артефакты. Рисунок 2-5 показывает алгоритм Ричардсона-Люси, выраженный математически.

Рисунок 2-5  уравнение развертки Ричардсона-Люси

В этом уравнении:

Как со сверткой, vImage обрабатывает все отдельные шаги развертки, таким образом не необходимо запомнить включенные шаги. Когда deconvolving, все, что необходимо обеспечить, является исходным ядром свертки (плюс дополнительное инвертированное ядро свертки, если исходное ядро не симметрично).

Используя ядра свертки

Теперь, когда Вы лучше понимаете структуру ядер и процесса позади свертки, пора фактически использовать несколько vImage функций свертки. Этот раздел показывает Вам, как выполнить рельефное, показанное на рисунке 2-1, и также объясняет различия между скручиванием с и беспристрастно.

Скручивание

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

Перечисление 2-1  , Производящее рельефный эффект

int myEmboss(void *inData,
 unsigned int inRowBytes,
 void *outData,
 unsigned int outRowBytes,
 unsigned int height,
 unsigned int width,
 void *kernel,
 unsigned int kernel_height,
 unsigned int kernel_width,
 int divisor ,
 vImage_Flags flags )
{
    uint_8 kernel = {-2, -2, 0, -2, 6, 0, 0, 0, 0}; // 1
    vImage_Buffer src = { inData, height, width, inRowBytes }; // 2
    vImage_Buffer dest = { outData, height, width, outRowBytes }; // 3
    unsigned char bgColor[4] = { 0, 0, 0, 0 }; // 4
    vImage_Error err; // 5
 
 
    err = vImageConvolve_ARGB8888(    &src,     //const vImage_Buffer *src
                                        &dest,    //const vImage_Buffer *dest,
                                        NULL,
                                        0,    //unsigned int srcOffsetToROI_X,
                                        0,    //unsigned int srcOffsetToROI_Y,
                                        kernel,    //const signed int *kernel,
                                        kernel_height,     //unsigned int
                                        kernel_width,    //unsigned int
                                        divisor,    //int
                                        bgColor,
                                       flags | kvImageBackgroundColorFill
                                       //vImage_Flags flags
                                    );
 
 
    return err;
}

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

  1. Объявляет рельефное ядро как int массив. Тип данных значений ядра должен соответствовать намеченный тип данных соответствующей функции vImage. Поскольку пример кода вызывает vImageConvolve_ARGB8888, значения ядра должны быть 8-разрядными целыми числами без знака (uint_8). vImage ожидает, что элементы ядра будут в массиве в слева направо, 1-я строка, 2-я строка, 3-й порядок строк (см. рисунок 2-2, чтобы видеть, как это упорядочило).

  2. Объявляет vImage_Buffer структура данных для получения информации об исходном изображении. Данные изображения являются хранилищем как массивом байтов (inData). Другие элементы хранят высоту, ширину и байты на строку изображения. Эти данные позволяют vImage знать, насколько большой массив данных изображения, и как должным образом обработать его.

  3. Объявляет a vImage_Buffer структура данных для получения информации о конечном изображении, как сделано ранее с исходным изображением.

  4. Объявляет a Pixel8888- отформатированный пиксель для представления цвета фона для конечного изображения (черный в этом случае).

  5. Объявляет a vImage_Err тип данных для хранения возвращаемого значения функции свертки.

После этого код отправляет заявленные значения как параметры к vImageConvolve_ARGB8888 функционируйте, где vImage обрабатывает обработку и хранит результат в dest. vImageConvolve_ARGB8888 функция является только одной из нескольких функций свертки, доступных в vImage. vImage, обычно предлагает четыре варианта той же функции — каждый для различного формата изображения. ARGB8888 суффикс сообщает, что эта функция предназначается для чередованных (полноцветных) изображений, где каждый пиксель является группировкой четырех 8-байтовых целых чисел, представляющих альфу (A), красный (R), зеленый (G), и синий (B) каналы. Для получения дополнительной информации на форматах изображения vImage использование, обратитесь к Форматам изображения, Доступным в vImage.

Для vImage для подтверждения надлежащих флагов, выборки myEmboss функция принимает a vImage_Flags параметр. Этот параметр представляет составной объект одного или более флагов что вызывающая сторона myEmboss представленный. Когда пример тогда вызывает vImage vImageConvolve_ARGB8888 функция, это передает те те же флаги, но на сей раз объединенный с дополнительным определенным постоянным флагом, kvImageBackgroundColorFill. Это делает это при помощи побитового оператора OR (|) объединить несколько флагов в единственный состав флагов, которые могут быть представлены с одной переменной. Это - стандартный способ сигнализировать флаги к vImage. Этот пример кода запрашивает, чтобы vImage использовали предоставленный цвет фонового изображения (вместе с тем, какой бы ни флаги были первоначально переданы функции).

Чтобы познакомиться с эффектами ядра, попытайтесь использовать значения от следующих двух ядер в Вашем собственном коде. Рисунок 2-6 показывает ядро для создания Гауссовой размытости, и рисунок 2-7 показывает фильтр Prewitt, который является ядром для граничного обнаружения.

Рисунок 2-6  ядро для Гауссова
blurFigure 2-7
  ядро для граничного обнаружения

Скручивание со смещением

vImage дает Вам опцию выполнить свертку со смещением или без. Смещение является значением, которое можно добавить к каждому элементу в результате свертки добавить дополнительное влияние от соседних пикселей. С тех пор с определенными свертками возможно получить отрицательные числа (которые не являются представимыми в формате 0–255), смещение препятствует сигналу сместиться из диапазона. Можно принять решение добавить смещение 127 или 128, чтобы позволить некоторым отрицательным числам быть представимыми (с неявным +127 или +128 в их значении). Полный эффект смещения украшает или затемняет изображение.

Поскольку каждая стандартная свертка функционирует в vImage (такой как vImageConvolve_PlanarF), существует соответствующая версия, использующая смещение, обозначенное “WithBias” на имя функции (vImageConvolveWithBias_PlanarF, например). Используя смещенные функции фактически идентично не смещенным функциям, за исключением дополнительного bias параметр необходимо передать функциям свертки то смещение использования. Тип данных для bias параметр должен соответствовать параметр пиксельных данных в изображении. См. vImage Ссылку Свертки для подробных данных об использовании этих функций.

  Смещение рисунка 2-8 по сравнению ни с каким смещением

Используя высокоскоростные фильтры

vImage также предлагает функции для определенных типов свертки, которая может быть значительно быстрее, чем общая свертка. Запускаясь в OS X v.10.4, у Вас есть опция использовать предоставленное поле и функции фильтра палатки для целочисленных форматов Planar_8 и ARGB8888. Эти фильтры выполняют операции размытости. Имена функций от их формы, когда изображено в виде графика в декартовой системе координат. Они эквивалентны скручиванию с определенными простыми ядрами, но Вы не должны предоставлять ядро. Эти функции могут быть порядками величины быстрее, чем выполнение эквивалентной свертки с помощью пользовательских ядер.

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

  Фильтр Поля рисунка 2-9

Вы используете фильтры палатки для размывания каждого пикселя изображения со взвешенным средним его окружающих пикселей. Функции палатки, доступные в vImage, vImageTentConvolve_Planar8 и vImageTentConvolve_ARGB8888. Эти операции размытости эквивалентны применению ядра свертки, заполненного значениями, уменьшающимися с расстоянием от центра. Как с vImageBoxConvolve_Planar8 и vImageBoxConvolve_ARGB8888, Вы не должны передавать ядро функции — просто высота и ширина. В частности, для M x N размер ядра, ядро было бы продуктом M x матрица на 1 столбец и 1 x N матрица строки. Каждый имел бы 1 как первый элемент, затем оценивает увеличение 1 до среднего элемента, затем уменьшающегося на 1 к последнему элементу.

  Фильтр Палатки рисунка 2-10

Например, предположите, что размер ядра является 3 x 5. Тогда первая матрица

../Art/vimage_matrix11.gif

и второе

../Art/vimage_matrix12.gif

Продукт

../Art/vimage_matrix13.gif

3 x 5 работ фильтра палатки эквивалентны свертке с вышеупомянутой матрицей.

Используя многократные ядра

vImage позволяет Вам применять многократные ядра в единственной свертке. vImageConvolveMultiKernel функции допускают Вас для указания четырех отдельных ядер — один для каждого канала в изображении. Это допускает больший уровень управления при применении фильтров к изображению, так как можно воздействовать на красные, зеленые, синие, и альфа-каналы индивидуально. Например, можно использовать свертки мультиядра для передискретизации цветовых каналов изображения по-другому для компенсации расположение фосфора RGB на экране. Так как каждое из этих четырех ядер может воздействовать на единственный канал, vImageConvolveMultiKernel функции доступны только для чередованных форматов изображения.

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

Deconvolving

Как с операциями позади свертки, vImage заботится о выполнении ранее упомянутого алгоритма Ричардсона-Люси для Вас. Ваше задание должно обеспечить ядро (называемый функцией рассеяния точки) начальной свертки. Перечисление 2-2 показывает как deconvole рельефный эффект. Вы могли использовать тот же код для deconvolve различных эффектов, таких как размывание, путем указания надлежащего ядра. Обратите внимание на то, что в отличие от операций свертки, существует дополнительный параметр ядра. Этот параметр может быть NULL если высота и ширина ядра не являются тем же размером. Если высота ядра и ширина неравны, необходимо предоставить идентичное ядро, но с его строками и инвертированными столбцами.

Перечисление 2-2 является примером того, как использовать vImage для deconvolve ARGB8888- отформатированное изображение.

Перечисление 2-2  Deconvolving рельефное изображение

int myDeconvolve(void *inData,
 unsigned int inRowBytes,
 void *outData,
 unsigned int outRowBytes,
 unsigned int height,
 unsigned int width,
 void *kernel,
 unsigned int kernel_height,
 unsigned int kernel_width,
 int divisor,
 int iterationCount,
 vImage_Flags flags )
{
    //Prepare data structures
    uint_8 kernel = {-2, -2, 0, -2, 6, 0, 0, 0, 0}; // 1
    vImage_Error err; // 2
    unsigned char bgColor[4] = { 0, 0, 0, 0 }; // 3
    vImage_Buffer src = { inData, height, width, inRowBytes }; // 4
    vImage_Buffer dest = { outData, height, width, outRowBytes }; // 5
 
 
 
    //Send data to vImage for processing
 
    err = vImageRichardsonLucyDeConvolve_ARGB8888(    &src,     // 6
                                        &dest,    //const vImage_Buffer *dest,
                                        NULL,
                                        0,    //unsigned int srcOffsetToROI_X,
                                        0,    //unsigned int srcOffsetToROI_Y,
                                        kernel,    //const signed int *kernel,
                                        NULL, //assumes symmetric kernel
                                        kernel_height,     //unsigned int kernel_height,
                                        kernel_width,    //unsigned int kernel_width,
                                        0, //height of second kernel
                                        0, //width of second kernel
                                        divisor,    //int
                                        0, //for second kernel
                                        bgColor,
                                        iterationCount, //uint32_t
                                        kvImageBackgroundColorFill | flags
                                        //vImage_Flags
                                    );
 
 
    //Report result
    return err; // 7
}

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

  1. Указывает ядро, используемое в исходной свертке, что vImage должен deconvolve. Пример использует симметричное ядро (и высота и ширина, 3), и поэтому не необходимо предоставить второе ядро к vImage.

  2. Объявляет vImage_Error структура для получения результата функции развертки.

  3. Объявляет a Pixel8888- отформатированный пиксель для представления цвета фона для конечного изображения (черный в этом случае).

  4. Объявляет a vImage_Buffer структура данных для получения информации об исходном изображении. Данные изображения получены как массив байтов (inData). Другие элементы хранят высоту, ширину и байты на строку изображения. Эти данные позволяют vImage знать, насколько большой массив данных изображения, и как должным образом обработать его.

  5. Объявляет a vImage_Buffer структура данных для получения информации о конечном изображении, как сделано ранее с исходным изображением.

  6. Предоставляет ранее заявленные структуры данных к vImage для обработки. Отметьте, как пример предоставляет vImageRichardsonDeConvolve_ARGB8888 функция с a NULL параметр для второго ядра. Это вызвано тем, что первое ядро симметрично, и поэтому инвертированное ядро не необходимо.

  7. Возвращает то же vImage_Error структура данных возвратилась из развертки.

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