FPGA study notes
Image processing algorithm
1. 中值滤波算法
1.1 原理
1.2 FPGA实现中值滤波算法
1. Median filtering algorithm
1.1 Principle
Set the gray value of each pixel to the median of the gray values of all pixels in a certain area window of that point.
Features: Effectively suppress noise and protect image edge information. It is a classic noise-smoothing method and can be used to process RGB image formats.
Method:
Sort the data by size, and then find the median value according to the ordered sequence of numbers. Sorting algorithms: software algorithms such as bubble sorting, bipartite sorting, and so on. There are fewer sorting algorithms suitable for hardware.
- Sort the three rows of pixels separately
- Respectively sort the 3 largest, 3 middle, and 3 smallest pixels in the three rows of pixels
- Sort the largest smallest, middle middle, smallest largest to get the median
1.2 FPGA implementation of median filter algorithm
-
Project goal :
Denoise the salt and pepper noise picture through the median filter algorithm, and display it on the TFT display through the FPGA.
-
Project tools :
① Hardware: Intel Cyclone IV E series FPGA development board, 5-inch (800*480) TFT capacitive touch screen,
② Software: Quartus software, Picture2Hex software, MATLAB -
Project component modules :
① pll: Generate the clock required for the project: 1. SDRAM controller clock; 2. SDRAM clock signal; 3. TFT screen controller clock
② uart serial port protocol (uart_rx, uart_tx)
③ read FIFO
④ write FIFO
⑤ SDRAM Control module
⑥ TFT screen control module
⑦ Median filter module -
Verilog code
/*
1. 分别对三行像素进行排序
2. 分别对三行像素中:3个最大值,3个中间值,3个最小值,进行排序
3. 对:3最大值中的最小值,3个中间值中的中间值,3个最小值中的最大值,进行排序,得到中值
*/
module median_filter_r0(
input clk, //33MHZ
input rst_n,
input [15:0] data_in, //灰度像素输入
input data_in_en,//lcd显示有效区使能信号
input hs_in,//行同步信号输入
input vs_in,//场同步信号输入
output wire [15:0] data_out,//中值处理后灰度像素输出
output wire data_out_en,
output wire hs_out,//行同步信号输出
output wire vs_out//场同步信号输出
);
//----timing declaration----
reg hs_reg0;
reg hs_reg1;
reg hs_reg2;
reg vs_reg0;
reg vs_reg1;
reg vs_reg2;
reg de_reg0;
reg de_reg1;
reg de_reg2;
//----pipeline declaration----
wire [15:0] row0;
wire [15:0] row1;
wire [15:0] row2;
reg [15:0] r0_c0;
reg [15:0] r0_c1;
reg [15:0] r0_c2;
reg [15:0] r1_c0;
reg [15:0] r1_c1;
reg [15:0] r1_c2;
reg [15:0] r2_c0;
reg [15:0] r2_c1;
reg [15:0] r2_c2;
reg [15:0] r0_max;
reg [15:0] r0_mid;
reg [15:0] r0_min;
reg [15:0] r1_max;
reg [15:0] r1_mid;
reg [15:0] r1_min;
reg [15:0] r2_max;
reg [15:0] r2_mid;
reg [15:0] r2_min;
reg [15:0] max_max;
reg [15:0] max_mid;
reg [15:0] max_min;
reg [15:0] mid_max;
reg [15:0] mid_mid;
reg [15:0] mid_min;
reg [15:0] min_max;
reg [15:0] min_mid;
reg [15:0] min_min;
reg [15:0] mid;
//--------------------------------------------------
//----3行像素缓存--------------------------//
shifter3_3 shifter3_3(
.clken(data_in_en),
.clock(clk),
.shiftin(data_in),
.shiftout(),
.taps0x(row0),
.taps1x(row1),
.taps2x(row2)
);
//----timing control-----------------------//
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
hs_reg0 <= 1'd0;
hs_reg1 <= 1'd0;
hs_reg2 <= 1'd0;
vs_reg0 <= 1'd0;
vs_reg1 <= 1'd0;
vs_reg2 <= 1'd0;
de_reg0 <= 1'd0;
de_reg1 <= 1'd0;
de_reg2 <= 1'd0;
end
else if(data_in_en)begin
hs_reg0 <= hs_in;
hs_reg1 <= hs_reg0;
hs_reg2 <= hs_reg1;
vs_reg0 <= vs_in;
vs_reg1 <= vs_reg0;
vs_reg2 <= vs_reg1;
de_reg0 <= data_in_en;
de_reg1 <= de_reg0;
de_reg2 <= de_reg1;
end
end
//-----------------------------------------//
//----pipeline-----------------------------//
//----3*3 matix from image
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r0_c0 <= 16'd0;
r0_c1 <= 16'd0;
r0_c2 <= 16'd0;
r1_c0 <= 16'd0;
r1_c1 <= 16'd0;
r1_c2 <= 16'd0;
r2_c0 <= 16'd0;
r2_c1 <= 16'd0;
r2_c2 <= 16'd0;
end
else if(data_in_en)begin
r0_c0 <= row0;
r0_c1 <= r0_c0;
r0_c2 <= r0_c1;
r1_c0 <= row1;
r1_c1 <= r1_c0;
r1_c2 <= r1_c1;
r2_c0 <= row2;
r2_c1 <= r2_c0;
r2_c2 <= r2_c1;
end
end
//------------------------------------------------------------------
//----1.分别对三行像素进行排序r0_max, r10_max,r2_max
//----r0------------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r0_max <= 16'd0;
r0_mid <= 16'd0;
r0_min <= 16'd0;
end
else if(data_in_en)begin
if((r0_c0>=r0_c1)&&(r0_c0>=r0_c2))begin//r0_max <= r0_c0
r0_max <= r0_c0;
if(r0_c1>=r0_c2)begin
r0_mid <= r0_c1;
r0_min <= r0_c2;
end
else begin
r0_mid <= r0_c2;
r0_min <= r0_c1;
end
end
else if((r0_c1>=r0_c0)&&(r0_c1>=r0_c2))begin//r0_max <= r0_c1;
r0_max <= r0_c1;
if(r0_c0>=r0_c2)begin
r0_mid <= r0_c0;
r0_min <= r0_c2;
end
else begin
r0_mid <= r0_c2;
r0_min <= r0_c0;
end
end
else if((r0_c2>=r0_c0)&&(r0_c2>=r0_c1))begin//r0_max <= r0_c2;
r0_max <= r0_c2;
if(r0_c0>=r0_c1)begin
r0_mid <= r0_c0;
r0_min <= r0_c1;
end
else begin
r0_mid <= r0_c1;
r0_min <= r0_c0;
end
end
end
end
//----r1--------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r1_max <= 16'd0;
r1_mid <= 16'd0;
r1_min <= 16'd0;
end
else if(data_in_en)begin
if((r1_c0>=r1_c1)&&(r1_c0>=r1_c2))begin//r0_max <= r0_c0
r1_max <= r1_c0;
if(r1_c1>=r1_c2)begin
r1_mid <= r1_c1;
r1_min <= r1_c2;
end
else begin
r1_mid <= r1_c2;
r1_min <= r1_c1;
end
end
else if((r1_c1>=r1_c0)&&(r1_c1>=r1_c2))begin//r0_max <= r0_c1;
r1_max <= r1_c1;
if(r1_c0>=r1_c2)begin
r1_mid <= r1_c0;
r1_min <= r1_c2;
end
else begin
r1_mid <= r1_c2;
r1_min <= r1_c0;
end
end
else if((r1_c2>=r1_c0)&&(r1_c2>=r1_c1))begin//r0_max <= r0_c2;
r1_max <= r1_c2;
if(r1_c0>=r1_c1)begin
r1_mid <= r1_c0;
r1_min <= r1_c1;
end
else begin
r1_mid <= r1_c1;
r1_min <= r1_c0;
end
end
end
end
//----r2--------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r2_max <= 16'd0;
r2_mid <= 16'd0;
r2_min <= 16'd0;
end
else if(data_in_en)begin
if((r2_c0>=r2_c1)&&(r2_c0>=r2_c2))begin//r0_max <= r0_c0
r2_max <= r2_c0;
if(r2_c1>=r2_c2)begin
r2_mid <= r2_c1;
r2_min <= r2_c2;
end
else begin
r2_mid <= r2_c2;
r2_min <= r2_c1;
end
end
else if((r2_c1>=r2_c0)&&(r2_c1>=r2_c2))begin//r0_max <= r0_c1;
r2_max <= r2_c1;
if(r2_c0>=r2_c2)begin
r2_mid <= r2_c0;
r2_min <= r2_c2;
end
else begin
r2_mid <= r2_c2;
r2_min <= r2_c0;
end
end
else if((r2_c2>=r2_c0)&&(r2_c2>=r2_c1))begin//r0_max <= r0_c2;
r2_max <= r2_c2;
if(r2_c0>=r2_c1)begin
r2_mid <= r2_c0;
r2_min <= r2_c1;
end
else begin
r2_mid <= r2_c1;
r2_min <= r2_c0;
end
end
end
end
//--------------------------------------------------------------------
//----2. 分别对三行像素中:3个最大值,3个中间值,3个最小值,进行排序
//----3个最大值------------------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
max_max <= 16'd0;
max_mid <= 16'd0;
max_min <= 16'd0;
end
else if(data_in_en)begin
if((r0_max >= r1_max)&&(r0_max >= r2_max))begin//max_max <= r0_max
max_max <= r0_max;
if((r1_max >= r2_max))begin
max_mid <= r1_max;
max_min <= r2_max;
end
else begin
max_mid <= r2_max;
max_min <= r1_max;
end
end
else if((r1_max >= r0_max)&&(r1_max >= r2_max))begin//max_max <= r1_max;
max_max <= r1_max;
if((r0_max >= r2_max))begin
max_mid <= r0_max;
max_min <= r2_max;
end
else begin
max_mid <= r2_max;
max_min <= r0_max;
end
end
else if((r2_max >= r0_max)&&(r2_max >= r1_max))begin//max_max <= r2_max;
max_max <= r2_max;
if((r0_max >= r1_max))begin
max_mid <= r0_max;
max_min <= r1_max;
end
else begin
max_mid <= r1_max;
max_min <= r0_max;
end
end
end
end
//----3个中间值------------------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
mid_max <= 16'd0;
mid_mid <= 16'd0;
mid_min <= 16'd0;
end
else if(data_in_en)begin
if((r0_mid >= r1_mid)&&(r0_mid >= r2_mid))begin//mid_max <= r0_mid
mid_max <= r0_mid;
if((r1_mid >= r2_mid))begin
mid_mid <= r1_mid;
mid_min <= r2_mid;
end
else begin
mid_mid <= r2_mid;
mid_min <= r1_mid;
end
end
else if((r1_mid >= r0_mid)&&(r1_mid >= r2_mid))begin//mid_max <= r1_mid;
mid_max <= r1_mid;
if((r0_mid >= r2_mid))begin
mid_mid <= r0_mid;
mid_min <= r2_mid;
end
else begin
mid_mid <= r2_mid;
mid_min <= r0_mid;
end
end
else if((r2_mid >= r0_mid)&&(r2_mid >= r1_mid))begin//mid_max <= r2_mid;
mid_max <= r2_mid;
if((r0_mid >= r1_mid))begin
mid_mid <= r0_mid;
mid_min <= r1_mid;
end
else begin
mid_mid <= r1_mid;
mid_min <= r0_mid;
end
end
end
end
//----3个最小值------------------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
min_max <= 16'd0;
min_mid <= 16'd0;
min_min <= 16'd0;
end
else if(data_in_en)begin
if((r0_min >= r1_min)&&(r0_min >= r2_min))begin//min_max <= r0_min
min_max <= r0_min;
if((r1_min >= r2_min))begin
min_mid <= r1_min;
min_min <= r2_min;
end
else begin
min_mid <= r2_min;
min_min <= r1_min;
end
end
else if((r1_min >= r0_min)&&(r1_min >= r2_min))begin//min_max <= r1_min;
min_max <= r1_min;
if((r0_min >= r2_min))begin
min_mid <= r0_min;
min_min <= r2_min;
end
else begin
min_mid <= r2_min;
min_min <= r0_min;
end
end
else if((r2_min >= r0_min)&&(r2_min >= r1_min))begin//min_max <= r2_min;
min_max <= r2_min;
if((r0_min >= r1_min))begin
min_mid <= r0_min;
min_min <= r1_min;
end
else begin
min_mid <= r1_min;
min_min <= r0_min;
end
end
end
end
//---------------------------------------------------------------------------------
//----3. 对:3个最大值中的最小值,3个中间值中的中间值,3个最小值中的最大值,进行排序,得到中值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
mid <= 16'd0;
else if(data_in_en)begin
if(((max_min >= mid_mid)&&(max_min < min_max))||((max_min < mid_mid)&&(max_min >= min_max)) )//mid <= max_min;
mid <= max_min;
else if(((mid_mid >= max_min)&&(mid_mid < min_max))||((mid_mid < max_min)&&(mid_mid >= min_max)) )//mid <= mid_mid;
mid <= mid_mid;
else if(((min_max >= max_min)&&(min_max < mid_mid))||((min_max < max_min)&&(min_max >= mid_mid)) )//mid <= min_max;
mid <= min_max;
else;
end
else;
end
//----result-------------------------------------------------------------------------
assign data_out = mid;
assign data_out_en = de_reg2;
assign hs_out = hs_reg2;
assign vs_out = vs_reg2;
//-----------------------------------------------------------------------------------
endmodule
-
Project result
5 inch TFT capacitive touch screen
Image: 800*480 pixels
(1). (Yiyanqianxi^^) Original network image:
(2). FPGA display original image:
(3). Add salt and pepper noise image: -
Salt&pepper noise density=0.1
(4). FPGA median filter processing diagram: -
Salt&pepper noise density=0.1
project result analysis: -
Comparing Figure 3 and Figure 4, we can find that the median filter algorithm can effectively remove salt and pepper noise;
Reference materials: "FPGA System Design and Verification Practical Guide"
[Note]: Personal study notes, if there are mistakes, please feel free to enlighten me, this is polite~~~