1

I want to implement 2D convolution function in C++ by myself, without using filter2D(). I'm trying to iterate all pixels of input image and kernel, then, assign new value to each pixel of dst. However, I got this error.

Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)

I found that this error tells I'm accessing nullptr, but I could not solve the problem. Here is my c++ code.

cv::Mat_<float> spatialConvolution(const cv::Mat_<float>& src, const cv::Mat_<float>& kernel)
{
//    declare variables
    Mat_<float> dst;
    Mat_<float> flipped_kernel;
    float tmp = 0.0;

//    flip kernel
    flip(kernel, flipped_kernel, -1);

//    multiply and integrate
// input rows
    for(int i=0;i<src.rows;i++){
// input columns
        for(int j=0;j<src.cols;j++){
// kernel rows
            for(int k=0;k<flipped_kernel.rows;k++){
// kernel columns
                for(int l=0;l<flipped_kernel.cols;l++){
                    tmp += src.at<float>(i,j) * flipped_kernel.at<float>(k,l);
                }
            }
            dst.at<float>(i,j) = tmp;
        }
    }
       return dst.clone();
} 
5
  • I don't really know open cv but i think you need to initialise dst Commented Nov 8, 2019 at 22:19
  • 1
    Nothing in the question conclusively points to a problem in the shown code. Just because the shown code allegedly crashes doesn't mean it's where the problem is. C++ doesn't work this way. The real problem can be anywhere. Which is why you must show a minimal reproducible example. Commented Nov 8, 2019 at 22:29
  • I modified to flipped_kernel.at<float>(k,l); and Mat_<float> dst; based on both of your advices. But I still have a same error. Any other point? Commented Nov 8, 2019 at 22:31
  • 2
    The issue is the line dst.at<float>(i,j) = tmp; because dst is not initialized. You can't assign something to index 5 if the matrix has no size/data. Instead, initialize the matrix as the first commenter said. Mat_<float> is not an initialization, it is a declaration. Use one of the initializations where you can specify a cv::Size or the rows/columns: docs.opencv.org/3.4/d3/d63/… Commented Nov 8, 2019 at 22:44
  • @alkasm I copied src as 'Mat dst = src.clone()' and it worked. Thank you for your comment! Commented Nov 8, 2019 at 23:08

2 Answers 2

5

To simplify let's suppose you have kernel 3x3

k(0,0) k(0,1) k(0,2)
k(1,0) k(1,1) k(1,2)
k(2,0) k(2,1) k(2,2)

to calculate convolution you are scanning input image (marked as I) from left to fright, from top to bottom and for every pixel of input image you assign one value calculated from the formula below:

newValue(y,x) = I(y-1,x-1) * k(0,0) + I(y-1,x) * k(0,1) + I(y-1,x+1) * k(0,2)
              + I(y,x-1) * k(1,0) + I(y,x) * k(1,1) + I(y,x+1) * k(1,2) + 
              + I(y+1,x-1) * k(2,0) + I(y+1,x) * k(2,1) + I(y+1,x+1) * k(2,2)


 ------------------x------------>
 |
 |
 |      [k(0,0) k(0,1) k(0,2)]
 y      [k(1,0) k(1,1) k(1,2)] 
 |      [k(2,0) k(2,1) k(2,2)]
 |

(y,x) of input Image (I) is anchor point of kernel, to assign new value to I(y,x) you need to multiply every k coefficient by corresponding point of I - your code doesn't do it.

First you need to create dst matrix with dimenstion as original image, and the same type of pixel. Then you need to rewrite your loops to reflect formula described above:

cv::Mat_<float> spatialConvolution(const cv::Mat_<float>& src, const cv::Mat_<float>& kernel)
{
    Mat dst(src.rows,src.cols,src.type());

    Mat_<float> flipped_kernel; 
    flip(kernel, flipped_kernel, -1);

    const int dx = kernel.cols / 2;
    const int dy = kernel.rows / 2;

    for (int i = 0; i<src.rows; i++) 
    {
        for (int j = 0; j<src.cols; j++) 
        {
            float tmp = 0.0f;
            for (int k = 0; k<flipped_kernel.rows; k++) 
            {
              for (int l = 0; l<flipped_kernel.cols; l++) 
              {
                int x = j - dx + l;
                int y = i - dy + k;
                if (x >= 0 && x < src.cols && y >= 0 && y < src.rows)
                    tmp += src.at<float>(y, x) * flipped_kernel.at<float>(k, l);
              }
            }
            dst.at<float>(i, j) = saturate_cast<float>(tmp);
        }
    }
    return dst.clone();
}
Sign up to request clarification or add additional context in comments.

Comments

2

Your memory access error is presumably happening due to the line:

dst.at<float>(i,j) = tmp;

because dst is not initialized. You can't assign something to that index of the matrix if it has no size/data. Instead, initialize the matrix first, as Mat_<float> is a declaration, not an initialization. Use one of the initializations where you can specify a cv::Size or the rows/columns from the different constructors for Mat (see the docs). For example, you can initialize dst with:

Mat dst{src.size(), src.type()};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.