Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm trying to create a convolution function but I'm having trouble during the access to the kernel data (cv::Mat).

I create the 3x3 kernel:

  cv::Mat krn(3, 3, CV_32FC1);
  krn.setTo(1);
  krn = krn/9;

And I try to loop over it. Next the image Mat will be the image to which I want to apply the convolution operator and output will be the result of convolution:

     for (int r = 0; r < image.rows - krn.rows; ++r) {

        for (int c = 0; c < image.cols - krn.cols; ++c) {

        int sum = 0;

        for (int rs = 0; rs < krn.rows; ++rs) {
          for (int cs = 0; cs < krn.cols; ++cs) {

            sum += krn.data[rs * krn.cols + cs] * image.data[(r + rs) * image.cols + c + cs];
          }
        }
        output.data[(r+1)*src.cols + c + 1]=sum;  // assuming 3x3 kernel
    }
  }

However the output is not as desired (only randomic black and white pixel). However, if I change my code this way:

for (int r = 0; r < image.rows - krn.rows; ++r) {
    
            for (int c = 0; c < image.cols - krn.cols; ++c) {
    
            int sum = 0;
    
            for (int rs = 0; rs < krn.rows; ++rs) {
              for (int cs = 0; cs < krn.cols; ++cs) {
    
                sum += 0.11 * image.data[(r + rs) * image.cols + c + cs];           // CHANGE HERE
              }
            }
            output.data[(r+1)*src.cols + c + 1]=sum;  // assuming 3x3 kernel
        }
      }

Using 0.11 instead of the kernel values seems to give the correct output. For this reason I think I'm doing something wrong accessing the kernel's data.

P.S: I cannot use krn.at<float>(rs,cs).

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
200 views
Welcome To Ask or Share your Answers For Others

1 Answer

Instead of needlessly using memcpy, you can just cast the pointer. I'll use a C-style cast because why not.

cv::Mat krn = 1 / (cv::Mat_<float>(3,3) <<
    1, 2, 3,
    4, 5, 6,
    7, 8, 9);

for (int i = 0; i < krn.rows; i += 1)
{
    for (int j = 0; j < krn.cols; j += 1)
    {
        // to see clearly what's happening
        uint8_t *byteptr = krn.data + krn.step[0] * i + krn.step[1] * j;
        float *floatptr = (float*) byteptr;

        // or in one step:
        float *floatptr = (float*) (krn.data + krn.step[0] * i + krn.step[1] * j);

        cout << "krn.at<float>(" << i << "," << j << ") = " << (*floatptr) << endl;
endl;
    }
}
krn.at<float>(0,0) = 1
krn.at<float>(0,1) = 0.5
krn.at<float>(0,2) = 0.333333
krn.at<float>(1,0) = 0.25
krn.at<float>(1,1) = 0.2
krn.at<float>(1,2) = 0.166667
krn.at<float>(2,0) = 0.142857
krn.at<float>(2,1) = 0.125
krn.at<float>(2,2) = 0.111111

Note that pointer arithmetic may not be obvious. if you have a uint8_t*, adding 1 moves it by one uint8_t, and if you have a float*, adding 1 moves it by one float which is four bytes. The step[] contains offsets expressed in bytes.

Consult the documentation for details, which include information on the step[] array that contains the strides/steps to calculate the offset given a tuple of indices into the matrix.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...