基于 OpenCV DFT 的卷积被移位
OpenCV DFT-based convolution is shifted
我尝试根据文档中的 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 函数一样过滤图像?所以在这种情况下,结果将是原始图像。
卷积结果的大小应该是 A.cols + B.cols - 1
乘以 A.rows + B.rows - 1
(就像 getOptimalDFTSize
调用的参数一样)。所以,为了得到完整的卷积结果,例子的第一行应该改为:
C.create(A.rows + B.rows - 1, A.cols + B.cols - 1, A.type());
这应该会给你一个比原始图像稍大的结果图像,包括一个与卷积尾部相对应的边界(过滤在此处向上和向下倾斜)。
另一方面,filter2D
不是 return 全卷积,因为输出仅限于与原始图像大小相同的图像,移除了卷积尾部。为此,filter2D
假设一个线性核,它沿列引入 (B.cols - 1)/2
的偏移,沿行引入 (B.rows - 1)/2
的偏移。因此可以使用以下方法提取过滤后的图像:
C.create(A.rows, A.cols, A.type());
...
tempA(Rect((B.cols-1)/2, (B.rows-1)/2, A.cols, A.rows).copyTo(C);
我尝试根据文档中的 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 函数一样过滤图像?所以在这种情况下,结果将是原始图像。
卷积结果的大小应该是 A.cols + B.cols - 1
乘以 A.rows + B.rows - 1
(就像 getOptimalDFTSize
调用的参数一样)。所以,为了得到完整的卷积结果,例子的第一行应该改为:
C.create(A.rows + B.rows - 1, A.cols + B.cols - 1, A.type());
这应该会给你一个比原始图像稍大的结果图像,包括一个与卷积尾部相对应的边界(过滤在此处向上和向下倾斜)。
另一方面,filter2D
不是 return 全卷积,因为输出仅限于与原始图像大小相同的图像,移除了卷积尾部。为此,filter2D
假设一个线性核,它沿列引入 (B.cols - 1)/2
的偏移,沿行引入 (B.rows - 1)/2
的偏移。因此可以使用以下方法提取过滤后的图像:
C.create(A.rows, A.cols, A.type());
...
tempA(Rect((B.cols-1)/2, (B.rows-1)/2, A.cols, A.rows).copyTo(C);