cv::filter2D与Gabor滤波器上的自包含卷积的区别



由于某种原因,我不得不自己编写过滤器函数。下面是我的卷积函数。

void Convolve (cv::Mat& f, cv::Mat& w, cv::Mat& output)
{
  output = f.clone();
  int height = f.rows;
  int width = f.cols;
  int a = (w.rows - 1) / 2;
  int b = (w.cols- 1) / 2;
  cv::Mat f2 = f.clone();
  for (int x = a; x < height - a; ++x)
  {
    for (int y = b; y < width - b; ++y)
    {
      float sum = 0.0;
      for (int s = -a; s <= a; ++s)
      { 
        for (int t = -b; t <= b; ++t)
        {
          sum += w.at<float>(s+a, t+b) * f2.at<float>(x+s, y+t);
        }
      }
      output.at<float>(x, y) = sum;
    }
  }
}

然后我比较了使用这个函数和cv::filter2D函数,发现它们在过滤后是不同的。当θ和psi为零时,滤波后的图像几乎相同,但其他图像则不同。

int main()
{
    cv::Mat in = cv::imread("something.jpg", 0);
    cv::Mat dest, dest1;
    cv::Mat src_f;
    in.convertTo(src_f, CV_32F);
    int kernel_size = 31;
    double sig = 1.0, th = 0.2, lm = 1.0, gm = 0.02, ps = 0.0;
    cv::Mat kernel =    cv::getGaborKernel(cv::Size(kernel_size,kernel_size), sig, th, lm, gm, ps);
    cv::filter2D(src_f, dest1, CV_32F, kernel);
    Convolve(src_f, kernel, dest);
    cv::Mat viz;
    dest.convertTo(viz, CV_8U, 1.0/255.0);
    cv::Mat viz1;
    dest1.convertTo(viz1, CV_8U, 1.0/255.0); 
    imshow("my dest", viz);
    imshow("k dest", viz1);
    cv::waitKey();
}

关于自包含卷积有什么建议吗?忽略零填充部分。

您在卷积实现中以浮点矩阵的形式访问内核,但它由doubles组成(根据文档,默认情况下ksize设置为CV_64F)。看起来OpenCV足够聪明,可以在矩阵与不同元素类型的卷积过程中检测到它,并自行执行转换/正确的内存访问,这就是它产生正确结果的原因。

为了修复你的代码片段,我添加了一行

kernel.convertTo(kernel, CV_32F);

这将产生视觉上等效的结果(直到填充)。

另一种选择是将ktype显式地设置为CV_32F

此外,当使用大内核(~11x11及更大)时,OpenCV的filter2D实现使用基于DFT的算法(在频域中)执行卷积,因此您可能会得到略有不同的结果和时序。

最新更新