2017-02-04 9 views
0

Оператор opencv Sobel вычисляет корреляцию, а не свертку? Я знаю, что функция filter2D вычисляет корреляцию, и я только что узнал (исходя из результатов кода), что оператор Sobel также вычисляет корреляцию. Ожидается ли это? AM я что-то пропустил?Оператор opencv Sobel вычисляет корреляцию?

Mat sobelx, dest1,dest2; 
Sobel(src, sobelx, src.depth(),1,0,3); 
imshow("Sobel filtered in x dir" ,sobelx); 
Mat kern = (Mat_<float>(3,3)<<-1,0,1,-1,0,1,-1,0,1); 
filter2D(src,dest1,src.type(),kern); 
imshow("Sobel in x-dir using corr ", dest1); 
/* dest1 equals sobelx */ 
flip(kern,kern, -1);//flip the kernel in x and y direction for convolution 
filter2D(src,dest2,src.type(),kern); 
imshow("Sobel in x-dir using conv ",dest2,); 

ответ

0

Вот тест, который я написал, а выход говорит правду. cv :: Собель вычисляет корреляцию и не свертку. Я использовал следующее ядро, которое является таким же, как используемый CV :: Собел

kern = [-1, 0, 1; 
     -2, 0, 2; 
     -1, 0, 1] 

Результаты показывают, что выход sobelx и filter2d (корреляции) такое же.

void test_sobel(){ 
cv::RNG(0); 
cv::Mat src(4,4, CV_8U); 
cv::randu(src, 0, 256); 
cv::Mat sobelx, dest_corr,dest_conv; 
cv::Sobel(src, sobelx, CV_32F,1,0,3); 
// sobel uses a 3x3 filter shown as below 
Mat kern = (Mat_<float>(3,3)<<-1,0,1,-2,0,2,-1,0,1); 
// filter2D computes correlation 
cv::filter2D(src,dest_corr,CV_32F,kern); 

//flip the kernel in x and y direction for convolution 
cv::Mat kern_conv; 
cv::flip(kern,kern_conv, -1); 
cv::filter2D(src,dest_conv,CV_32F,kern_conv); 

std::cout << "kern = \n" << kern<< std::endl; 
std::cout << "kern_conv = \n" << kern_conv<< std::endl; 
std::cout << "src = \n" << src << std::endl; 
std::cout << "sobelx = \n" << sobelx<< std::endl; 
std::cout << "dest_corr = \n" << dest_corr<< std::endl; 
std::cout << "dest_conv =\n" << dest_conv << std::endl; 
cv::Mat diff1 = sobelx - dest_corr; 
cv::Mat diff2 = sobelx - dest_conv; 
std::cout << "sobelx - dest_corr = " << cv::sum(diff1)[0] << std::endl; 
std::cout << "sobelx - dest_conv = " << cv::sum(diff2)[0] << std::endl; 
} 

Выход:

kern = 
[-1, 0, 1; 
-2, 0, 2; 
-1, 0, 1] 
kern_conv = 
[1, 0, -1; 
2, 0, -2; 
1, 0, -1] 
src = 
[246, 156, 192, 7; 
165, 166, 2, 179; 
231, 212, 171, 230; 
    93, 138, 123, 80] 
sobelx = 
[0, -434, -272, 0; 
0, -440, -105, 0; 
0, -253, -9, 0; 
0, -60, -80, 0] 
dest_corr = 
[0, -434, -272, 0; 
0, -440, -105, 0; 
0, -253, -9, 0; 
0, -60, -80, 0] 
dest_conv = 
[0, 434, 272, 0; 
0, 440, 105, 0; 
0, 253, 9, 0; 
0, 60, 80, 0] 
sobelx - dest_corr = 0 
sobelx - dest_conv = -3306 
0

Edit:

Чтобы получить ядра OpenCV Собела, вы можете позвонить cv::getDerivKernels, чтобы получить два разборных ядра (это cv::sepFilter2D что на самом деле называется в OpenCV коде cv::Sobel или Intel IPP Sobel или любой другой бэкэнд, если присутствует), и действительно выполняется корреляция.

Описанное ниже ядро ​​устарело, но тестовый код может быть полезен!


Самый лучший вариант, чтобы проверить, чтобы избежать сюрприз:

{ 
    cv::RNG(0); //fix RNG 

    cv::Mat img(8, 8, CV_8U); 
    cv::randu(img, 0, 256); 

    cv::Mat sobel_x; 
    cv::Sobel(img, sobel_x, CV_64F, 1, 0); 

    cv::Mat sobel_filter; 
    cv::Mat kern = (cv::Mat_<double>(3, 3) << 1, 0, -1, 
               2, 0, -2, 
               1, 0, -1); 
    cv::filter2D(img, sobel_filter, CV_64F, kern); 

    cv::Mat kern_flip, sobel_filter_conv; 
    cv::flip(kern, kern_flip, -1); 
    cv::filter2D(img, sobel_filter_conv, CV_64F, kern_flip); 

    std::cout << "img:\n" << img << std::endl; 
    std::cout << "sobel_x:\n" << sobel_x << std::endl; 
    std::cout << "sobel_filter:\n" << sobel_filter << std::endl; 
    std::cout << "sobel_filter_conv:\n" << sobel_filter_conv << std::endl; 

    cv::Mat diff = sobel_x - sobel_filter; 
    cv::Mat diff2 = sobel_x - sobel_filter_conv; 
    std::cout << "Diff sobel_x - sobel_filter: " << cv::sum(diff)[0] << std::endl; 
    std::cout << "Diff sobel_x - sobel_filter_conv: " << cv::sum(diff2)[0] << std::endl; 
} 


{ 
    cv::RNG(0); //fix RNG 

    cv::Mat img(8, 8, CV_8U); 
    cv::randu(img, 0, 256); 

    cv::Mat sobel_y; 
    cv::Sobel(img, sobel_y, CV_64F, 0, 1); 

    cv::Mat sobel_filter; 
    cv::Mat kern = (cv::Mat_<double>(3, 3) << 1, 2, 1, 
               0, 0, 0, 
              -1, -2, -1); 
    cv::filter2D(img, sobel_filter, CV_64F, kern); 

    cv::Mat kern_flip, sobel_filter_conv; 
    cv::flip(kern, kern_flip, -1); 
    cv::filter2D(img, sobel_filter_conv, CV_64F, kern_flip); 

    std::cout << "img:\n" << img << std::endl; 
    std::cout << "sobel_y:\n" << sobel_y << std::endl; 
    std::cout << "sobel_filter:\n" << sobel_filter << std::endl; 
    std::cout << "sobel_filter_conv:\n" << sobel_filter_conv << std::endl; 

    cv::Mat diff = sobel_y - sobel_filter; 
    cv::Mat diff2 = sobel_y - sobel_filter_conv; 
    std::cout << "Diff sobel_y - sobel_filter: " << cv::sum(diff)[0] << std::endl; 
    std::cout << "Diff sobel_y - sobel_filter_conv: " << cv::sum(diff2)[0] << std::endl; 
} 

Выход:

img: 
[246, 156, 192, 7, 165, 166, 2, 179; 
231, 212, 171, 230, 93, 138, 123, 80; 
105, 242, 231, 239, 174, 174, 176, 191; 
134, 54, 234, 69, 25, 147, 24, 67; 
124, 158, 203, 206, 89, 144, 210, 51; 
    31, 132, 123, 250, 234, 246, 204, 74; 
111, 208, 249, 149, 234, 37, 55, 147; 
143, 29, 214, 169, 215, 84, 190, 204] 
sobel_x: 
[0, -228, -262, -210, 134, -266, -90, 0; 
0, -48, -116, -240, -90, -101, -86, 0; 
0, 292, 27, -401, -144, 33, -104, 0; 
0, 405, 75, -589, 29, 121, -236, 0; 
0, 350, 229, -326, -50, 211, -438, 0; 
0, 401, 225, 93, -182, -118, -327, 0; 
0, 439, 140, 82, -313, -413, 168, 0; 
0, 418, 162, -28, -394, -408, 460, 0] 
sobel_filter: 
[0, 228, 262, 210, -134, 266, 90, 0; 
0, 48, 116, 240, 90, 101, 86, 0; 
0, -292, -27, 401, 144, -33, 104, 0; 
0, -405, -75, 589, -29, -121, 236, 0; 
0, -350, -229, 326, 50, -211, 438, 0; 
0, -401, -225, -93, 182, 118, 327, 0; 
0, -439, -140, -82, 313, 413, -168, 0; 
0, -418, -162, 28, 394, 408, -460, 0] 
sobel_filter_conv: 
[0, -228, -262, -210, 134, -266, -90, 0; 
0, -48, -116, -240, -90, -101, -86, 0; 
0, 292, 27, -401, -144, 33, -104, 0; 
0, 405, 75, -589, 29, 121, -236, 0; 
0, 350, 229, -326, -50, 211, -438, 0; 
0, 401, 225, 93, -182, -118, -327, 0; 
0, 439, 140, 82, -313, -413, 168, 0; 
0, 418, 162, -28, -394, -408, 460, 0] 
Diff sobel_x - sobel_filter: -3428 
Diff sobel_x - sobel_filter_conv: 0 

img: 
[110, 239, 216, 103, 137, 248, 173, 53; 
221, 142, 83, 166, 251, 222, 243, 67; 
    29, 232, 208, 159, 115, 91, 244, 128; 
151, 254, 47, 13, 132, 253, 137, 127; 
180, 181, 179, 168, 236, 246, 66, 169; 
188, 198, 198, 137, 131, 63, 5, 237; 
220, 209, 155, 88, 28, 12, 58, 99; 
    6, 49, 196, 195, 163, 9, 82, 197] 
sobel_y: 
[0, 0, 0, 0, 0, 0, 0, 0; 
-176, -103, 33, 82, -145, -265, 60, 292; 
84, 118, -113, -461, -360, -163, -121, -92; 
200, 20, -100, 110, 406, 253, -160, -274; 
-38, 76, 370, 398, -68, -513, -344, -44; 
136, 72, -100, -392, -730, -684, -320, -156; 
-662, -482, -95, 146, 68, 1, 60, 74; 
0, 0, 0, 0, 0, 0, 0, 0] 
sobel_filter: 
[0, 0, 0, 0, 0, 0, 0, 0; 
176, 103, -33, -82, 145, 265, -60, -292; 
-84, -118, 113, 461, 360, 163, 121, 92; 
-200, -20, 100, -110, -406, -253, 160, 274; 
38, -76, -370, -398, 68, 513, 344, 44; 
-136, -72, 100, 392, 730, 684, 320, 156; 
662, 482, 95, -146, -68, -1, -60, -74; 
0, 0, 0, 0, 0, 0, 0, 0] 
sobel_filter_conv: 
[0, 0, 0, 0, 0, 0, 0, 0; 
-176, -103, 33, 82, -145, -265, 60, 292; 
84, 118, -113, -461, -360, -163, -121, -92; 
200, 20, -100, 110, 406, 253, -160, -274; 
-38, 76, 370, 398, -68, -513, -344, -44; 
136, 72, -100, -392, -730, -684, -320, -156; 
-662, -482, -95, 146, 68, 1, 60, 74; 
0, 0, 0, 0, 0, 0, 0, 0] 
Diff sobel_y - sobel_filter: -8204 
Diff sobel_y - sobel_filter_conv: 0 
+0

Привет @Catree, ваш тест еще раз доказывает, что ** резюме :: Собела вычисляет корреляцию и не свертку **. _kern_, который вы использовали в фрагменте кода, уже перевернуто. Следовательно, отменяются результаты. Используйте следующее ядро, и вы получите фактические результаты. cv :: Mat kern = (cv :: Mat_ (3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1); Вот документ opencv, который указывает на стандартное ядро ​​Sobel [http://docs.opencv.org/3.0.0/d2/d2c/tutorial_sobel_derivatives.html] – Aparajuli

+0

Я не могу найти единого мнения о ядре Sobel (например, эти источники дают несколько иные формы: https://en.wikipedia.org/wiki/Sobel_operator; http://www.cim.mcgill.ca/~image529/TA529/Image529_99/assignments/edge_detection/references/sobel.htm; https://stackoverflow.com/questions/9567882/sobel-filter-kernel-of-large-size). Для любопытства, почему это важно для вас? – Catree

+0

Другие источники: https://software.intel.com/en-us/node/504204?language=en; https://github.com/scikit-image/scikit-image/blob/master/skimage/filters/edges.py#L59 На мой взгляд, если вам нужны точные результаты, просто используйте 'cv :: filter2D' и ядро на ваш выбор. – Catree