В последнее время я занимаюсь обработкой изображений, и мне хотелось бы знать, как работает алгоритм нерезкой маски. Я смотрю на исходный код для Gimp и его реализацию, но до сих пор я все еще в неведении о том, как это работает. Мне нужно реализовать его для проекта, над которым я работаю, но я бы хотел понять алгоритм, который я использую.
Как работает нерезкая маска?
Ответ 1
Я не знал, как это работает, но натолкнулся на пару действительно хороших страниц, чтобы понять это. В основном это происходит следующим образом:
- Что противоположно заточенному изображению? Расплывчатый. Мы знаем, как размыть изображение. Дублируйте исходное изображение и выполните гауссовское размытие. Это ползунок Radius в большинстве диалогов USM.
- Хорошо, если мы вычитаем размытость, нам следует оставить детали, которые являются высококонтрастными! Подумайте об этом: если вы размываете небо, оно по-прежнему выглядит как небо. Вычтите пиксели, и вы получите sky-sky = 0. Если вы размываете логотип Coke, вы получаете размытый логотип Coke. Вычтите его, и вы останетесь с краями. Так что разница
- Что заставляет вещи выглядеть острее? Контраст. Дублируйте исходное изображение снова и увеличивайте контрастность. Сумма, на которую вы увеличиваете контраст, - это ползунок "Сумма" или "Интенсивность" в большинстве диалогов USM.
-
Наконец, все вместе. На данный момент у вас есть три вещи:
- Высококонтрастная версия исходного изображения.
- Разница размытого изображения и вашего оригинала (этот слой в основном черный). Этот слой является нерезкой маской
- Оригинальный
Алгоритм выглядит следующим образом: Посмотрите на пиксель от нерезкой маски и узнайте его яркость (яркость). Если яркость 100%, используйте значение из высококонтрастного изображения для этого пикселя. Если это 0%, используйте значение из исходного изображения для этого пикселя. Если он где-то посередине, смешайте значения двух пикселей, используя некоторый вес. При желании измените только значение пикселя, если оно изменится более чем на определенную величину (это ползунок Threshold в большинстве диалогов 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;
}
Примечание. Я не специалист по графике, но это то, что я смог изучить на страницах, которые я нашел. Прочитайте их самостоятельно и убедитесь, что вы согласны с моими выводами, но выполнение вышеописанного должно быть достаточно простым, так что сделайте снимок!
Ссылки
Ответ 2
Ключом является идея пространственной частоты. Гауссовский фильтр пропускает только низкие пространственные частоты, поэтому, если вы сделаете что-то вроде:
2 * (исходное изображение) - (гауссовское отфильтрованное изображение)
Тогда эффект в пространственной частотной области:
(2 * все частоты) - (низкие частоты) = (2 * высокие частоты) + (1 * низкие частоты).
Таким образом, по сути, "нерезкая маска", повышает высокочастотные компоненты изображения - точные параметры гауссовского размера фильтра и веса при вычитании изображений определяют точные свойства фильтра.
Ответ 3
Unsharp Mask работает, создавая размытую версию изображения с использованием фильтра размытия Gaussian, а затем вычитая это из исходного изображения (с некоторым примененным весовым значением), то есть
blurred_image = blur(input_image)
output_image = input_image - blurred_image * weight
Ответ 4
Unsharp обычно реализуется как ядро свертки, которое обнаруживает ребра. Результат этой свертки добавляется обратно к исходному изображению, чтобы увеличить краевой контраст, который добавляет иллюзию дополнительной "резкости".
Точное используемое ядро варьируется от человека к человеку и приложения-приложения. Большинство из них имеют общий формат:
-1 -1 -1
g = -1 8 -1
-1 -1 -1
Некоторые оставляют диагонали, иногда вы получаете более высокие весы, и все ядро масштабируется, а некоторые просто пробовали разные веса. Все они имеют тот же эффект, что и в конце, это просто вопрос игры, пока вы не найдете тот, который вам нравится в конечном результате.
Учитывая входное изображение I
, выход определяется как:
out = I + c(I * g)
, где *
- оператор двумерной свертки, а c
- некоторая константа масштабирования, обычно выше 0.5
и меньше 1
, поэтому вы избегаете выдувать больше каналов, чем вам нужно.
Ответ 5
Рассмотрим приведенный ниже код, который принимает во входном изображении IMG.
IMGblur = blur(IMG) // get all the low frequency pixels
temp = IMG - IMGblur // all the low frequency pixels will be 0
IMGsharp = IMG + k(temp) // k is in [0.3,0.7]
// in this final result , all low frequency pixels of IMGsharp is same as IMG,
// but all high frequency signals of IMGsharp is (1+k)times higher than IMG
Надеюсь, это поможет!
Вскоре Chee Loong,
Университет Торонто