Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opencv - how does the filter2D() method actually work?

I did look for the source code to Filter2D but could not find it. Neither could Visual c++. Are there any experts on the filter2D algorithm here? I know how it's supposed to work but not how it actually works. I made my own filter2d() function to test things, and the results are substantially different from opencvs filter2D(). Here's my code:

Mat myfilter2d(Mat input, Mat filter){

Mat dst = input.clone();
cout << " filter data successfully found.  Rows:" << filter.rows << " cols:" << filter.cols << " channels:" << filter.channels() << "\n";
cout << " input data successfully found.  Rows:" << input.rows << " cols:" << input.cols << " channels:" << input.channels() << "\n";

for (int i = 0-(filter.rows/2);i<input.rows-(filter.rows/2);i++){
    for (int j = 0-(filter.cols/2);j<input.cols-(filter.cols/2);j++){  //adding k and l to i and j will make up the difference and allow us to process the whole image
        float filtertotal = 0;
        for (int k = 0; k < filter.rows;k++){
            for (int l = 0; l < filter.rows;l++){
                if(i+k >= 0 && i+k < input.rows && j+l >= 0 && j+l < input.cols){  //don't try to process pixels off the endge of the map
                    float a = input.at<uchar>(i+k,j+l);
                    float b = filter.at<float>(k,l);
                    float product = a * b;
                    filtertotal += product;
                }
            }
        }
        //filter all proccessed for this pixel, write it to dst
        st.at<uchar>(i+(filter.rows/2),j+(filter.cols/2)) = filtertotal;

    }
}
return dst;
}

Anybody see anything wrong with my implementation? (besides being slow)

Here is my execution:

  cvtColor(src,src_grey,CV_BGR2GRAY);
  Mat dst = myfilter2d(src_grey,filter);
  imshow("myfilter2d",dst);
  filter2D(src_grey,dst2,-1,filter);
  imshow("filter2d",dst2);

Here is my kernel:

float megapixelarray[basesize][basesize] = {
            {1,1,-1,1,1},
            {1,1,-1,1,1},
            {1,1,1,1,1},
            {1,1,-1,1,1},
            {1,1,-1,1,1}
            };

And here are the (substantially different) results:

Thoughts, anyone?

EDIT: Thanks to Brians answer I added this code:

//normalize the kernel so its sum = 1
Scalar mysum = sum(dst);
dst = dst / mysum[0];   //make sure its not 0
dst = dst * -1;  //show negetive

and filter2d worked better. Certain filters give an exact match, and other filters, like the Sobel, fail miserably.

I'm getting close to the actual algorithm, but not there yet. Anyone else with any ideas?

like image 464
john ktejik Avatar asked Dec 20 '12 22:12

john ktejik


People also ask

What is the filter 2d?

The Filter2D operation convolves an image with the kernel. You can perform this operation on an image using the Filter2D() method of the imgproc class. Following is the syntax of this method − filter2D(src, dst, ddepth, kernel)

What is Ddepth in OpenCV?

ddepth means desired depth of the destination image.

What is kernel size in OpenCV?

The kernels will define the size of the convolution, the weights applied to it, and an anchor point usually positioned at the center. So in a 3x3 matrix, each pixel is affected only by the pixels around it, wherein a 7x7 farther pixels would change it.


1 Answers

I think the issue is probably one of scale: if your input image is an 8-bit image, most of the time the convolution will produce a value that overflows the maximum value 255.

In your implementation it looks like you are getting the wrapped-around value, but most OpenCV functions handle overflow by capping to the maximum (or minimum) value. That explains why most of the output of OpenCV's function is white, and also why you are getting concentric shapes in your output too.

To account for this, normalize your megapixelarray filter by dividing every value by the entire sum of the filter (i.e. make sure that the sum of the filter values is 1):

For example, instead of this filter (sum = 10):

1 1 1
1 2 1
1 1 1

Try this filter (sum = 1):

0.1 0.1 0.1
0.1 0.2 0.1
0.1 0.1 0.1
like image 107
Brian L Avatar answered Sep 18 '22 07:09

Brian L