一、原理
1.将连续输入的9个灰度值存入移位寄存器,并通过抽头形成3×3矩阵,而后通过组合逻辑输出9个数的中值。
2.抽头原理
因为数据存入shift reg需要一拍的时间,若选用5、2抽头需要对input单独延迟一拍,本例选用6、3抽头以及input作为滤波矩阵的列输入,避免对input的单独延迟处理。
每个时钟上升沿到来时,矩阵左列为抽头输入,其他列依次右移,如图所示。
3.求中值算法
①将9个数分成3组,每组3个数。求每一组的最大值、中值、最小值
②对3个最大值求最小值,对3个最小值求最大值,对3个中值求中值,得到3个数
③对这三个数求中值,这个数也是9个像素的中值
二、verilog实现
顶层模块:
// Module Name: mid_9_nums
// Target Device: xc7z010clg400-1
// Tool versions: vivado 2017.4
// Last Version: 2022.4.18
// Description: mid_filter
//port define
module mid_9_nums(
input clk,
input rst_n,
input [7:0] data_in,
output [7:0] data_out
);
parameter length = 9;
reg [7:0] data_reg [length-1:0];//9 shift reg
/*********max/mid/min reg**********/
wire [7:0] data_max [2:0];
wire [7:0] data_mid [2:0];
wire [7:0] data_min [2:0];
wire [7:0] data_min_max;
wire [7:0] data_max_min;
wire [7:0] data_mid_mid;
/**********************************/
/**************matrix**************/
reg [7:0] m11,m12,m13;
reg [7:0] m21,m22,m23;
reg [7:0] m31,m32,m33;
/**********************************/
wire [7:0] row1,row2;
reg [7:0] row3;
integer i;
//9 nums shift reg
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
for(i = 0; i < length; i = i + 1)begin
data_reg[i] <= 8'b0;
end
end
else begin
for(i = 0; i < length - 1; i = i + 1)begin
data_reg[i+1] <= data_reg[i];
data_reg[0] <= data_in;
end
end
end
/**************taps**************
→-----6 . . . -------→ 9 nums shift reg
↑
|5 4 3|
↑
→-----→
↑
|2 1 0|
↑
data_in
********************************/
assign row1 = data_reg[6];
assign row2 = data_reg[3];
always @(posedge clk)begin
row3 <= data_in;
end
//3*3 filter matrix
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
{m11,m12,m13,m21,m22,m23,m31,m32,m33} <= 72'd0;
end
else begin
{m11,m12,m13} <= {m12,m13,row1};
{m21,m22,m23} <= {m22,m23,row2};
{m31,m32,m33} <= {m32,m33,row3};
end
end
//output must be wire type
//input port must be connected
//instance
min_mid_max_3 stage1_tmp1(m11,m12,m13, data_min[2], data_mid[2], data_max[2]);
min_mid_max_3 stage1_tmp2(m21,m22,m23, data_min[1], data_mid[1], data_max[1]);
min_mid_max_3 stage1_tmp3(m31,m32,m33, data_min[0], data_mid[0], data_max[0]);
min_mid_max_3 stage2_tmp1(.in1(data_min[2]),.in2(data_min[1]),.in3(data_min[0]),.min(),.mid(),.max(data_min_max));
min_mid_max_3 stage2_tmp2(.in1(data_mid[2]),.in2(data_mid[1]),.in3(data_mid[0]),.min(),.mid(data_mid_mid),.max());
min_mid_max_3 stage2_tmp3(.in1(data_max[2]),.in2(data_max[1]),.in3(data_max[0]),.min(data_max_min),.mid(),.max());
min_mid_max_3 stage3_tmp(.in1(data_min_max),.in2(data_mid_mid),.in3(data_max_min),.min(),.mid(data_out),.max());
endmodule
子模块:求三个数的最大值、最小值、中值
// Module Name: min_mid_max_3
// Target Device: xc7z010clg400-1
// Tool versions: vivado 2017.4
// Description: take the middle value / minimum / maximum of 3 numbers
module min_mid_max_3(
input [7:0] in1,
input [7:0] in2,
input [7:0] in3,
output reg [7:0] min,
output reg [7:0] mid,
output reg [7:0] max
);
always @(*)begin
if(in1 > in2)begin
if(in2 > in3)begin
max = in1;
mid = in2;
min = in3;
end
else begin
if(in1 > in3)begin
max = in1;
mid = in3;
min = in2;
end
else begin
max = in3;
mid = in1;
min = in2;
end
end
end
else begin//1<2
if(in1 > in3)begin
max = in2;
mid = in1;
min = in3;
end
else begin
if(in2 > in3)begin
max = in2;
mid = in3;
min = in1;
end
else begin
max = in3;
mid = in2;
min = in1;
end
end
end
end
endmodule
testbench:
`timescale 1ns / 1ps
module tb_mid_num();
//10mhz
parameter CLK_PERIOD = 100;
reg clk;
reg rst_n;
reg [7:0] data_in;
wire [7:0] data_out;
always # (CLK_PERIOD/2) clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;
#300
rst_n = 1'b1;
end
//random input
always @(posedge clk)begin
data_in = {$random}%256;
end
//instance
mid_9_nums u_mid_num(clk, rst_n, data_in, data_out);
endmodule
三、仿真
从截取的部分仿真结果来看,当输入为连续的225、23、67、201、134、37、193、141、90时,下一个时钟上升沿来临时,67/37/90组成一列输入到中值滤波的3*3矩阵,并通过中值算法求出中值134,作为中值滤波的输出。
综合结果: