2013-07-31 4 views
2

Я пытаюсь перенести некоторый код из Matlab в Opencv и вам нужна точная копия функции градиента. Я пробовал функцию cv :: Sobel, но по какой-то причине значения в полученном cv :: Mat не совпадают с значениями в версии Matlab. Для дальнейших вычислений мне нужен градиент X и Y в отдельных матрицах.Градиентный эквивалент Matlab в opencv

Любое решение, которое может достичь этого было бы здорово

+0

'резюме :: Собел()' это именно то, что вы хотите. Если вы публикуете код, который вы использовали (и что вы ожидаете от него), мы можем посмотреть и посмотреть, что ваша проблема. – Aurelius

ответ

0

Вы должны вызвать Собела 2 раза, с аргументами:

xorder = 1, yorder = 0 

и

xorder = 0, yorder = 1 

Вы должны выбрать соответствующее ядро размер.

См documentation

Это еще может быть, что реализация MatLab была другой, в идеале вы должны получить какое ядро ​​там было использовано ...

Edit:

Если вам нужно указать ваше собственное ядро, вы можете использовать более общий filter2D. Глубина назначения будет CV_16S (16 бит).

+0

Я до сих пор не знаю, что использовать borderType, который даст похожие результаты. Более подробное объяснение того, что действительно поможет –

+0

Я ищу матричный точный результат после градиента Matlab и cv :: Sobel. –

+0

@ArpanShah Ясно, что тип границы влияет только на пиксель на границе ИЗОБРАЖЕНИЯ (так, первая строка, первая колонка, последняя строка, последний столбец, если у вас есть размер ядра 3, в противном случае первые 2 строки, первые 2 столбца и т. Д. если у вас размер ядра 5 и т. д.). Что-то отличное от значения по умолчанию используется только тогда, когда область для вас вычисляет Sobel - это не весь образ, а что-то внутри него, где информация за пределами области все еще имеет смысл – Antonio

0

Matlab вычисляет градиент по-разному для внутренних рядов и рядов границ (то же самое верно для столбцов, конечно). На границах это простая передовая разница gradY(1) = row(2) - row(1). Градиент для внутренних рядов вычисляется по центральной разности gradY(2) = (row(3) - row(1))/2.

Я думаю, что вы не можете добиться того же результата, просто запустив единственный фильтр свертки по всей матрице в OpenCV. Используйте cv::Sobel() с ksize = 1, затем обработайте границы (вручную или с помощью фильтра [1 -1]).

6

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

(е (я + 1, к) + е (я-1, J) - 2е (I, J))/2

Что мы хотим

(е (я + I, J) -f (я-1, J))/2

Таким образом, мы должны применить

Mat kernelx = (Mat_<float>(1,3)<<-0.5, 0, 0.5); 
Mat kernely = (Mat_<float>(3,1)<<-0.5, 0, 0.5); 
filter2D(src, fx, -1, kernelx) 
filter2D(src, fy, -1, kernely); 

Matlab обрабатывает пиксели границы в отличие от внутренних пикселей. Таким образом, приведенный выше код не соответствует значениям границы. Можно использовать BORDER_CONSTANT для выравнивания значения границы с постоянным числом, к сожалению, постоянное число равно -1 по OpenCV и не может быть изменено на 0 (это то, что мы хотим).

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

+1

О, на самом деле, вы можете использовать copyMakeBorder() для расширения границы Mat с определенным постоянным значением. –

0

Ответ Pei отчасти правильный.Matlab использует эти расчеты для границ:

G (:, 1) = A (:, 1) = A (:, 1); G (:, N) = A (:, N) - A (:, N-1);

так использовал следующий код OpenCV для завершения градиента:

static cv::Mat kernelx = (cv::Mat_<double>(1, 3) << -0.5, 0, 0.5); 
static cv::Mat kernely = (cv::Mat_<double>(3, 1) << -0.5, 0, 0.5); 
cv::Mat fx, fy; 

cv::filter2D(Image, fx, -1, kernelx, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE); 
cv::filter2D(Image, fy, -1, kernely, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE); 

fx.col(fx.cols - 1) *= 2; 
fx.col(0) *= 2; 
fy.row(fy.rows - 1) *= 2; 
fy.row(0) *= 2; 
Смежные вопросы