OpenCV gpu::dft 逆变换后的失真图像

标签 opencv gpu dft

我正在研究图像频率过滤的 GPU 实现。 我的代码在 CPU 上运行良好(我使用了类似 this 的东西),但我花了一整天时间尝试在 GPU 上进行同样的工作——但没有成功。我想在频域中应用一个滤波器,因此我需要正向变换的完整(复杂)结果。 我读到我需要传递两个复杂的矩阵(src 和 dst)来转发 dft 以获得全谱(32FC2)。然而,我在逆变换后无法获得相同的图像(返回的图像非常失真)。

我的代码(最接近的结果):

gpu.img1 = gpu::GpuMat(vrH, imgWidth, CV_32FC2);
gpu.img2 = gpu::GpuMat(vrH, imgWidth, CV_32FC2);
gpu.img4 = gpu::GpuMat(vrH, imgWidth, CV_32FC1);
gpu.img5 = gpu::GpuMat(vrH, imgWidth, CV_8UC1);

Mat planes[] = {imageIn, Mat::zeros(imageIn.size(), CV_32FC1)};
merge(planes, 2, imageIn);

gpu::Stream stream; 
gpu.img1.upload(imageIn);

gpu::dft(gpu.img1, gpu.img2, gpu.img1.size(), 0, stream);
gpu::dft(gpu.img2, gpu.img4, gpu.img1.size(), DFT_INVERSE | DFT_REAL_OUTPUT | DFT_SCALE, stream);
stream.enqueueConvert(gpu.img4, gpu.img5, CV_8U);

stream.waitForCompletion();
gpu.img5.download(imageOut);  
namedWindow("processed",1); imshow("processed", imageOut); waitKey(1000);

非常感谢您的帮助和建议。

最佳答案

我又花了几个小时,但我最终解决了这个问题。有两种选择

1) 实数到复数 (CV_32FC1 -> CV_32FC2) 正向和复数到实数 (CV_32FC2 -> CV_32FC1) 逆向
作为正向变换的结果,获得了更窄的频谱矩阵(newWidth = oldWidth/2+1,如 documentation 中所述)。它不是非 GPU dft 情况下的 CSS 紧凑矩阵。它是一个复杂的矩阵,利用了频谱对称的事实。因此,这里也可以应用任何滤波器,执行速度比第二种情况少将近一半。 在这种情况下,应设置以下标志:

  • 前进 -> 0
  • 逆-> DFT_INVERSE | DFT_REAL_OUTPUT | DFT_SCALE

这对我来说效果很好。请记住提前正确声明用于其类型的 GpuMat(CV_32FC1 或 CV_32FC2)

2) 复杂到复杂 (CV_32FC2 -> CV_32FC2) 正向和复杂到复杂 (CV_32FC2 -> CV_32FC2) 反向 全尺寸频谱 (CV_32FC2) 在前向 DFT 中生成。在这种情况下,标志是

  • 前进 -> 0
  • 逆 -> DFT_INVERSE

逆变换的结果是一个复数矩阵(CV_32FC2),因此需要将其拆分并从零 channel 中提取所需的结果。稍后需要显式缩放数据:

Mat lenaAfter;
Mat lena = imread("C:/Users/Fundespa/Desktop/lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);

lena.convertTo(lena, CV_32F, 1);

std::vector<Mat> planes;
planes.push_back(lena);
planes.push_back(Mat::zeros(lena.size(), CV_32FC1));
merge(planes, lena);

gpu::GpuMat lenaGPU = gpu::GpuMat(512, 512, CV_32FC2);
gpu::GpuMat lenaSpectrum = gpu::GpuMat(512, 512, CV_32FC2);
gpu::GpuMat lenaOut = gpu::GpuMat(512, 512, CV_32FC2);
lenaGPU.upload(lena);

gpu::dft(lenaGPU, lenaSpectrum, lenaGPU.size(), 0, stream);
int c = lenaSpectrum.channels();
Size s = lenaSpectrum.size();
gpu::dft(lenaSpectrum, lenaOut, lenaGPU.size(), DFT_INVERSE, stream);

gpu::split(lenaOut, splitter, stream);
stream.waitForCompletion();
splitter[0].download(lenaAfter);
//  lenaOut.download(lenaAfter);

c = lenaAfter.channels();

double n,x;
minMaxIdx(lenaAfter, &n, &x);

lenaAfter.convertTo(lenaAfter, CV_8U, 255.0/x);

namedWindow("lena after",1);    imshow("lena after", lenaAfter); waitKey(1000);

就这么简单!我不知道为什么我没有早点遇到这个。我决定以任何方式发布它,因为那里的人可能有同样的问题或需要一些指导。

关于OpenCV gpu::dft 逆变换后的失真图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15957671/

相关文章:

linux - Linux Mint/Ubuntu 14.04 上 Tensorflow 的 GPU 支持

c++ - MATLAB 中的 fft2 与 OpenCV C++ 中的 dft 速度比较

python - 只有整数、切片 (`:` )、省略号 (`...` )、numpy.newaxis (`None` ) 和整数或 bool 数组是有效的索引

c# - 当轮廓可以撕裂时,如何检测简单形状(使用emgu cv)?

python - PyTorch找不到名字?? (名称错误: name 'device' is not defined)

java - 实时 OpenCV 相机上的透明图像叠加

gpu - 我们如何将网络(图)数据复制到 GPU 中?

android - Android 上的频率检测 - AudioRecord

windows - OpenCV/VideoCapture/添加摄像头,对已有摄像头调试参数

image - 识别音乐符号的程序