2016-05-30 2 views
1

Если я применить Собел фильтр к изображению в Python с использованием scipy.ndimage.filters.convole я получаю значимые результаты, например, для этого простого входного изображения imgПрименение ядра с OpenCV в C++

0 255 0 
0 255 0 
0 255 0 

свертка

dimage.filters.convolve(img, Kx) 

с Kx

-1 0 1 
-2 0 2 
-1 0 1 

возвращает MEA ningful градиент в направлении х:

-1020 0 1020 
-1020 0 1020 
-1020 0 1020 

Я не знаю, как получить эквивалентный результат с помощью openCV2 в C++, хотя. Когда я определить входное изображение

int image_data[9] = {0, 255, 0, 0, 255, 0, 0, 255, 0}; 
cv::Mat image = cv::Mat(3, 3, CV_32F, image_data); 

и применить ядро ​​на

cv::Mat gradientx; 
double sobelx_data[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; 
cv::Mat sobelx = cv::Mat(3, 3, CV_32F, sobelx_data); 
cv::filter2D(image, gradientx, -1, sobelx); 

я получаю следующий результат

for(int row=0; row<gradientx.rows; row++) { 
    for(int col=0; col<gradientx.cols; col++) { 
    std::cout << gradientx.at<int>(row,col) << std::endl; 
    } 
} 

возвращает следующее изображение

478 -2147482660 478 
478 -2147482660 478 
478 -2147482660 478 

Кажется, что есть n проблема переполнения, но я не знаю почему. Попытка получить значения из gradientx.at<double>(row,col) производит

-1.68911e-311 8.10602e-312 8.11663e-312 
-1.68911e-311 8.10602e-312 8.11663e-312 
-1.68911e-311 2.122e-314 8.54412e-72 

Может кто-нибудь сказать мне, почему это? Разве не filter2D должен сделать 2D-свертку на изображении, и почему я получаю странные значения при обращении к выходным пикселям с <double>? Спасибо.

+0

'CV_32F' является' float'. – beaker

+0

@beaker Спасибо, я поменял его на float .. Положите, теперь он печатает мне нулевую матрицу ... – TheWaveLad

+0

Теперь похоже, что у вас проблемы с типом границы. Я отправлю ответ за секунду. – beaker

ответ

4

Итак, вот ваш код с типами исправленных (я также добавил несколько параметров filter2D):

float image_data[9] = {0, 255, 0, 0, 255, 0, 0, 255, 0}; 
cv::Mat image = cv::Mat(3, 3, CV_32F, image_data); 
std::cout << "image = " << std::endl << image << std::endl; 

cv::Mat gradientx; 
float sobelx_data[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; 
cv::Mat sobelx = cv::Mat(3, 3, CV_32F, sobelx_data); 
std::cout << "sobelx = " << std::endl << sobelx << std::endl; 

cv::filter2D(image, gradientx, -1, sobelx, cv::Point(-1, -1), 0, 
      cv::BORDER_DEFAULT); 
std::cout << "gradientx = " << std::endl << gradientx << std::endl; 

Результат:

image = 
[0, 255, 0; 
0, 255, 0; 
0, 255, 0] 
sobelx = 
[-1, 0, 1; 
-2, 0, 2; 
-1, 0, 1] 
gradientx = 
[0, 0, 0; 
0, 0, 0; 
0, 0, 0] 

Если вы посмотрите на вершине на странице документации по адресу filtering вы увидите все типы границ, которые использует OpenCV. По умолчанию filter2D использует BORDER_REFLECT_101. Это, вероятно, не то, что мы хотим, поэтому давайте изменим его на BORDER_REPLICATE.

cv::filter2D(image, gradientx, -1, sobelx, cv::Point(-1, -1), 0, 
      cv::BORDER_REPLICATE); 

Результат:

image = 
[0, 255, 0; 
0, 255, 0; 
0, 255, 0] 
sobelx = 
[-1, 0, 1; 
-2, 0, 2; 
-1, 0, 1] 
gradientx = 
[1020, 0, -1020; 
1020, 0, -1020; 
1020, 0, -1020] 

Это лучше, но ценности перевернуты. Если вы посмотрите на нижнюю часть описания функции для filter2D, вы увидите, что она фактически вычисляет кросс-корреляцию, а не свертку. Поэтому нам нужно перевернуть ядро, чтобы получить правильные результаты.

cv::Mat sobelxflip; 
cv::flip(sobelx, sobelxflip, -1); 

cv::filter2D(image, gradientx, -1, sobelxflip, cv::Point(-1, -1), 0, 
      cv::BORDER_REPLICATE); 
std::cout << "gradientx = " << std::endl << gradientx << std::endl; 

Результат:

gradientx = 
[-1020, 0, 1020; 
-1020, 0, 1020; 
-1020, 0, 1020] 
Смежные вопросы