You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将FFTW的2D DCT输出缩放至匹配OpenCV结果?

如何让FFTW的2D DCT输出匹配OpenCV的结果?

我正尝试让FFTW的2D DCT输出与OpenCV的2D DCT输出匹配。观察发现输出缩放规则似乎与行列数的平方根相关,当行列数互为倍数时能找到缩放规则,但非倍数时无法确定通用方案:

示例矩阵

0 1 2 3 4 5
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
5 6 7 8 9 10
6 7 8 9 10 11
7 8 9 10 11 12

OpenCV输出

[41.56921938165306, -11.77350269189626, -9.906343049429816e-16, -1.154700538379252, 
2.654396620040385e-16, -0.2264973081037412;
 -15.78040416381215, 0, 0, 0, 0, 0;
 6.797823324068903e-16, 0, 0, 0, 0, 0;
 -1.649620627042291, 0, 0, 0, 0, 0;
 0, 0, 0, 0, 0, 0;
 -0.4921096019966774, 0, 0, 0, 0, 0;
 -1.64113972635833e-15, 0, 0, 0, 0, 0;
 -0.1241948195350329, 0, 0, 0, 0, 0]

FFTW输出

1152 -230.713 0 -22.6274 0 -4.43842
-309.232 0 0 0 0 0
0 0 0 0 0 0
-32.3258 0 0 0 0 0
0 0 0 0 0 0
-9.64334 0 0 0 0 0
0 0 0 0 0 0
-2.43371 0 0 0 0 0

通用缩放方案

问题核心在于FFTW和OpenCV实现的DCT-II采用了不同的缩放规则:

  • FFTW的FFTW_REDFT10(对应DCT-II)输出是未归一化的原始变换结果,2D变换中行和列各乘2,整体缩放因子为4。
  • OpenCV的cv::dct采用正交归一化的DCT-II,会根据变换位置的索引(是否为0)应用不同的缩放系数。

要将FFTW输出转换为OpenCV格式,对每个元素(i,j)应用以下缩放规则:

double scale_i = (i == 0) ? (1.0 / (2 * sqrt(rows))) : (1.0 / sqrt(2 * rows));
double scale_j = (j == 0) ? (1.0 / (2 * sqrt(cols))) : (1.0 / sqrt(2 * cols));
double opencv_val = fftw_val * scale_i * scale_j;

验证示例

以示例中的元素为例:

  • 位置(0,0):scale_i=1/(2*sqrt(8))≈0.1768,scale_j=1/(2*sqrt(6))≈0.2042,1152*0.1768*0.2042≈41.569,与OpenCV输出一致。
  • 位置(0,1):scale_i=0.1768,scale_j=1/sqrt(12)≈0.2887,-230.713*0.1768*0.2887≈-11.7735,匹配OpenCV结果。
  • 位置(1,0):scale_i=1/sqrt(16)=0.25,scale_j=0.2042,-309.232*0.25*0.2042≈-15.7804,完全吻合。

修改后的代码示例

在FFTW计算完成后,对输出矩阵应用上述缩放即可:

#include <opencv2/core/core.hpp>
#include <fftw3.h>
#include <iostream>
#include <cmath>

void compute2Ddct(const double* input, double* output, int rows, int cols) {
    fftw_plan plan = fftw_plan_r2r_2d(rows, cols, const_cast<double*>(input), output, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE);
    fftw_execute(plan);
    fftw_destroy_plan(plan);
}

void scaleFFTWtoOpenCV(double* fftw_output, double* opencv_scaled, int rows, int cols) {
    for (int i = 0; i < rows; ++i) {
        double scale_i = (i == 0) ? (1.0 / (2 * sqrt(rows))) : (1.0 / sqrt(2 * rows));
        for (int j = 0; j < cols; ++j) {
            double scale_j = (j == 0) ? (1.0 / (2 * sqrt(cols))) : (1.0 / sqrt(2 * cols));
            opencv_scaled[i * cols + j] = fftw_output[i * cols + j] * scale_i * scale_j;
        }
    }
}

int main() {
    const int rows = 8;
    const int cols = 6;

    double image[rows * cols];
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            image[i * cols + j] = i + j;
        }
    }

    // OpenCV DCT计算
    cv::Mat opencv_dct(rows, cols, CV_64F, image);
    opencv_dct = opencv_dct.clone();
    cv::dct(opencv_dct, opencv_dct, 0);
    std::cout << "OpenCV DCT输出:\n" << opencv_dct << std::endl;

    // FFTW DCT计算及缩放
    double dct_output[rows * cols];
    compute2Ddct(image, dct_output, rows, cols);

    double scaled_output[rows * cols];
    scaleFFTWtoOpenCV(dct_output, scaled_output, rows, cols);

    std::cout << "\nFFTW缩放后输出:\n";
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            std::cout << scaled_output[i * cols + j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

内容的提问来源于stack exchange,提问作者Iordan Bogdan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:54:51