基于OpenCV DFT的卷积被移位

时间:2017-04-09 12:17:21

标签: c++ opencv filtering fft dft

我尝试根据文档中的this OpenCV example 在频谱中实现图像过滤,并在此方便复制:

void convolveDFT(InputArray A, InputArray B, OutputArray C)
{
  C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type());
  Size dftSize;
  // calculate the size of DFT transform
  dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1);
  dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1);

  // allocate temporary buffers and initialize them with 0's
  Mat tempA(dftSize, A.type(), Scalar::all(0));
  Mat tempB(dftSize, B.type(), Scalar::all(0));

  // copy A and B to the top-left corners of tempA and tempB, respectively
  Mat roiA(tempA, Rect(0,0,A.cols,A.rows));
  A.copyTo(roiA);
  Mat roiB(tempB, Rect(0,0,B.cols,B.rows));
  B.copyTo(roiB);

  // now transform the padded A & B in-place;
  // use "nonzeroRows" hint for faster processing
  dft(tempA, tempA, 0, A.rows);
  dft(tempB, tempB, 0, B.rows);

  // multiply the spectrums;
  // the function handles packed spectrum representations well
  mulSpectrums(tempA, tempB, tempA);

  // transform the product back from the frequency domain.
  // Even though all the result rows will be non-zero,
  // you need only the first C.rows of them, and thus you
  // pass nonzeroRows == C.rows
  dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows);

  // now copy the result back to C.
  tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C);
}

我使用Lena图像作为A(512x512)和一个标识过滤器(除中心之外的所有条目设置为0)为B(41x41)。

Original filtered

似乎图像的底部和右侧部分已被裁剪。此外,虽然由于SO格式在此处不可见,但过滤后的图像小于原始图像(因为函数的第一行)。

如何修改代码以便像filter2D函数一样过滤图像?因此,在这种情况下,结果将是原始图像。

1 个答案:

答案 0 :(得分:1)

The size of the convolution result should be A.cols + B.cols - 1 by A.rows + B.rows - 1 (just like the arguments of the getOptimalDFTSize calls). So, to get the full convolution result, the first line of the example should be changed to:

C.create(A.rows + B.rows - 1, A.cols + B.cols - 1, A.type());

This should then give you a resulting image that is slightly larger than the original one, including a border all around which correspond to the tail of the convolution (where the filtering ramps up and down).

filter2D on the other hand does not return a full convolution as the output is limited to an image that is the same size as the original one, removing the convolution tails. To do this, filter2D assumes a linear kernel which introduces a shift of (B.cols - 1)/2 along the columns and (B.rows - 1)/2 along the rows. The filtered image can thus be extracted with the following:

C.create(A.rows, A.cols, A.type());
...
tempA(Rect((B.cols-1)/2, (B.rows-1)/2, A.cols, A.rows).copyTo(C);