我正在寻找一种简单的快速DCT算法和矩阵[NxM]的IDCT

时间:2014-03-31 18:02:15

标签: performance algorithm mathematical-optimization dct

我正在寻找一种简单的算法来执行任何大小的矩阵[NxM]的快速DCT(类型2),以及用于逆变换IDCT的算法(也称为DCT类型) 3)。

我需要DCT-2D算法,但即使是DCT-1D算法也足够好,因为我可以使用DCT-1D来实现DCT-2D(和IDCT-1D来实现IDCT-2D)。

PHP代码是首选,但任何足够清晰的算法都可以。

当矩阵大小超过[200x200]时,我当前用于实现DCT / IDCT的PHP脚本非常慢。

我正在寻找一种方法,在不到20秒的时间内完成最高达[4000x4000]的DCT。有谁知道怎么做?

1 个答案:

答案 0 :(得分:2)

这是通过FFT以相同的长度进行1D FDCT和IFDCT的计算:

//---------------------------------------------------------------------------
void DFCTrr(double *dst,double *src,double *tmp,int n)
    {
    // exact normalized DCT II by N DFFT
    int i,j;
    double nn=n,a,da=(M_PI*(nn-0.5))/nn,a0,b0,a1,b1,m;
    for (j=  0,i=n-1;i>=0;i-=2,j++) dst[j]=src[i];
    for (j=n-1,i=n-2;i>=0;i-=2,j--) dst[j]=src[i];
    DFFTcr(tmp,dst,n);
    m=2.0*sqrt(2.0);
    for (a=0.0,j=0,i=0;i<n;i++,j+=2,a+=da)
        {
        a0=tmp[j+0]; a1= cos(a);
        b0=tmp[j+1]; b1=-sin(a);
        a0=(a0*a1)-(b0*b1);
        if (i) a0*=m; else a0*=2.0;
        dst[i]=a0;
        }
    }
//---------------------------------------------------------------------------
void iDFCTrr(double *dst,double *src,double *tmp,int n)
    {
    // exact normalized DCT III = iDCT II by N iDFFT
    int i,j;
    double nn=n,a,da=(M_PI*(nn-0.5))/nn,a0,m,aa,bb;
    m=1.0/sqrt(2.0);
    for (a=0.0,j=0,i=0;i<n;i++,j+=2,a+=da)
        {
        a0=src[i];
        if (i) a0*=m;
        aa= cos(a)*a0;
        bb=+sin(a)*a0;
        tmp[j+0]=aa;
        tmp[j+1]=bb;
        }
    m=src[0]*0.25;
    iDFFTrc(src,tmp,n);
    for (j=  0,i=n-1;i>=0;i-=2,j++) dst[i]=src[j]-m;
    for (j=n-1,i=n-2;i>=0;i-=2,j--) dst[i]=src[j]-m;
    }
//---------------------------------------------------------------------------
  • dst是目标向量[n]
  • src是源向量[n]
  • tmp是临时向量[2n]

这些数组不应该重叠!!! 它取自我的变换类,所以我希望不要忘记复制一些东西。

  • XXXrr表示目的地是真实的,而来源也是真实的域
  • XXXrc表示目的地是真实的,而来源是复杂的域
  • XXXcr表示目的地很复杂,而来源是真实的域

所有数据都是double数组,对于复数域,第一个数字是Real,第二个是Imaginary部分,因此数组的大小为2N。两个函数都使用 FFT iFFT ,如果您还需要代码,请注释我。只是为了确保我在下面添加了不快速的实现。复制它要容易得多,因为快速使用过多的转换类层次结构

缓慢的DFT,iDFT测试实施:

//---------------------------------------------------------------------------
void transform::DFTcr(double *dst,double *src,int n)
    {
    int i,j;
    double a,b,a0,_n,q,qq,dq;
    dq=+2.0*M_PI/double(n); _n=2.0/double(n);
    for (q=0.0,j=0;j<n;j++,q+=dq)
        {
        a=0.0; b=0.0;
        for (qq=0.0,i=0;i<n;i++,qq+=q)
            {
            a0=src[i];
            a+=a0*cos(qq);
            b+=a0*sin(qq);
            }
        dst[j+j  ]=a*_n;
        dst[j+j+1]=b*_n;
        }
    }
//---------------------------------------------------------------------------
void transform::iDFTrc(double *dst,double *src,int n)
    {
    int i,j;
    double a,a0,a1,b0,b1,q,qq,dq;
    dq=+2.0*M_PI/double(n);
    for (q=0.0,j=0;j<n;j++,q+=dq)
        {
        a=0.0;
        for (qq=0.0,i=0;i<n;i++,qq+=q)
            {
            a0=src[i+i  ]; a1=+cos(qq);
            b0=src[i+i+1]; b1=-sin(qq);
            a+=(a0*a1)-(b0*b1);
            }
        dst[j]=a*0.5;
        }
    }
//---------------------------------------------------------------------------

因此,当代码正常运行时,测试只需将名称重写为DFFTcriDFFTrc(或使用它们与FFT,iFFT进行比较),然后实现自己的 FFT, iFFT 有关详细信息,请参阅:

2D DFCT

  1. src矩阵调整为2

    的力量

    通过添加零,使用快速算法,大小必须始终为2的力量!!!

  2. 分配NxN真实矩阵tmp,dst1xN复杂向量t

  3. DFCTrr

    转换行
    DFCT(tmp.line(i),src.line(i),t,N)
    
  4. 转置tmp矩阵

  5. DFCTrr

    转换行
    DFCT(dst.line(i),tmp.line(i),t,N)
    
  6. 转置dst矩阵

  7. 将矩阵乘以dst

  8. 0.0625归一化

    2D iDFCT

    与上述相同,但使用iDFCTrr并乘以16.0代替。

    <强> [注释]

    确保在实施自己的FFT和iFFT之前,他们给出与我相同的结果,否则DCT / iDCT将无法正常工作!!!