基于FPGA的二维DCT变换和逆变换verilog实现,包含testbench

250 阅读3分钟

1.算法运行效果图预览

4e64314b4ddba8f6ea84f16ed4dd2776_82780907_202403061924430534920334_Expires=1709724883&Signature=3sKVC1hltvlou9XgOYOEHwu91O0%3D&domain=8.jpeg  

数据导入到matlab显示图像

ece73eecbf8f762589246ffc15e0cdc3_82780907_202403061924270393683364_Expires=1709724867&Signature=8Jn%2Bc5Vrym4DMs9t2fnOatA2C%2B4%3D&domain=8.jpeg  

2.算法运行软件版本

vivado2019.2

 

matlab2022a

 

3.算法理论概述

        离散余弦变换(Discrete Cosine Transform,DCT)是一种广泛应用于图像和信号处理领域的变换技术。在图像处理中,DCT常被用于图像压缩,如JPEG标准中就采用了DCT变换。FPGA(Field Programmable Gate Array)作为一种可编程逻辑电路,具有并行处理能力强、可重构性高等特点,非常适合实现DCT变换和逆变换。

 

      二维DCT是一种在图像处理和压缩编码中广泛应用的正交变换,它可以将图像数据从空间域转换到频率域。对于一个8x8像素块,其二维DCT变换定义如下:

19f2d03d69b0904544b530e3387238cf_82780907_202403061922040910129219_Expires=1709724724&Signature=fZ0jfrYmN1Dzc01%2FjxS6G1mclAU%3D&domain=8.png  

逆变换过程用于从频率域数据恢复回空间域图像,其公式定义为:

c6eaf2f1b294019e12b6bac2612af9b2_82780907_202403061921540830841776_Expires=1709724714&Signature=QAMiStXS0Mf2QZgED7TFM97bnTs%3D&domain=8.png  

在FPGA上实现2D DCT和IDCT需要进行以下步骤:

 

流水线设计:为了提高计算速度和并行度,可将DCT/IDCT算法分解为多个阶段,每个阶段对应一部分计算任务,通过流水线的方式逐级完成。

 

蝶形运算单元:DCT/IDCT的核心计算部分可以用一系列复用的蝶形运算结构来实现。每个蝶形单元执行一对两维频域系数与空间域像素之间的乘积累积操作。

 

存储器优化:合理利用FPGA内部的Block RAM(BRAM)或分布式RAM来缓存中间结果和输入输出数据,减少对外部存储器的访问次数,提升系统性能。

 

资源分配与优化:根据FPGA器件特性,合理分配逻辑资源如查找表(LUT)、触发器以及布线资源,确保算法高效运行的同时尽量降低功耗。

 

流水线调度与同步:在多级流水线的设计中,必须确保各阶段间的正确数据传递与同步,避免数据冲突和死锁现象的发生。

 

量化与舍入误差控制:实际应用中,为了减少计算复杂性和存储需求,通常会对DCT系数进行量化,这会引入一定的失真。在FPGA实现时需考虑量化策略及舍入误差的影响。

 

 

 

 

4.部分核心程序 ``timescale 1ns / 1ps

//

// Company:

// Engineer:

//

// Create Date: 2024/02/19 20:11:37

// Design Name:

// Module Name: TEST_tops

// Project Name:

// Target Devices:

// Tool Versions:

// Description:

//

// Dependencies:

//

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//

//

 

 

module TEST_tops();

 

 

 

reg       i_clk;

reg       i_rst;

wire[7:0] o_din;                

wire[11:0]o_dct;               

wire[7:0] o_idct;

 

 

tops tops_uut(

            .i_clk        (i_clk),

                            .i_rst        (i_rst),

 

                                  .o_din       (o_din),

                                  .o_dct       (o_dct),

 

                                  .o_idct      (o_idct)

           );

 

initial

begin

     i_clk = 1'b0;

          i_rst = 1'b1;

          #1000

          i_rst = 1'b0;

end 

integer fout1;

integer fout2;

integer fout3;

initial begin

 fout1 = $fopen("A.txt","w");

 fout2 = $fopen("B.txt","w");

 fout3 = $fopen("C.txt","w");

end

always @ (posedge i_clk)

 begin

        $fwrite(fout1,"%d\n",o_din);

         $fwrite(fout2,"%d\n",o_dct);

         $fwrite(fout3,"%d\n",o_idct);      

end

       

       

       

always #5 i_clk = ~i_clk;

endmodule`