灰度图数据>中值滤波模块
1 顶层代码:
`timescale 1ns / 1ps
//中值滤波
module image_median_filter (
input clk,
input reset,
input [10:0] img_width,
input [ 9:0] img_height,
input cam_vsync, // 输入场同步信号
input valid_i, // 输入数据有效信号
input [15:0] rgb_565_i, // 输入的16位RGB图像数据
output cmos_frame_vsync, //输出帧有效信号
output valid_o, // 输出数据有效信号
output [15:0] rgb_565_o // 输出的16位灰度图像数据
);
//常量声明
localparam N = 3;
//变量声明
reg [23:0] img_data_o;
wire [23:0] img_data_i;
assign img_data_i = {rgb_565_i[15:11], 3'b000, rgb_565_i[10:5], 2'b00, rgb_565_i[4:0], 3'b000};
wire valid_gray;
wire [7:0] img_data_gray;
(* mark_debug="true" *) wire valid;
wire vsync;
(* mark_debug="true" *) wire [7:0] prev_line_data;
(* mark_debug="true" *) wire [7:0] cur_line_data;
(* mark_debug="true" *) wire [7:0] next_line_data;
reg valid_d1;
reg vsync_d1;
reg [7:0] prev_line_data_d1;
reg [7:0] cur_line_data_d1;
reg [7:0] next_line_data_d1;
reg [7:0] prev_line_data_d2;
reg [7:0] cur_line_data_d2;
reg [7:0] next_line_data_d2;
reg [10:0] x_cnt;
reg valid_s;
reg vsync_s;
reg [7:0] prev_line_data_d2_s;
reg [7:0] cur_line_data_d2_s;
reg [7:0] next_line_data_d2_s;
reg [7:0] prev_line_data_d1_s;
reg [7:0] cur_line_data_d1_s;
reg [7:0] next_line_data_d1_s;
reg [7:0] prev_line_data_s;
reg [7:0] cur_line_data_s;
reg [7:0] next_line_data_s;
wire valid_sort0;
reg vsync_sort0;
wire [7:0] prev_line_max_data;
wire [7:0] prev_line_mid_data;
wire [7:0] prev_line_min_data;
wire [7:0] cur_line_max_data;
wire [7:0] cur_line_mid_data;
wire [7:0] cur_line_min_data;
wire [7:0] next_line_max_data;
wire [7:0] next_line_mid_data;
wire [7:0] next_line_min_data;
wire valid_sort1;
reg vsync_sort1;
wire [7:0] max_mid_data;
wire [7:0] mid_mid_data;
wire [7:0] min_mid_data;
wire valid_sort2;
reg vsync_sort2;
wire [7:0] mid_data;
reg valid_sort3;
reg cmos_frame_sort3;
image_line_buffer u_image_line_buffer (
.clk (clk),
.reset (reset),
.img_width (img_width),
.img_height (img_height),
.valid_i (valid_i),
.img_data_i (img_data_i),
.valid_o (valid),
.cam_vsync_o (vsync),
.prev_line_data_o(prev_line_data),
.cur_line_data_o (cur_line_data),
.next_line_data_o(next_line_data)
);
always @(posedge clk or negedge reset) begin
if (!reset) begin
valid_d1 <= 0;
vsync_d1 <= 0;
prev_line_data_d1 <= 0;
cur_line_data_d1 <= 0;
next_line_data_d1 <= 0;
prev_line_data_d2 <= 0;
cur_line_data_d2 <= 0;
next_line_data_d2 <= 0;
end else begin
valid_d1 <= valid;
vsync_d1 <= vsync;
prev_line_data_d1 <= prev_line_data;
cur_line_data_d1 <= cur_line_data;
next_line_data_d1 <= next_line_data;
prev_line_data_d2 <= prev_line_data_d1;
cur_line_data_d2 <= cur_line_data_d1;
next_line_data_d2 <= next_line_data_d1;
end
end
//边界数据处理
always @(posedge clk or negedge reset) begin
if (!reset) begin
x_cnt <= 0;
end else begin
x_cnt <= valid_d1 ? ((x_cnt == img_width - 1) ? 0 : x_cnt + 1) : x_cnt;
end
end
always @(posedge clk or negedge reset) begin
if (!reset) begin
valid_s <= 0;
vsync_s <= 0;
prev_line_data_d2_s <= 0;
cur_line_data_d2_s <= 0;
next_line_data_d2_s <= 0;
prev_line_data_d1_s <= 0;
cur_line_data_d1_s <= 0;
next_line_data_d1_s <= 0;
prev_line_data_s <= 0;
cur_line_data_s <= 0;
next_line_data_s <= 0;
end else begin
valid_s <= valid_d1;
vsync_s <= vsync_d1;
prev_line_data_d1_s <= prev_line_data_d1;
cur_line_data_d1_s <= cur_line_data_d1;
next_line_data_d1_s <= next_line_data_d1;
if (x_cnt == 0) begin
prev_line_data_d2_s <= prev_line_data_d1;
cur_line_data_d2_s <= cur_line_data_d1;
next_line_data_d2_s <= next_line_data_d1;
prev_line_data_s <= prev_line_data;
cur_line_data_s <= cur_line_data;
next_line_data_s <= next_line_data;
end else if (x_cnt == img_width - 1) begin
prev_line_data_d2_s <= prev_line_data_d2;
cur_line_data_d2_s <= cur_line_data_d2;
next_line_data_d2_s <= next_line_data_d2;
prev_line_data_s <= prev_line_data_d1;
cur_line_data_s <= cur_line_data_d1;
next_line_data_s <= next_line_data_d1;
end else begin
prev_line_data_d2_s <= prev_line_data_d2;
cur_line_data_d2_s <= cur_line_data_d2;
next_line_data_d2_s <= next_line_data_d2;
prev_line_data_s <= prev_line_data;
cur_line_data_s <= cur_line_data;
next_line_data_s <= next_line_data;
end
end
end
//第1个周期
sort u_sort0 (
.clk (clk),
.reset (reset),
.valid_i (valid_s),
.data0 (prev_line_data_d2_s),
.data1 (prev_line_data_d1_s),
.data2 (prev_line_data_s),
.valid_o (valid_sort0),
.max_data(prev_line_max_data),
.mid_data(prev_line_mid_data),
.min_data(prev_line_min_data)
);
sort u_sort1 (
.clk (clk),
.reset (reset),
.valid_i (valid_s),
.data0 (cur_line_data_d2_s),
.data1 (cur_line_data_d1_s),
.data2 (cur_line_data_s),
.valid_o (),
.max_data(cur_line_max_data),
.mid_data(cur_line_mid_data),
.min_data(cur_line_min_data)
);
sort u_sort2 (
.clk (clk),
.reset (reset),
.valid_i (valid_s),
.data0 (next_line_data_d2_s),
.data1 (next_line_data_d1_s),
.data2 (next_line_data_s),
.valid_o (),
.max_data(next_line_max_data),
.mid_data(next_line_mid_data),
.min_data(next_line_min_data)
);
//第2个周期
sort u_sort3 (
.clk (clk),
.reset (reset),
.valid_i (valid_sort0),
.data0 (prev_line_max_data),
.data1 (cur_line_max_data),
.data2 (next_line_max_data),
.valid_o (valid_sort1),
.max_data(),
.mid_data(max_mid_data),
.min_data()
);
sort u_sort4 (
.clk (clk),
.reset (reset),
.valid_i (valid_sort0),
.data0 (prev_line_mid_data),
.data1 (cur_line_mid_data),
.data2 (next_line_mid_data),
.valid_o (),
.max_data(),
.mid_data(mid_mid_data),
.min_data()
);
sort u_sort5 (
.clk (clk),
.reset (reset),
.valid_i (valid_sort0),
.data0 (prev_line_min_data),
.data1 (cur_line_min_data),
.data2 (next_line_min_data),
.valid_o (),
.max_data(),
.mid_data(min_mid_data),
.min_data()
);
//第3个周期
sort u_sort6 (
.clk (clk),
.reset (reset),
.valid_i (valid_sort1),
.data0 (max_mid_data),
.data1 (mid_mid_data),
.data2 (min_mid_data),
.valid_o (valid_sort2),
.max_data(),
.mid_data(mid_data),
.min_data()
);
always @(posedge clk or negedge reset) begin
if (!reset) begin
vsync_sort0 <= 0;
vsync_sort1 <= 0;
vsync_sort2 <= 0;
end else begin
vsync_sort0 <= vsync_s;
vsync_sort1 <= vsync_sort0;
vsync_sort2 <= vsync_sort1;
end
end
always @(posedge clk or negedge reset) begin
if (!reset) begin
valid_sort3 <= 0;
img_data_o <= 0;
cmos_frame_sort3 <= 0;
end else begin
valid_sort3 <= valid_sort2;
cmos_frame_sort3 <= vsync_sort2;
//灰度图像
img_data_o <= {3{mid_data}};
end
end
assign valid_o = valid_sort3;
assign cmos_frame_vsync = cmos_frame_sort3;
assign rgb_565_o = {{img_data_o[23:19], img_data_o[15:10], img_data_o[7:3]}};
endmodule
2 三行缓存代码:
`timescale 1ns / 1ps
//3行缓存
module image_line_buffer (
input wire clk,
input wire reset,
input wire [10:0] img_width,
input wire [ 9:0] img_height,
input wire valid_i,
input wire [23:0] img_data_i,
output reg valid_o,
output reg cam_vsync_o,
output reg [23:0] prev_line_data_o,
output reg [23:0] cur_line_data_o,
output reg [23:0] next_line_data_o
);
//常量声明
parameter N = 3; //窗口大小
//变量声明
genvar i;
integer j;
wire [0:0] valid[0:N-1];
wire [23:0] data[0:N-1];
reg [10:0] out_data_cnt;
reg [9:0] out_line_cnt;
reg ch_valid;
reg ch_cam_vsync;
reg [23:0] ch_data[0:N-1];
assign valid[0] = valid_i;
assign data[0] = img_data_i;
//行缓存模块, 只需要缓存N-1个fifo即可
generate
for (i = 1; i < N; i = i + 1) begin : lb
line_buffer u_line_buffer (
.clk (clk),
.reset (reset),
.img_width(img_width),
.valid_i (valid[i-1]),
.data_i (data[i-1]),
.valid_o (valid[i]),
.data_o (data[i])
);
end
endgenerate
//按照上一行、当前行、下一行输出
//特殊情况,可根据需求设定,是复制还是给0
//第1个行缓存,是整个画面的第1行时, 上一行数据不存在,复制第1个行缓存或者直接为0输出
//第1个行缓存,是整个画面的最后1行时,下一行数据不存在,复制第1个行缓存输出
always @(posedge clk or negedge reset) begin
if (!reset) begin
for (j = 0; j < 3; j = j + 1) ch_data[j] <= 0;
end else if (valid[N-2]) begin
ch_data[1] <= data[1];
if (out_line_cnt == 0) begin
ch_data[2] <= data[0];
ch_data[0] <= data[0];
end else if (out_line_cnt == img_height - 1) begin
ch_data[2] <= data[2];
ch_data[0] <= data[2];
end else begin
ch_data[2] <= data[2];
ch_data[0] <= data[0];
end
end
end
always @(posedge clk or negedge reset) begin
if (!reset) begin
ch_valid <= 0;
out_data_cnt <= 0;
out_line_cnt <= 0;
end else begin
ch_valid <= valid[N-2];
out_data_cnt <= valid[N-2] ? ((out_data_cnt == img_width - 1) ? 0 : out_data_cnt + 1) : out_data_cnt;
ch_cam_vsync <= (out_line_cnt == img_height - 1) ? 1 : 0;
out_line_cnt <= valid[N-2]&&(out_data_cnt == img_width - 1) ? ((out_line_cnt == img_height - 1) ? 0 : out_line_cnt + 1) : out_line_cnt;
end
end
//单路输出
always @(posedge clk or negedge reset) begin
if (!reset) begin
valid_o <= 0;
prev_line_data_o <= 0;
cur_line_data_o <= 0;
next_line_data_o <= 0;
end else begin
valid_o <= ch_valid;
prev_line_data_o <= ch_data[2];
cur_line_data_o <= ch_data[1];
next_line_data_o <= ch_data[0];
cam_vsync_o <= ch_cam_vsync;
end
end
endmodule
3 一行缓存代码:
`timescale 1ns / 1ps
//1行缓存
module line_buffer (
input wire clk,
input wire reset,
input wire [10:0] img_width,
input wire valid_i,
input wire [23:0] data_i,
output wire valid_o,
output wire [23:0] data_o
);
//变量声明
wire rd_en;
wire [10:0] fifo_data_count_w;
assign rd_en = valid_i && (fifo_data_count_w == img_width) ? 1'b1 : 1'b0;
assign valid_o = rd_en;
fifo_line_buffer u_fifo_line_buffer (
.clk (clk), // input wire clk
.srst (!reset), // input wire srst
.din (data_i), // input wire [23 : 0] din
.wr_en(valid_i), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout (data_o), // output wire [23 : 0] dout
.data_count(fifo_data_count_w) // output wire [10 : 0] data_count
);
endmodule
4 排序代码:
`timescale 1ns / 1ps
//中值滤波排序模块
//接收三个8位的数据输入(data0, data1, data2),以及它们各自的标识符(data0_id, data1_id, data2_id),然后输出排序后的最大值、中值和最小值以及它们对应的标识符
module sort (
input clk,
input reset,
input valid_i,
input [7:0] data0,
input [7:0] data1,
input [7:0] data2,
input [3:0] data0_id,
input [3:0] data1_id,
input [3:0] data2_id,
output reg valid_o,
output reg [7:0] max_data,
output reg [7:0] mid_data,
output reg [7:0] min_data,
output reg [3:0] max_id,
output reg [3:0] mid_id,
output reg [3:0] min_id
);
always @(posedge clk or negedge reset) begin
if (!reset) begin
valid_o <= 0;
max_data <= 0;
mid_data <= 0;
min_data <= 0;
max_id <= 0;
mid_id <= 0;
min_id <= 0;
end else begin
valid_o <= valid_i;
if (data0 >= data1 && data0 >= data2) begin
max_data <= data0;
max_id <= data0_id;
end else if (data1 >= data0 && data1 >= data2) begin
max_data <= data1;
max_id <= data1_id;
end else begin
max_data <= data2;
max_id <= data2_id;
end
if ((data1 >= data0 && data0 >= data2) || (data2 >= data0 && data0 >= data1)) begin
mid_data <= data0;
mid_id <= data0_id;
end else if ((data0 >= data1 && data1 >= data2) || (data2 >= data1 && data1 >= data0)) begin
mid_data <= data1;
mid_id <= data1_id;
end else /*if((data0 >= data2 && data2 >= data1) || (data1 >= data2 && data2 >= data0))*/ begin
mid_data <= data2;
mid_id <= data2_id;
end
if (data2 >= data0 && data1 >= data0) begin
min_data <= data0;
min_id <= data0_id;
end else if (data2 >= data1 && data0 >= data1) begin
min_data <= data1;
min_id <= data1_id;
end else /*if(data0 >= data2 && data1 >= data2)*/ begin
min_data <= data2;
min_id <= data2_id;
end
end
end
endmodule