Я играл вокруг с обработкой изображений в последнее время, и я хотел бы знать, как алгоритм нерезкой маски работает. Я смотрю на исходный код для Калеки, и это - реализация, но до сих пор я все еще в неведении относительно того, как это на самом деле работает. Я должен реализовать его для проекта, я продолжаю работать, но я хотел бы на самом деле понять алгоритм, который я использую.
Я тоже не знал, как это работает, но наткнулся на пару действительно хороших страниц, чтобы понять это. Обычно это выглядит так:
Наконец собрал все воедино. На данный момент у вас есть три вещи:
Алгоритм выглядит следующим образом: посмотрите на пиксель из маски нерезкости и узнайте его яркость (яркость). Если яркость равна 100%, используйте значение из высококонтрастного изображения для этого пикселя. Если это 0%, используйте значение из исходного изображения для этого пикселя. Если это где-то посередине, смешайте значения двух пикселей, используя некоторое взвешивание. При желании можно изменять значение пикселя, только если оно изменяется более чем на определенную величину (это ползунок Порог в большинстве диалогов USM).
Сложите все вместе, и вы получите свой образ!
Вот какой-то псевдокод:
color[][] usm(color[][] original, int radius, int amountPercent, int threshold) {
// copy original for our return value
color[][] retval = copy(original);
// create the blurred copy
color[][] blurred = gaussianBlur(original, radius);
// subtract blurred from original, pixel-by-pixel to make unsharp mask
color[][] unsharpMask = difference(original, blurred);
color[][] highContrast = increaseContrast(original, amountPercent);
// assuming row-major ordering
for(int row = 0; row < original.length; row++) {
for(int col = 0; col < original[row].length; col++) {
color origColor = original[row][col];
color contrastColor = highContrast[row][col];
color difference = contrastColor - origColor;
float percent = luminanceAsPercent(unsharpMask[row][col]);
color delta = difference * percent;
if(abs(delta) > threshold)
retval[row][col] += delta;
}
}
return retval;
}
Примечание : Я не специалист по графике, но это то, что я смог узнать из найденных мной страниц. Прочтите их сами и убедитесь, что вы согласны с моими выводами, но реализация вышеизложенного должна быть достаточно простой, так что попробуйте!
Нерезкость обычно реализуется как ядро свертки, которое обнаруживает края. Результат этой свертки добавляется обратно к исходному изображению для увеличения контрастности краев, что добавляет иллюзию дополнительной «резкости».
Точное используемое ядро сильно различается от человека к человеку и от приложения к приложению. Большинство из них имеют такой общий формат:
-1 -1 -1
g = -1 8 -1
-1 -1 -1
Некоторые не учитывают диагонали, иногда вы получаете больший вес и масштабируется все ядро, а некоторые просто пробуют другие веса. В конце концов, все они имеют одинаковый эффект, это просто вопрос игры, пока вы не найдете тот, который вам нравится в конечном результате.
Для входного изображения I
выход определяется как:
out = I + c (I * g)
, где *
- оператор двумерной свертки, а c
- некоторая константа масштабирования, обычно выше 0,5
и меньше 1
, поэтому вы не перегружаете больше каналов, чем необходимо.
Unsharp Mask работает путем создания размытой версии изображения с помощью фильтра размытия Гаусса, а затем вычитания ее из исходного изображения (с применением некоторого значения веса), т. е.
blurred_image = blur(input_image)
output_image = input_image - blurred_image * weight
Ключевым является идея пространственной частоты . Гауссовский фильтр пропускает только низкие пространственные частоты, поэтому, если вы сделаете что-то вроде:
2 * (исходное изображение) - (гауссово фильтрованное изображение)
, то его эффект в области пространственных частот будет следующим:
(2 * все частоты) - (низкие частоты) = (2 * высокие частоты) + (1 * низкие частоты).
Таким образом, по сути, «маска нерезкости» усиливает высокочастотные компоненты изображения - точные параметры размера гауссовского фильтра и веса при вычитании изображений определяют точные свойства фильтра. .