Как работает нерезкая маска?

В последнее время я занимаюсь обработкой изображений, и мне хотелось бы знать, как работает алгоритм нерезкой маски. Я смотрю на исходный код для 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,

Университет Торонто