1 简介
均值滤波是一种低通滤波,它可以有效过滤图片中的椒盐噪声,但是副作用也同样明显,会使图片的边缘过于模糊。
均值滤波的卷积核系数均为1。
这里最终重复一下算法实现以及验证的步骤:
1.MATLAB读取图片并转化为TXT格式,命名为pre.txt。
2.ModelSim读取pre.txt文本并输入给FPGA实现的算法模块进行仿真,并将仿真后的数据写入TXT文本,命名为post.txt。
3.MATLAB对读取图像并用算法对图像进行处理,同时读取步骤2的post.txt文本进行数据对比,如果数据完全一致,则FPGA算法实现与MALAB算法实现均正确。
4.MATLAB读取post.txt转化为图片,查看算法实现效果。
由步骤可知MATLAB共有三个文件,一个图片转TXT,一个算法实现与比较,一个TXT转图片。
2 MATLAB的格式转换
本试验采用的图片为第六章的RGB转YCBCR最后生成的图片。点击此处跳转到文章,
转化的MATLAB代码为:
clear;
clc;
close all;
a = imread('../img/gray.bmp');
imshow(a);
[row,col] = size(a);
p_fid = fopen('../data/pre.txt','w+');
for i = 1:row
for j = 1:col
fprintf(p_fid,'%02x' ,a(i,j));
fprintf(p_fid,'\n');
end
end
fclose(p_fid);
3 均值滤波的FPGA实现与仿真。
均值滤波要用到3X3的卷积核,这里我们选择边沿复制的方式,卷积核系数均为1,卷积核的生成方式查看第七章点击跳转,在此模块的基础上继续编写均值滤波部分。由于均值滤波需要除以9,在FPGA中的除法实现较为消耗资源与时间,除以9采用先乘以7281再除以65536来实现。
3.1 均值滤波的FPGA实现
3.1.1 3X3卷积核实现
module padding_matrix #(
parameter COL = 1920 ,
parameter ROW = 1080 ,
parameter PADDING = 0
)(
input wire clk ,
input wire rst_n ,
input wire [7:0] data ,
input wire data_de ,
output wire matrix_de ,
output reg [7:0] matrix11 ,
output reg [7:0] matrix12 ,
output reg [7:0] matrix13 ,
output reg [7:0] matrix21 ,
output reg [7:0] matrix22 ,
output reg [7:0] matrix23 ,
output reg [7:0] matrix31 ,
output reg [7:0] matrix32 ,
output reg [7:0] matrix33
);
reg [1:0] data_de_r ;
reg [7:0] data_r1 ;
reg [7:0] data_r2 ;
reg [15:0] col_cnt ;
reg [15:0] row_cnt ;
reg data_valid ;
reg [4:0] data_valid_r;
reg fake_data_valid;
wire [7:0] row1_data ;
wire [7:0] row2_data ;
reg [7:0] row3_data ;
wire [1:0] padding ;
assign padding = PADDING;
always @(posedge clk )begin
data_de_r <= {data_de_r[1:0],data_de};
data_valid_r <= {data_valid_r[3:0],data_valid};
data_r1 <= data ;
end
wire pos_data_de;
assign pos_data_de = {data_de_r[0],data_de} == 2'b01;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
col_cnt <= 0;
end
else if(col_cnt == COL + 1)begin
col_cnt <= 0;
end
else if(data_valid || fake_data_valid)begin
col_cnt <= col_cnt + 1;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
row_cnt <= 0;
end
else if(col_cnt == COL + 1 && row_cnt == ROW )begin
row_cnt <= 0;
end
else if(col_cnt == COL + 1)begin
row_cnt <= row_cnt + 1;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
fake_data_valid <= 0;
end
else if (data_valid_r[4] == 0 && row_cnt == ROW && col_cnt <= COL ) begin
fake_data_valid <= 1;
end
else begin
fake_data_valid <= 0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
row3_data <= 0;
end
else if(col_cnt == 0 && pos_data_de && padding == 0)begin
row3_data <= 0 ;
end
else if(col_cnt == 0 && pos_data_de && padding == 1)begin
row3_data <= 8'hFF ;
end
else if(col_cnt == 0 && pos_data_de)begin
row3_data <= data ;
end
else if(col_cnt == COL && data_de_r[1] && padding == 0)begin
row3_data <= 0;
end
else if(col_cnt == COL && data_de_r[1] && padding == 1)begin
row3_data <= 8'hFF;
end
else if(col_cnt == COL && data_de_r[1])begin
row3_data <= row3_data;
end
else begin
row3_data <= data_r1;
end
end
always@(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
data_valid <= 0;
end
else if(data_de || data_de_r[1])begin
data_valid <= 1'b1;
end
else begin
data_valid <= 1'b0;
end
end
wire rd_en ;
fifo_matrix_buf u1_fifo_matrix_buf (
.rst (!rst_n ),
.wr_clk (clk ),
.rd_clk (clk ),
.din (row2_data ),
.wr_en (data_valid ),
.rd_en (rd_en ),
.dout (row1_data ),
.full ( ),
.empty ( )
);
fifo_matrix_buf u2_fifo_matrix_buf (
.rst (!rst_n ),
.wr_clk (clk ),
.rd_clk (clk ),
.din (row3_data ),
.wr_en (data_valid ),
.rd_en (rd_en ),
.dout (row2_data ),
.full ( ),
.empty ( )
);
assign rd_en = (row_cnt > 0 & (data_valid | fake_data_valid) )? 1'b1 : 1'b0;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
{matrix11,matrix12,matrix13} <= 24'd0;
{matrix21,matrix22,matrix23} <= 24'd0;
{matrix31,matrix32,matrix33} <= 24'd0;
end
else if(rd_en)begin
if(row_cnt == 1)begin
if (padding == 0) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13, 8'h0};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
if (padding == 1) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13, 8'hFF};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
else begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row2_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
end
else if (row_cnt == ROW) begin
if (padding == 0) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33, 8'h0};
end
else if(padding == 1) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33, 8'hff};
end
else begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row2_data};
end
end
else begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
end
end
reg [2:0] rd_en_r;
always @(posedge clk)begin
rd_en_r <= {rd_en_r[1:0],rd_en};
end
assign matrix_de = rd_en_r[2] & rd_en_r[0] ;
endmodule
3.1.2 均值滤波算法的FPGA实现
`timescale 1ns / 1ps
module ave_filter#(
parameter DW = 8
)(
input wire clk ,
input wire rst_n ,
input wire matrix_de ,
input wire [DW-1:0] matrix11 ,
input wire [DW-1:0] matrix12 ,
input wire [DW-1:0] matrix13 ,
input wire [DW-1:0] matrix21 ,
input wire [DW-1:0] matrix22 ,
input wire [DW-1:0] matrix23 ,
input wire [DW-1:0] matrix31 ,
input wire [DW-1:0] matrix32 ,
input wire [DW-1:0] matrix33 ,
output wire ave_data_de ,
output wire [DW-1:0] ave_data
);
reg [2:0] matrix_de_r ;
reg [DW+1:0] one_line ;
reg [DW+1:0] two_line ;
reg [DW+1:0] three_line ;
reg [DW+3:0] sum_matrix ;
reg [DW+15:0] pre_ave_data ;
always @(posedge clk)begin
if(rst_n == 0)begin
matrix_de_r <= 0;
end
else begin
matrix_de_r <= {matrix_de_r[1:0],matrix_de};
end
end
always @(posedge clk)begin
if(rst_n == 0)begin
one_line <= 0;
two_line <= 0;
three_line <= 0;
end
else if(matrix_de)begin
one_line <= matrix11 + matrix12 + matrix13;
two_line <= matrix21 + matrix22 + matrix23;
three_line <= matrix31 + matrix32 + matrix33;
end
else begin
one_line <= 0;
two_line <= 0;
three_line <= 0;
end
end
always @(posedge clk)begin
if(rst_n == 0)begin
sum_matrix <= 0;
end
else if(matrix_de_r[0])begin
sum_matrix <= one_line + two_line + three_line ;
end
else begin
sum_matrix <= 0;
end
end
always @(posedge clk)begin
if(rst_n == 0)begin
pre_ave_data <= 0;
end
else if(matrix_de_r[1])begin
pre_ave_data <= sum_matrix * 7281;
end
else begin
pre_ave_data <= 0;
end
end
assign ave_data = pre_ave_data[DW+15:16];
assign ave_data_de = matrix_de_r[2];
endmodule
3.1.3 3X3卷积核生成与均值滤波模块的连接
`timescale 1ns / 1ps
module top_ave_filter#(
parameter COL = 1920 ,
parameter ROW = 1080 ,
parameter PADDING = 2 ,
parameter DW = 8
)(
input wire clk ,
input wire rst_n ,
input wire data_de ,
input wire [DW-1:0] data ,
output wire ave_data_de ,
output wire [DW-1:0] ave_data
);
wire [DW-1:0] matrix11 ;
wire [DW-1:0] matrix12 ;
wire [DW-1:0] matrix13 ;
wire [DW-1:0] matrix21 ;
wire [DW-1:0] matrix22 ;
wire [DW-1:0] matrix23 ;
wire [DW-1:0] matrix31 ;
wire [DW-1:0] matrix32 ;
wire [DW-1:0] matrix33 ;
padding_matrix #(
.COL (COL ),
.ROW (ROW ),
.PADDING (PADDING )
)u_padding_matrix(
.clk (clk ),
.rst_n (rst_n ),
.data (data ),
.data_de (data_de ),
.matrix_de (matrix_de ),
.matrix11 (matrix11 ),
.matrix12 (matrix12 ),
.matrix13 (matrix13 ),
.matrix21 (matrix21 ),
.matrix22 (matrix22 ),
.matrix23 (matrix23 ),
.matrix31 (matrix31 ),
.matrix32 (matrix32 ),
.matrix33 (matrix33 )
);
ave_filter #(
.DW (DW)
)u_ave_filter(
.clk (clk ),
.rst_n (rst_n ),
.matrix_de (matrix_de ),
.matrix11 (matrix11 ),
.matrix12 (matrix12 ),
.matrix13 (matrix13 ),
.matrix21 (matrix21 ),
.matrix22 (matrix22 ),
.matrix23 (matrix23 ),
.matrix31 (matrix31 ),
.matrix32 (matrix32 ),
.matrix33 (matrix33 ),
.ave_data_de (ave_data_de ),
.ave_data (ave_data )
);
endmodule
3.2 FPGA仿真
3.2.1 像素读入
`timescale 1ns / 1ps
module img_gen
#(
parameter ACTIVE_IW = 1920 ,
parameter ACTIVE_IH = 1080 ,
parameter TOTAL_IW = 2200 ,
parameter TOTAL_IH = 1100 ,
parameter H_START = 100 ,
parameter V_START = 4
)(
input wire clk ,
input wire rst_n ,
output reg vs ,
output reg de ,
output reg [7:0] data
);
reg [7:0] raw_array [ACTIVE_IW*ACTIVE_IH-1:0];
integer i;
initial begin
for (i=0 ;i<ACTIVE_IH*ACTIVE_IW ; i=i+1) begin
raw_array[i] = 0;
end
end
initial begin
$readmemh("H:/picture/Z7/lesson7/data/pre.txt",raw_array);
end
reg [15:0] hcnt ;
reg [15:0] vcnt ;
reg h_de ;
reg v_de ;
reg index_de ;
reg [31:0] index ;
always @(posedge clk or negedge rst_n)
if(!rst_n)
hcnt <= 'd0;
else if(hcnt == TOTAL_IW - 1)
hcnt <= 'd0;
else
hcnt <= hcnt + 1'b1;
always @(posedge clk or negedge rst_n)
if(!rst_n)
vcnt <= 'd0;
else if(hcnt == TOTAL_IW - 1 && vcnt == TOTAL_IH - 1)
vcnt <= 'd0;
else if(hcnt == TOTAL_IW - 1)
vcnt <= vcnt + 1'b1;
else
vcnt <= vcnt;
always @(posedge clk or negedge rst_n)
if(!rst_n)
vs <= 'd0;
else if(vcnt>=2)
vs <= 1'b1;
else
vs <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
h_de <= 'd0;
else if(hcnt >= H_START && hcnt < H_START + ACTIVE_IW)
h_de <= 1'b1;
else
h_de <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
v_de <= 'd0;
else if(vcnt >= V_START && vcnt < V_START + ACTIVE_IH)
v_de <= 1'b1;
else
v_de <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
index_de <= 'd0;
else if(h_de == 1'b1 && v_de == 1'b1)
index_de <= 1'b1;
else
index_de <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
index <= 'd0;
else if(index == ACTIVE_IW * ACTIVE_IH-1)
index <= 0;
else if(index_de == 1'b1)
index <= index + 1;
else
index <= index;
always @(posedge clk or negedge rst_n)
if(!rst_n)
de <= 'd0;
else
de <= index_de;
always @(posedge clk or negedge rst_n)begin
if(index_de == 1'b1)
data <= raw_array[index];
else
data <= 0;
end
endmodule
3.2.1 顶层TB连接
`timescale 1ns / 1ps
module img_gen
#(
parameter ACTIVE_IW = 1920 ,
parameter ACTIVE_IH = 1080 ,
parameter TOTAL_IW = 2200 ,
parameter TOTAL_IH = 1100 ,
parameter H_START = 100 ,
parameter V_START = 4
)(
input wire clk ,
input wire rst_n ,
output reg vs ,
output reg de ,
output reg [7:0] data
);
reg [7:0] raw_array [ACTIVE_IW*ACTIVE_IH-1:0];
integer i;
initial begin
for (i=0 ;i<ACTIVE_IH*ACTIVE_IW ; i=i+1) begin
raw_array[i] = 0;
end
end
initial begin
$readmemh("H:/picture/Z7/lesson7/data/pre.txt",raw_array);
end
reg [15:0] hcnt ;
reg [15:0] vcnt ;
reg h_de ;
reg v_de ;
reg index_de ;
reg [31:0] index ;
always @(posedge clk or negedge rst_n)
if(!rst_n)
hcnt <= 'd0;
else if(hcnt == TOTAL_IW - 1)
hcnt <= 'd0;
else
hcnt <= hcnt + 1'b1;
always @(posedge clk or negedge rst_n)
if(!rst_n)
vcnt <= 'd0;
else if(hcnt == TOTAL_IW - 1 && vcnt == TOTAL_IH - 1)
vcnt <= 'd0;
else if(hcnt == TOTAL_IW - 1)
vcnt <= vcnt + 1'b1;
else
vcnt <= vcnt;
always @(posedge clk or negedge rst_n)
if(!rst_n)
vs <= 'd0;
else if(vcnt>=2)
vs <= 1'b1;
else
vs <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
h_de <= 'd0;
else if(hcnt >= H_START && hcnt < H_START + ACTIVE_IW)
h_de <= 1'b1;
else
h_de <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
v_de <= 'd0;
else if(vcnt >= V_START && vcnt < V_START + ACTIVE_IH)
v_de <= 1'b1;
else
v_de <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
index_de <= 'd0;
else if(h_de == 1'b1 && v_de == 1'b1)
index_de <= 1'b1;
else
index_de <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
index <= 'd0;
else if(index == ACTIVE_IW * ACTIVE_IH-1)
index <= 0;
else if(index_de == 1'b1)
index <= index + 1;
else
index <= index;
always @(posedge clk or negedge rst_n)
if(!rst_n)
de <= 'd0;
else
de <= index_de;
always @(posedge clk or negedge rst_n)begin
if(index_de == 1'b1)
data <= raw_array[index];
else
data <= 0;
end
endmodule
4 MATLAB实现与比较
4.1 MATLAB实现
clc;
clear all;
GRAY = imread('../img/gray.bmp');
[row,col] = size(GRAY);
GRAY = double(GRAY);
ave_padding = zeros(row+2,col+2);
ave_result = zeros(row,col);
for i = 1:row
for j = 1:col
ave_padding(i+1,j+1) = GRAY(i,j);
end
end
for i = 1:row+2
ave_padding(i,1) = ave_padding(i,2);
ave_padding(i,col+2) = ave_padding(i,col+1);
end
for i = 1:col+2
ave_padding(1,i) = ave_padding(2,i);
ave_padding(row+2,i) = ave_padding(row+1,i);
end
for i = 2:row+1
for j = 2:col+1
matrix11 = ave_padding(i-1,j-1);
matrix12 = ave_padding(i-1,j);
matrix13 = ave_padding(i-1,j+1);
matrix21 = ave_padding(i,j-1);
matrix22 = ave_padding(i,j);
matrix23 = ave_padding(i,j+1);
matrix31 = ave_padding(i+1,j-1);
matrix32 = ave_padding(i+1,j);
matrix33 = ave_padding(i+1,j+1);
ave_result(i-1,j-1) = (matrix11+matrix12+matrix13+matrix21+matrix22+matrix23+matrix31+matrix32+matrix33)/9;
end
end
matlab_Y = uint8(floor(ave_result));
a = textread('../data/post.txt','%s');
IMdec = hex2dec(a);
col = 1920;
row = 1080;
IM = reshape(IMdec,col,row);
fpga_Y = uint8(IM)';
subplot(1,2,1)
imshow(matlab_Y),title('MATLAB算法图像');
subplot(1,2,2)
imshow(fpga_Y),title('FPGA算法图像');
sub = matlab_Y - fpga_Y;
min_sub = min(min(sub));
max_sub = max(max(sub));
4.2 比较
4.2.1 数据比较
两者实现像素做差可以看出FPGA实现与MATLAB实现在部分像素区域有着一个像素点的误差,这在定浮点数中无可避免。
4.2.2 算法结果比较
4.2.3算法前后比较
将FPGA仿真得到的post.txt图像数据转化为BMP格式的图片并显示出来。转化代码为:
clear ;
clc ;
close;
a = textread("../data/post.txt",'%s');
IMdec = hex2dec(a);
col = 1920;
row = 1080;
IM = reshape(IMdec,col,row);
b = uint8(IM)';
imwrite(b,'../img/post.bmp');
subplot(1,2,1)
imshow('../img/post.bmp'),title('FPGA算法图像');
subplot(1,2,2)
imshow('../img/gray.bmp'),title('原图像');
得到的图像对比如下图,可以看出边缘明显变模糊,这也是均值滤波的缺点,所以一般情况下不会用均值滤波来做图像处理,一般采用中值滤波等。