filter2D实现中的差异

时间:2019-01-21 04:37:16

标签: c++ opencv image-processing computer-vision convolution

我试图实现convolute2D(在OpenCV中为filter2D),并提出了以下代码。

Mat convolute2D(Mat image, double** kernel, int W){
    Mat filtered_image = image.clone();
    // find center position of kernel (half of kernel size)
    int kCenterX = W / 2;
    int kCenterY = W / 2;
    int xx = 0;
    int yy = 0;
    cout << endl << "Performing convolution .." << endl;
    cout << "Image Size : " << image.rows << ", " << image.cols <<endl;
    for (int i = 0; i < image.rows; ++i){
        for (int j = 0; j < image.cols; ++j){
            for(int x = 0; x < W; ++x){
                xx = W - 1 - x;
                for(int y = 0; y < W; ++y){
                    yy = W - 1 - y;
                    int ii = i + (x - kCenterX);
                    int jj = j + (y - kCenterY);
                    if( ii >= 0 && ii < image.rows && jj >= 0 && jj < image.cols) {
                        filtered_image.at<uchar>(Point(j, i)) += image.at<uchar>(Point(jj, ii)) * kernel[xx][yy];
                    }

                }
            }
        }
    }
    return filtered_image;
}

假设我们总是有一个正方形核。但是我的结果与filter2D截然不同。是因为可能的溢出还是我的实现有问题?

谢谢

2 个答案:

答案 0 :(得分:4)

您的代码有两个问题:

  1. 在将输出图像添加到值之前,请勿将其设置为零。因此,您正在计算的是“输入+过滤后的输入”,而不仅仅是“过滤后的输入”。

  2. 假设kernel的值非常小,则“输入像素*内核值”可能会产生一个很小的数字,当写入uchar时会四舍五入。将所有这些值加到内核中,最终结果将太低。

我建议您这样做:

double res = 0;
for(int x = 0; x < W; ++x){
   int xx = W - 1 - x;
   for(int y = 0; y < W; ++y){
      int yy = W - 1 - y;
      int ii = i + (x - kCenterX);
      int jj = j + (y - kCenterY);
      if( ii >= 0 && ii < image.rows && jj >= 0 && jj < image.cols) {
         res += image.at<uchar>(Point(jj, ii)) * kernel[xx][yy];
      }
   }
}
filtered_image.at<uchar>(Point(j, i)) = res;

这可以同时解决两个问题。另外,这应该更快一些,因为访问输出图像会有一些开销。

要获得更快的速度,请考虑检查越界读取(内部循环中的if)会显着降低代码速度,并且对于大多数像素(几乎没有像素)几乎完全没有必要图像边缘)。相反,您可以将循环分为[0,kCenterX][kCenterX,image.rows-kCenterX][image.rows-kCenterX,image.rows]。中间循环通常是迄今为止最大的循环,不需要检查越界读取。

答案 1 :(得分:1)

并使用cv :: saturate_cast正确分配给uchar,例如:

filtered_image.at<uchar>(Point(j, i)) = cv::saturate_cast<uchar>(res);