空间滤波的机理通过滤波模版的逐点地移动,在每一点(x,y)处,滤波器在该点的响应通过事先定义的关系来计算。对于线性空间滤波,其响应由滤波器系数与滤波掩模扫过区域的相应像素值的乘积之和给出。
一般来说在MxN的图像上,用mxn大小的滤波器掩模进行线性滤波由下式给出:
g ( x , y ) = ∑ s = − a a ∑ s = − b b w ( s , t ) f ( x + s , y + t ) g(x,y)=\sum _ { s= -a } ^ { a }\sum _ { s = -b } ^ { b } w(s,t)f(x+s,y+t) g(x,y)=s=−a∑as=−b∑bw(s,t)f(x+s,y+t)
中心处的值由模版和周围值的函数算出计算出并代替原来的值,对整个图像每一个像素点都进行相同的操作,就完成了图像的空间滤波。
平滑空间滤波器用于模糊处理和减小噪声。模糊处理经常用于预处理,例如在提取大的目标之前去除图像中的一些琐碎的细节、桥接连线或曲线的缝合。平滑线性空间滤波器的输出响应是包括在滤波掩模邻域内像素的简单平均值。因此这些滤波器也称为均值滤波器。
一幅MxN的图像经过一个mxn(m和n是奇数)的加权均值滤波器滤波的过程可由下式给出:
g ( x , y ) = ∑ s = − a a ∑ s = − b b w ( s , t ) f ( x + s , y + t ) ∑ s = − a a ∑ s = − b b w ( s , t ) g(x,y)= \frac { \sum _ { s= -a } ^ { a }\sum _ { s = -b } ^ { b } w(s,t)f(x+s,y+t)} { \sum _ { s= -a } ^ { a }\sum _ { s = -b } ^ { b } w(s,t)} g(x,y)=∑s=−aa∑s=−bbw(s,t)∑s=−aa∑s=−bbw(s,t)f(x+s,y+t)
%matlab仿真滤波
%基于1/16的加权均值滤波
clear
clc
I1=imread('lena.jpg');
I=im2double(I1);
[m,n,c]=size(I);
A=zeros(m,n,c);
% 1 2 1
% 1/16 * 2 4 2
% 1 2 1
%for R
for i=2:m-1
for j=2:n-1
A(i,j,1)=I(i-1,j-1,1)+I(i+1,j-1,1)+I(i-1,j+1,1)+I(i+1,j+1,1)+2*I(i+1,j,1)+2*I(i-1,j,1)+2*I(i,j+1,1)+2*I(i,j-1,1)+4*I(i,j,1);
end
end
%for G
for i=2:m-1
for j=2:n-1
A(i,j,2)=I(i-1,j-1,2)+I(i+1,j-1,2)+I(i-1,j+1,2)+I(i+1,j+1,2)+2*I(i+1,j,2)+2*I(i-1,j,2)+2*I(i,j+1,2)+2*I(i,j-1,2)+4*I(i,j,2);
end
end
%for B
for i=2:m-1
for j=2:n-1
A(i,j,3)=I(i-1,j-1,3)+I(i+1,j-1,3)+I(i-1,j+1,3)+I(i+1,j+1,3)+2*I(i+1,j,3)+2*I(i-1,j,3)+2*I(i,j+1,3)+2*I(i,j-1,3)+4*I(i,j,3);
end
end
B=A/16;
%output
imwrite(B,'lena.tif','tif');
imshow('lena.jpg');title('origin image');figure
imshow('lena.tif');title('image after average filter')
第一张为原始图像,第二张为经过均值滤波的图像,可以看出滤波后的图像有一些模糊,这是由于均值滤波对图像做了平滑处理,像素值高的像素会被拉低,像素值低的像素会被拉高,趋于一个平均值,由于在图像的人物轮廓边界的值差别较大,经平均值后边界得到平滑,所以平滑滤波会使图像的边界会变得模糊。
//FPGA实现
module VIP_Gray_Mean_Filter
#(
parameter [9:0] IMG_HDISP = 10'd480, //640*480
parameter [9:0] IMG_VDISP = 10'd272
)
(
//global clock
input clk, //100MHz
input rst_n, //global reset
//Image data prepred to be processd
input per_frame_vsync, //Prepared Image data vsync valid signal
input per_frame_href, //Prepared Image data href vaild signal
input per_frame_clken, //Prepared Image data output/capture enable clock
input [7:0] per_img_Y, //Prepared Image brightness input
//Image data has been processd
output post_frame_vsync, //Processed Image data vsync valid signal
output post_frame_href, //Processed Image data href vaild signal
output post_frame_clken, //Processed Image data output/capture enable clock
output [15:0] post_img_Y //Processed Image brightness input
);
//----------------------------------------------------
//Generate 8Bit 3X3 Matrix for Video Image Processor.
//Image data has been processd
wire matrix_frame_vsync; //Prepared Image data vsync valid signal
wire matrix_frame_href; //Prepared Image data href vaild signal
wire matrix_frame_clken; //Prepared Image data output/capture enable clock
wire [7:0] matrix_p11, matrix_p12, matrix_p13; //3X3 Matrix output
wire [7:0] matrix_p21, matrix_p22, matrix_p23;
wire [7:0] matrix_p31, matrix_p32, matrix_p33;
VIP_Matrix_Generate_3X3_8Bit
#(
.IMG_HDISP (IMG_HDISP), //640*480
.IMG_VDISP (IMG_VDISP)
)
u_VIP_Matrix_Generate_3X3_8Bit
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
//Image data prepred to be processd
.per_frame_vsync (per_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (per_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (per_frame_clken), //Prepared Image data output/capture enable clock
.per_img_Y (per_img_Y), //Prepared Image brightness input
//Image data has been processd
.matrix_frame_vsync (matrix_frame_vsync), //Processed Image data vsync valid signal
.matrix_frame_href (matrix_frame_href), //Processed Image data href vaild signal
.matrix_frame_clken (matrix_frame_clken), //Processed Image data output/capture enable clock
.matrix_p11(matrix_p11), .matrix_p12(matrix_p12), .matrix_p13(matrix_p13), //3X3 Matrix output
.matrix_p21(matrix_p21), .matrix_p22(matrix_p22), .matrix_p23(matrix_p23),
.matrix_p31(matrix_p31), .matrix_p32(matrix_p32), .matrix_p33(matrix_p33)
);
//Add you arithmetic here
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//Mean Filter of 3X3 datas, need 2 clock
//Step 1
reg [10:0] mean_value1, mean_value2, mean_value3;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
mean_value1 <= 0;
mean_value2 <= 0;
mean_value3 <= 0;
end
else
begin
mean_value1 <= matrix_p11 + matrix_p12 + matrix_p13;
mean_value2 <= matrix_p21 + 11'd0 + matrix_p23;
mean_value3 <= matrix_p31 + matrix_p32 + matrix_p33;
end
end
//Step2
reg [10:0] mean_value4;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
mean_value4 <= 0;
else
mean_value4 <= mean_value1 + mean_value2 + mean_value3;
end
//step3
reg [16:0] post_img_Y1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
post_img_Y1 <=16'd0;
end
else begin
post_img_Y1<= {mean_value4[10:6],mean_value4[10:5],mean_value4[10:6]};
end
end
//------------------------------------------
//lag 2 clocks signal sync
reg [2:0] per_frame_vsync_r;
reg [2:0] per_frame_href_r;
reg [2:0] per_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
per_frame_vsync_r <= 0;
per_frame_href_r <= 0;
per_frame_clken_r <= 0;
end
else
begin
per_frame_vsync_r <= {per_frame_vsync_r[1:0], matrix_frame_vsync};
per_frame_href_r <= {per_frame_href_r[1:0], matrix_frame_href};
per_frame_clken_r <= {per_frame_clken_r[1:0], matrix_frame_clken};
end
end
assign post_frame_vsync = per_frame_vsync_r[2];
assign post_frame_href = per_frame_href_r[2];
assign post_frame_clken = per_frame_clken_r[2];
assign post_img_Y = post_frame_href ? post_img_Y1: 16'd0;
endmodule
FPGA实现时主要要注意的就是数据相加时的字长要增大,运算完后要对数据的高位进行截取,采用流水线的方法实现图像处理的硬件加速。
本文引用了其他文章资料,如有侵权,联系本人会做出修改。版本1.0,2019.10.20 作者小飞。