Расчет направления градиента - PullRequest
3 голосов
/ 23 октября 2010

Я работаю над своей задачей в курсе компьютерного зрения.Одной из подзадач является вычисление направления градиента на основе яркости изображения.Я сделал матрицу bright [width] [height], содержащую значения яркости для каждого пикселя изображения.И у меня есть две такие функции:

double Image::grad_x(int x,int y){
    if(x==width-1 || x==0) return bright[x][y];
    return bright[x+1][y]-bright[x-1][y];
}
double Image::grad_y(int x,int y){
    if(y==height-1 || y==0) return bright[x][y];
    return bright[x][y+1]-bright[x][y-1];
}

РЕДАКТИРОВАТЬ: проверка границы исправлена ​​

Я работаю с простой производной, без использования оператора Собеля, потому что простой производной достаточно для моих нужд.

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

Ответы [ 4 ]

1 голос
/ 23 октября 2010

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

Угловые случаи - это проблема, потому что у вас недостаточно данных для вычисления градиента втак же, как и другие пиксели.Один из способов справиться с ними - просто не вычислять угловые случаи и жить с немного меньшим изображением.

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

В ваших вычислениях x-градиента вы, возможно, рассчитали производную A для пикселя 1 и B для пикселя 2. Если вы хотите экстраполировать значение для пикселя0 (угловой регистр) можно использовать значение a- (ba).

Числовой пример:

  pixel1: gradient = 100
  pixel2: gradient = 80

  extrapolate using a-(b-a): 

  pixel0: gradient = 100 - (80-100)) = 120
1 голос
/ 23 октября 2010

Итак, с одной стороны, вы хотите сохранить простоту, с другой стороны, вы хотите, чтобы ваша программа работала хорошо.Ага.

На самом деле я делаю что-то подобное, хотя меня не волнует граница.Мне нравится основывать коэффициенты на кубических B-сплайнах.Если вы свернете свой дискретный 2D-сигнал с помощью 2D-кубического B-сплайна, вы получите очень плавную и дважды непрерывно дифференцируемую функцию.Можно вычислить точные интенсивности и производные этой функции в произвольных точках.Поскольку кубический B-сплайн не является интерполятором, результат будет немного сглажен по сравнению с оригиналом.Но это не проблема для многих приложений.Фактически, это имеет тенденцию улучшать вещи (подавляя шум до некоторой степени) во многих ситуациях.Если вам не нужен этот эффект сглаживания, вы можете обойти его (см. Мою ссылку ниже).

В одном измерении реконструкция с использованием кубического B-сплайна в качестве фильтра реконструкции с последующей повторной выборкой сигнала эквивалентнадля свертки сигнала с

1/6 4/6 1/6

Производная точная этого равна:

1/2 0 -1/2

И точная вторая производная равна:

1 -2 1

Эти коэффициенты следуют из кубической кривой B-сплайна и ее производных.В 2D вы можете комбинировать это произвольно.Один фильтр для направления x и один фильтр для направления y.Примеры:

"B-Spline reconstruction" (divisor=36)
   1  4  1
   4 16  4
   1  4  1

"B-Spline differentiator in X" (divisor=12)
   1  0 -1
   4  0 -4
   1  0 -1

"B-Spline, 2nd derivative in X, 1st derivative in Y" (divisor=2)
   1 -2  1
   0  0  0
  -1  2 -1

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

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

Если вы заботитесь о границе, вам нужно каким-то образом выбрать экстраполяцию, соответствующую вашим потребностям.Я обычно просто повторяю значения пикселей последних пикселей.Это хорошо работает для моих приложений *.

0 голосов
/ 23 октября 2010

Утилита:

OpenCV с использованным вами ядром свертки ([1 0 -1]).

Границы пикселей:

Зависит от приложения.Вот несколько хороших способов дополнить ваше изображение .

0 голосов
/ 23 октября 2010

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

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

Почему бы не взять только ядро ​​Собеля? Это быстрое и не более трудоемкое кодирование?

Редактировать: вы не проверяете границы в x-направлении. grad_x (0, 0) приведет к исключению времени выполнения.

...