这是一个 Verilog 的模块化代码,用于缩放图像。以下是对每行代码的注释解释:
module image_resize(
input clk, rst_n,
input [31:0] image_in, // 输入图像
input h_sync_in, // 输入水平同步信号
input v_sync_in, // 输入垂直同步信号
output reg [31:0] image_out, // 输出缩放后图像
output reg h_sync_out, // 输出缩放后水平同步信号
output reg v_sync_out // 输出缩放后垂直同步信号
);
该代码的模块名为 image_resize
,有几个输入和输出端口,分别是:clk
(时钟信号)、rst_n
(复位信号)、image_in
(输入图像)、h_sync_in
(输入水平同步信号)、v_sync_in
(输入垂直同步信号)、image_out
(输出缩放后图像)、h_sync_out
(输出缩放后水平同步信号)、v_sync_out
(输出缩放后垂直同步信号)。其中,[31:0]
表示信号的位宽为 32 位。
parameter W_IN = 2400;
parameter H_IN = 1080;
parameter W_OUT = 1540;
parameter H_OUT = 720;
定义一些参数,分别表示输入图像的宽度和高度、输出图像的宽度和高度。
wire [10:0] h_sync_end = 1547; // 行同步信号结束时机
wire [10:0] v_sync_end = 725; // 场同步信号结束时机
定义行同步信号和场同步信号在输出图像中的结束位置。
reg [23:0] x;
reg [9:0] h_counter;
reg [9:0] v_counter;
其中,x
表示当前处理到输入图像的第几个像素位置,h_counter
表示当前处理到输出图像的第几行,v_counter
表示当前处理到输出图像的第几场。
ram ram_inst( // 定义 RAM 实例
.clk(clk),
.rst_n(rst_n),
.wr_en(h_sync_in && v_counter < H_OUT), // 当满足输入同步信号并且输出行数小于输出图像的高度时,RAM 允许写入数据
.data_in(image_in),
.addr_in({(v_counter * W_IN + x) >> 2, 2'b00}), // 将当前输入图像上的位置转换成 RAM 的地址
.data_out(image_out)
);
定义一个 RAM 模块实例,用于存储输入图像的像素值,并根据输出图像的大小进行缩放。其中,.wr_en
表示 RAM 写使能信号,当输出行数小于输出图像高度和输入行数小于输入图像高度都成立时,允许写入数据。.addr_in
表示将输入图像上的像素点转换成 RAM 中的地址。其中,2'b00
表示进一步将地址补齐到 32 位。
// 行同步信号
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin // 复位时将行同步信号清零
h_counter <= 0;
h_sync_out <= 1'b0;
end else begin
if (x == h_sync_end) begin // 当处理到输出图像中的行同步信号位置时,将行计数器清零,并将行同步信号设置为高电平
h_counter <= 0;
h_sync_out <= 1'b1;
end else if (x == W_OUT - 1) begin // 当处理完一行数据时,将行计数器加 1,并将行同步信号设置为低电平
h_counter <= h_counter + 1;
h_sync_out <= 1'b0;
end
end
end
// 场同步信号
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin // 复位时将场同步信号清零
v_counter <= 0;
v_sync_out <= 1'b0;
end else begin
if (v_counter == v_sync_end) begin // 当处理到输出图像中的场同步信号位置时,将场计数器清零,并将场同步信号设置为高电平
v_counter <= 0;
v_sync_out <= 1'b1;
end else if (x == W_OUT - 1) begin // 当处理完一行数据时,将场计数器加 1,并将场同步信号设置为低电平
v_counter <= v_counter + 1;
v_sync_out <= 1'b0;
end
end
end
定义两个模块,分别处理行同步信号和场同步信号。其中,行同步信号需要处理输出图像中的行同步信号位置,当处理到该位置时,清零行计数器并将行同步信号设置为高电平;当处理完一行数据时,将行计数器加 1。场同步信号的处理与行同步信号类似。
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin // 复位时将 x 和输出图像数据清零
x <= 0;
image_out <= 0;
end else begin
if (v_counter < H_OUT && x < W_OUT) begin // 当输出行数小于输出图像高度并且处理到的像素点小于输出图像宽度时,进行缩放处理
int x_f = (h_counter * W_IN << 16) / W_OUT; // 计算水平方向上缩放比例
int y_f = (v_counter * H_IN << 16) / H_OUT; // 计算垂直方向上缩放比例
// 边界处理
if (x_f >= W_IN) begin // 当水平方向上的缩放比例大于等于输入图像宽度时,将其限定为输入图像宽度 - 1
x_f = W_IN - 1;
end
if (y_f >= H_IN) begin // 当垂直方向上的缩放比例大于等于输入图像高度时,将其限定为输入图像高度 - 1
y_f = H_IN - 1;
end
int x_0 = x_f >> 16; // 计算缩放后所在像素点的坐标
int y_0 = y_f >> 16;
int x_1 = x_0 + 1;
int y_1 = y_0 + 1;
int a = x_f - (x_0 << 16); // 计算插值使用的系数
int b = y_f - (y_0 << 16);
int A = ram_inst.read({y_0 * W_IN + x_0, 2'd0}); // 从 RAM 中读取数据
int B = ram_inst.read({y_0 * W_IN + x_1, 2'd0});
int C = ram_inst.read({y_1 * W_IN + x_0, 2'd0});
int D = ram_inst.read({y_1 * W_IN + x_1, 2'd0});
// 双线性插值计算
int temp1 = (1 - a) * A + a * B;
int temp2 = (1 - a) * C + a * D;
int output_pixel = ((1 - b) * temp1 + b * temp2) >> 16; // 将计算结果右移 16 位,转换成 8 位数据
// 将数据放入输出寄存器中
image_out <= output_pixel;
end
// 更新 x 的值
if (x >= W_OUT - 1) begin // 当处理到输出图像的最后一个像素点时,将 x 重置为 0;否则继续向后处理
x <= 0;
end else begin
x <= x + 1;
end
end
end
定义一个模块,实现对输入图像的缩放处理,并将处理后的数据放入输出寄存器中。其中,首先根据行计数器和输出宽度计算水平方向上的缩放比例和缩放后所在像素点的坐标,然后从 RAM 中读取这些像素点的数据,并进行双线性插值计算,最后将计算结果放入输出寄存器中。每处理完一个像素点时,更新 x
的取值,用于计算下一个像素点的输出。当处理完输出图像的最后一个像素点时,将 x
重置为 0。
endmodule
结束该 Verilog 模块的定义。