Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the kernel coefficients for OpenCV's Sobel filter for sizes larger than 3 x 3?

I am using OpenCV's Sobel filter of size 5x5 and 7x7 to calculate the image derivative.

Could someone please let me know the kernel values for the Sobel filter of size 5x5 and 7x7 in OpenCV? When doing a Google search, it's showing me a lot of different kernels.

Here are some examples for 5 x 5:

1. The separable

2   1   0   -1  -2
4   8   0   -4  -8
6  12   0   -12 -6
4   8   0   -4  -8
2   1   0   -1  -2

2 . The non-separable

2   1   0   -1  -2
4  10   0   -4  -10
7  17   0   -17 -7
4  10   0   -4  -10
2   1   0   -1  -2

3. The strange non-separable

2   1   0   -1  -2
3   2   0   -2  -3
4   3   0   -3  -4
3   2   0   -2  -3
2   1   0   -1  -2
like image 352
user1235183 Avatar asked Jul 30 '15 16:07

user1235183


2 Answers

You can use getDerivKernels to determine the kernel coefficients for the Sobel filter if you really want to see what OpenCV uses. What you need to do is specify which direction you want and the size of the mask you want. As such, there are two directions per size of the kernel, so we need to call this four times.

However, what is returned are the horizontal, x, and vertical, y, 1D kernels that represent the Sobel filter which you can use to perform separable 2D filtering via sepFilter2D. If you actually want to see the kernels themselves, you simply take the outer product between the x and y kernels that are returned from getDerivKernels.

Here's something quick using Python's OpenCV interface to show the 5 x 5 x, y and 7 x 7 x and y kernels:

In [1]: import numpy as np

In [2]: import cv2

In [3]: sobel5x = cv2.getDerivKernels(1, 0, 5)

In [4]: np.outer(sobel5x[0], sobel5x[1])
Out[4]: 
array([[ -1.,  -4.,  -6.,  -4.,  -1.],
       [ -2.,  -8., -12.,  -8.,  -2.],
       [  0.,   0.,   0.,   0.,   0.],
       [  2.,   8.,  12.,   8.,   2.],
       [  1.,   4.,   6.,   4.,   1.]], dtype=float32)

In [5]: sobel5y = cv2.getDerivKernels(0, 1, 5)

In [6]: np.outer(sobel5y[0], sobel5y[1])
Out[6]: 
array([[ -1.,  -2.,   0.,   2.,   1.],
       [ -4.,  -8.,   0.,   8.,   4.],
       [ -6., -12.,   0.,  12.,   6.],
       [ -4.,  -8.,   0.,   8.,   4.],
       [ -1.,  -2.,   0.,   2.,   1.]], dtype=float32)

In [7]: sobel7x = cv2.getDerivKernels(1, 0, 7)

In [8]: np.outer(sobel7x[0], sobel7x[1])
Out[8]: 
array([[  -1.,   -6.,  -15.,  -20.,  -15.,   -6.,   -1.],
       [  -4.,  -24.,  -60.,  -80.,  -60.,  -24.,   -4.],
       [  -5.,  -30.,  -75., -100.,  -75.,  -30.,   -5.],
       [   0.,    0.,    0.,    0.,    0.,    0.,    0.],
       [   5.,   30.,   75.,  100.,   75.,   30.,    5.],
       [   4.,   24.,   60.,   80.,   60.,   24.,    4.],
       [   1.,    6.,   15.,   20.,   15.,    6.,    1.]], dtype=float32)

In [9]: sobel7y = cv2.getDerivKernels(0, 1, 7)

In [10]: np.outer(sobel7y[0], sobel7y[1])
Out[10]: 
array([[  -1.,   -4.,   -5.,    0.,    5.,    4.,    1.],
       [  -6.,  -24.,  -30.,    0.,   30.,   24.,    6.],
       [ -15.,  -60.,  -75.,    0.,   75.,   60.,   15.],
       [ -20.,  -80., -100.,    0.,  100.,   80.,   20.],
       [ -15.,  -60.,  -75.,    0.,   75.,   60.,   15.],
       [  -6.,  -24.,  -30.,    0.,   30.,   24.,    6.],
       [  -1.,   -4.,   -5.,    0.,    5.,    4.,    1.]], dtype=float32)

Note that the kernels are not normalized. If you want to use these for filtering, you should probably normalize the kernels. There's a flag in getDerivKernels that will allow you to normalize the mask.

Also notice that one mask for a given size is the transpose of the other, which makes sense if you want to detect edges for a particular orientation.


For completeness, here's the C++ version of the above Python code. To compile the code, place this into a file... call it test.cpp, then do this in the terminal:

g++ -Wall -g -o test test.cpp `pkg-config --cflags --libs opencv`

Once compiled, run the program using ./test.


#include <cv.h>

using namespace std;
using namespace cv;

int main() {

    // For the kernels
    Mat sobelX, sobelY;

    // 5 x 5 - x direction
    getDerivKernels(sobelX, sobelY, 1, 0, 5, false, CV_32F);
    cout << "sobel5x = " << endl << " " << sobelX*sobelY.t() << endl << endl;

    // 5 x 5 - y direction
    getDerivKernels(sobelX, sobelY, 0, 1, 5, false, CV_32F);
    cout << "sobel5y = " << endl << " " << sobelX*sobelY.t() << endl << endl;

    // 7 x 7 - x direction
    getDerivKernels(sobelX, sobelY, 1, 0, 7, false, CV_32F);
    cout << "sobel7x = " << endl << " " << sobelX*sobelY.t() << endl << endl;

    // 7 x 7 - y direction
    getDerivKernels(sobelX, sobelY, 0, 1, 7, false, CV_32F);
    cout << "sobel7y = " << endl << " " << sobelX*sobelY.t() << endl << endl;

    return 0;
}

Note that the x and y kernels are both column vectors, so you need transpose the y vector so that it becomes a row vector to compute the outer product.

like image 149
rayryeng Avatar answered Sep 28 '22 16:09

rayryeng


You might also want to take a look at my derivation for Sobel kernels of arbitrary sizes and angles here https://stackoverflow.com/a/41065243/2424669

like image 36
Daniel Avatar answered Sep 28 '22 16:09

Daniel