我尝试根据文档中的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)。
似乎图像的底部和右侧部分已被裁剪。此外,虽然由于SO格式在此处不可见,但过滤后的图像小于原始图像(因为函数的第一行)。
如何修改代码以便像filter2D函数一样过滤图像?因此,在这种情况下,结果将是原始图像。
答案 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);