C ++ - 特征FFT用于二维图像的反卷积

时间:2018-02-08 15:44:52

标签: fft eigen convolution eigen3 deconvolution

我正在尝试对图像执行反卷积, I n x m 。用于对其进行卷积的内核是 K ,其也是 n x m 。 现在我想通过执行反卷积找到原始图像 O 。我知道我可以通过对 K 执行傅立叶变换并除以 I / K 来检索图像 O 强>,因为在傅立叶域中卷积是一种产品。 (我从here)获得了这些信息。

我看到另一篇关于如何使用特征FFT执行正向变换的帖子,here

我的前向傅里叶变换代码是:

I =输入图像(时域)

O =输出图像(频域)

tempFreq =计算的临时矩阵(频域)

timevec1 =浮动矢量

freqvec1,freqvec2,freqvec3 =复杂载体

for (Int32 i = 0; i < I->uRowsCount; ++i)
{
    for (Int32 j = 0; j < I->uColumnsCount; ++j)
    {
        timevec1.push_back((*I)(i, j));
    }

    fft.fwd(freqvec1, timevec1);

    for (Int32 j = 0; j < I->uColumnsCount; ++j)
    {
        (tempFreq)(i, j) = freqvec1[j];
    }

    freqvec1.clear();
    timevec1.clear();
}

freqvec1.clear();
timevec1.clear();


for (Int32 j = 0; j < I->uColumnsCount; ++j)
{
    for (Int32 i = 0; i < I->uRowsCount; ++i)
    {
        freqvec2.push_back((tempFreq)(i, j));
    }

    fft.fwd(freqvec1, freqvec2);

    for (Int32 i = 0; i < I->uRowsCount; ++i)
    {
        (O)(i, j) = freqvec1[i];
    }

    freqvec2.clear();
    freqvec1.clear();
}

我的逆傅立叶变换代码是:

I =输入图像(频域)

O =输出图像(时域)

tempTime =计算的临时矩阵(时域)

timevec1,timevec2 =浮动矢量

freqvec1,freqvec2 =复杂载体

    for (Int32 j = 0; j < O->uColumnsCount; ++j)
    {
        for (Int32 i = 0; i < O->uRowsCount; ++i)
        {
            freqvec1.push_back((I)(i, j));
        }

        fft.inv(timevec1, freqvec1);

        for (Int32 i = 0; i < O->uRowsCount; ++i)
        {
            (*tempTime)(i, j) = timevecCol[i];
        }

        freqvec1.clear();
        timevec1.clear();
    }

    freqvec1.clear();
    timevec1.clear();

    for (Int32 i = 0; i < O->uRowsCount; ++i)
    {
        for (Int32 j = 0; j < O->uColumnsCount; ++j)
        {
            freqvec2.push_back((*tempTime)(i, j));
        }

        fft.inv(timevec2, freqvec2);

        for (Int32 j = 0; j < O->uColumnsCount; ++j)
        {
            (*O)(i, j) = timevec2[j];
        }

        freqvec2.clear();
        timevec2.clear();
    }

对于解卷积,我将频域中的输入图像与频域中的内核分开:

freqDomainOutputImage = freqDomainInputImage.cwiseQuotient(freqDomainKernel);

为了得到原始图像,我在freqDomainOutputImage上执行逆傅里叶变换。

我得到的结果是: enter image description here

我相信FFT正在镜像左上角到另一边,但我不知道为什么?我没有使用halfSpectrum。第二,为什么图像会移位?如果我通过用以下代码替换最后一个循环将输出图像移动到中心:

(*O)((i + O->uRowsCount/2)%O->uRowsCount, (j + O->uColumnsCount/2)%O->uColumnsCount) = timevec2[j];

然后我的输出是: enter image description here

(您可以看到图像是从左上象限镜像的。)

最后,为什么它似乎有噪音,即使我自己添加模糊而没有噪音?

1 个答案:

答案 0 :(得分:2)

tempTime需要复杂。你似乎扔掉了那个想象的组件,因此你得到了镜像效果。

从具有复共轭对称性的复频域图像开始,应用1D DFT(例如沿行)。该变换的结果是仅沿着列具有复共轭对称性的复杂图像。下一个1D DFT采用这些列并从中创建实值信号,从而产生实值图像。

如果在第一步之后丢弃虚部,则沿着该维移除空间域图像的奇数分量,留下偶数(对称)图像。这就是你在结果中看到这种对称性的原因。

以这种方式思考:逆DFT逆转了DFT的过程。如果DFT变为real->complex->complex,则反转必须为complex->complex->real。中间图像具有空间和频率维度。频率分量总是很复杂。

您已经发现需要交换象限。这是因为DFT在空间域和频域中都使用最左边的像素作为原点。因此,您的空间域卷积内核必须在左上角有其原点才能正常工作。

最后,你想知道噪音。这是由数值不稳定引起的。图像的某些频率成分只具有非常小的值。对于低通滤波图像尤其如此。在那里,您将非常小的值除以其他非常小的值,产生无意义。

反卷积在实践中总是需要正规化。维纳滤波器是向反卷积添加正则化的最简单方法。有关详细信息,请参阅this other answer