图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado

名称:图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado

软件:Vivado

语言:Verilog

功能介绍

本工程使用 Verilog 实现图像最近邻缩放与固定模式旋转,顶层模块为 image_process_top。两种处理功能通过 algo_sel 选择,共享输入图像 RAM 和输出图像 RAM,适合学习 FPGA 图像几何变换中的存储组织、算法模块连接与仿真验证方法。

像素采用 RGB888 格式,每个像素占用 24 位。顶层默认输入尺寸为 96 × 64,输出尺寸为 144 × 96,对应宽、高各放大 1.5 倍的缩放配置。输入尺寸、输出尺寸、RAM 地址位宽及 ROTATE_MODE 均以参数形式设置,旋转模式的具体定义对应 rotate_fixed 模块。

工程以 RAM 读写接口组织图像处理过程:仿真端写入输入像素,启动所选算法,并读取输出像素。busy 表示当前所选算法的忙状态,done 表示完成脉冲。结合输入图片、缩放与旋转输出图片以及 Testbench,可用于图像处理课程设计、算法仿真和模块级工程参考。

运行环境

开发软件为 Vivado,主要设计语言为 Verilog,工程文件为 image_process.xpr,设计顶层为 image_process_top,仿真测试顶层为 tb_image_process。行为仿真使用 Vivado XSim。

图像测试文件包括 input.bmp 与 input_pixels.mem,仿真输出图像包括 output_scale.bmp 和 output_rotate.bmp。运行仿真时需检查图像文件路径,使输入像素文件的读取位置和输出图像的保存位置与本地工程目录对应。

设计思路

设计围绕“输入图像存储—算法处理—输出图像存储”组织数据通路。输入 RAM 保存 RGB888 像素,缩放与旋转模块分别产生读取地址,并接收同一条 24 位像素数据总线;处理后的写使能、写地址和像素数据通过顶层选择逻辑送入输出 RAM。

两种算法共享输入、输出存储资源。algo_sel 为 0 时选择 scale_nearest,为 1 时选择 rotate_fixed;start 与算法选择条件组合后,只启动对应的处理模块。busy 和 done 也按相同选择条件输出,便于仿真控制端判断处理状态。由于顶层直接使用 algo_sel 选择数据通路,处理期间应保持算法选择稳定,完成一次处理后再切换算法。

图像尺寸与 RAM 地址位宽通过参数传递到各子模块,输入 RAM 深度为 IN_WIDTH × IN_HEIGHT,输出 RAM 深度为 OUT_WIDTH × OUT_HEIGHT。调整尺寸时,需要同步检查地址位宽是否足以覆盖像素存储空间,并结合算法模块确认输出尺寸及旋转模式配置。

仿真侧通过 tb_in_wr_en、tb_in_wr_addr 和 tb_in_wr_data 写入输入图像,再通过 start 启动算法;输出图像由 tb_out_rd_addr 和 tb_out_rd_data 接口读取。这样的接口安排便于把图像文件、像素存储和 HDL 运算过程连接起来,逐步检查地址访问、输出写入及完成信号。

模块结构

image_process_top:顶层连接模块,实例化输入 RAM、输出 RAM、缩放模块和旋转模块,完成启动条件分配、存储访问选择以及 busy、done 状态输出。

scale_nearest:最近邻缩放模块,接收输入、输出图像尺寸与地址位宽参数,通过读地址访问输入像素,通过写使能、写地址和写数据接口输出处理结果。

rotate_fixed:固定模式旋转模块,接收图像尺寸、地址位宽和 ROTATE_MODE 参数,使用与缩放模块一致的存储访问及状态接口。

simple_dual_port_ram:图像存储模块,分别实例化为输入、输出 RAM,数据宽度均为 24 位,存储深度由相应图像的宽、高乘积确定。

tb_image_process:图像处理仿真测试模块,与顶层的输入写入、输出读取和算法控制接口配合,用于组织图像处理测试。

演示视频

演示视频用于配合图像缩放与旋转工程的学习,可结合顶层接口、仿真说明和输出图像理解处理流程。

仿真图/仿真说明/设计文档图片

设计文档围绕工程文件、程序文件、程序编译、RTL 图、Testbench、输入图片以及仿真图和仿真结果展开,便于对照模块结构理解图像处理流程。

图像测试以 input.bmp 和 input_pixels.mem 为输入参考,output_scale.bmp 与 output_rotate.bmp 分别对应缩放、旋转输出。学习时可结合输出图片观察几何变换效果,并在 XSim 中关注 start、algo_sel、busy、done 及 RAM 读写信号,检查启动、数据访问和处理完成之间的关系。

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image1.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image10.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image11.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image12.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image13.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image14.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image15.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image16.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image17.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image18.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image2.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image3.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image4.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image5.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image6.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image7.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image8.png

图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado 设计文档图片 image9.png

部分代码

以下展示顶层模块 image_process_top 的部分代码,完整源码请下载压缩包查看。

module image_process_top #(
    parameter integer IN_WIDTH       = 96,   // 输入图像宽度
    parameter integer IN_HEIGHT      = 64,   // 输入图像高度
    parameter integer OUT_WIDTH      = 144,  // 输出图像宽度
    parameter integer OUT_HEIGHT     = 96,   // 输出图像高度
    parameter integer ROTATE_MODE    = 0,    // 旋转角度模式, 见 rotate_fixed.v
    parameter integer IN_ADDR_WIDTH  = 13,   // 输入 RAM 地址位宽
    parameter integer OUT_ADDR_WIDTH = 14    // 输出 RAM 地址位宽
) (
    input  wire                       clk,             // 系统时钟
    input  wire                       rst_n,           // 异步低有效复位
    input  wire                       start,           // 算法启动脉冲
    input  wire                       algo_sel,        // 算法选择: 0=缩放, 1=旋转
    input  wire                       tb_in_wr_en,     // testbench 写输入 RAM 使能
    input  wire [IN_ADDR_WIDTH-1:0]   tb_in_wr_addr,   // testbench 写输入 RAM 地址
    input  wire [23:0]                tb_in_wr_data,   // testbench 写输入 RAM 数据, RGB888
    input  wire [OUT_ADDR_WIDTH-1:0]  tb_out_rd_addr,  // testbench 读输出 RAM 地址
    output wire [23:0]                tb_out_rd_data,  // testbench 读输出 RAM 数据, RGB888
    output wire                       busy,            // 当前算法忙标志
    output wire                       done             // 当前算法完成脉冲
);

    localparam ALGO_SCALE  = 1'b0;
    localparam ALGO_ROTATE = 1'b1;

    wire [IN_ADDR_WIDTH-1:0]  scale_rd_addr;
    wire [IN_ADDR_WIDTH-1:0]  rotate_rd_addr;
    wire [IN_ADDR_WIDTH-1:0]  input_rd_addr;
    wire [23:0]               input_rd_data;

    wire                      scale_wr_en;
    wire                      rotate_wr_en;
    wire [OUT_ADDR_WIDTH-1:0] scale_wr_addr;
    wire [OUT_ADDR_WIDTH-1:0] rotate_wr_addr;
    wire [23:0]               scale_wr_data;
    wire [23:0]               rotate_wr_data;
    wire                      output_wr_en;
    wire [OUT_ADDR_WIDTH-1:0] output_wr_addr;
    wire [23:0]               output_wr_data;

    wire scale_busy;
    wire rotate_busy;
    wire scale_done;
    wire rotate_done;

    assign input_rd_addr  = (algo_sel == ALGO_SCALE) ? scale_rd_addr  : rotate_rd_addr;
    assign output_wr_en   = (algo_sel == ALGO_SCALE) ? scale_wr_en    : rotate_wr_en;
    assign output_wr_addr = (algo_sel == ALGO_SCALE) ? scale_wr_addr  : rotate_wr_addr;
    assign output_wr_data = (algo_sel == ALGO_SCALE) ? scale_wr_data  : rotate_wr_data;
    assign busy           = (algo_sel == ALGO_SCALE) ? scale_busy     : rotate_busy;
    assign done           = (algo_sel == ALGO_SCALE) ? scale_done     : rotate_done;

    simple_dual_port_ram #(
        .DATA_WIDTH(24),
        .ADDR_WIDTH(IN_ADDR_WIDTH),
        .DEPTH(IN_WIDTH * IN_HEIGHT)
    ) u_input_ram (
        .clk(clk),
        .wr_en(tb_in_wr_en),
        .wr_addr(tb_in_wr_addr),
        .wr_data(tb_in_wr_data),
        .rd_addr(input_rd_addr),
        .rd_data(input_rd_data)
    );

    simple_dual_port_ram #(
        .DATA_WIDTH(24),
        .ADDR_WIDTH(OUT_ADDR_WIDTH),
        .DEPTH(OUT_WIDTH * OUT_HEIGHT)
    ) u_output_ram (
        .clk(clk),
        .wr_en(output_wr_en),
        .wr_addr(output_wr_addr),
        .wr_data(output_wr_data),
        .rd_addr(tb_out_rd_addr),
        .rd_data(tb_out_rd_data)
    );

    scale_nearest #(
        .IN_WIDTH(IN_WIDTH),
        .IN_HEIGHT(IN_HEIGHT),
        .OUT_WIDTH(OUT_WIDTH),
        .OUT_HEIGHT(OUT_HEIGHT),
        .IN_ADDR_WIDTH(IN_ADDR_WIDTH),
        .OUT_ADDR_WIDTH(OUT_ADDR_WIDTH)
    ) u_scale_nearest (
        .clk(clk),
        .rst_n(rst_n),
        .start(start && (algo_sel == ALGO_SCALE)),
        .rd_addr(scale_rd_addr),
        .rd_data(input_rd_data),
        .wr_en(scale_wr_en),
        .wr_addr(scale_wr_addr),
        .wr_data(scale_wr_data),
        .busy(scale_busy),
        .done(scale_done)
    );

    rotate_fixed #(
        .IN_WIDTH(IN_WIDTH),
        .IN_HEIGHT(IN_HEIGHT),
        .OUT_WIDTH(OUT_WIDTH),
        .OUT_HEIGHT(OUT_HEIGHT),
        .ROTATE_MODE(ROTATE_MODE),
        .IN_ADDR_WIDTH(IN_ADDR_WIDTH),
        .OUT_ADDR_WIDTH(OUT_ADDR_WIDTH)
    ) u_rotate_fixed (
        .clk(clk),
        .rst_n(rst_n),
        .start(start && (algo_sel == ALGO_ROTATE)),
        .rd_addr(rotate_rd_addr),
        .rd_data(input_rd_data),
        .wr_en(rotate_wr_en),
        .wr_addr(rotate_wr_addr),
        .wr_data(rotate_wr_data),
        .busy(rotate_busy),
        .done(rotate_done)
    );

endmodule

代码文件(付费下载)

📥 付费后此处显示完整工程压缩包下载链接。
1、代码文件需要付费后才可见。
2、支付问题请联系微信公众号客服。
3、优质Verilog/VHDL代码资源,所见即所得。
Verilog/VHDL资源下载 » 图像最近邻缩放与固定模式旋转 FPGA 设计 Verilog Vivado

注册为本站会员,充值100得150,详情咨询客服

目前为止共有 *** 位优秀的会员加入! 立刻加入会员