1、5/3离散小波变换的原理
标准的提升小波过程主要包括分裂(split)、预测(predict)、更新(update)步骤,其实现的结构图如下图所示。
(1)分裂就是将信号分解成数据相关的集合,效果越好的分裂其分裂的数据相关性越强。小波基的不同相当于分裂的方式不同,在本文的设计中我采用的惰性分裂将数据分离成奇偶序列x(2n)和x(2n+1)。惰性分裂是小波变换硬件实现的一种常见的分裂方式。
(2)分裂使得两个数据集合具有很好的相关性,考虑其相关性,使用奇序列通过一个预测算子P(.)来预测偶序列,预测误差定义为D(n),D(n)通过下式求得。
通过预测能够帮助我们消除分裂后的冗余信息,使数据表达得更加紧致。预测的过程往往是可逆的,在预测算子确定的情况下,便可以通过下式来恢复。此外,高频信息也将在预测的过程中被分解出来,即就是信号的高频分量。
(3)预测后获得了信号的高频信息,但是低频信息并没有获取到,为了保留信号的完整性。需要利用预测后的数据和来获得一组信号的低频信息数据。低频信息通过一个固定的更新算子来获得,如下式所示。
综上可知,提升算法将原始的小波变换分解为分裂、预测、更新等比较简单的、易于实现的步骤。这写步骤还是可逆的,我们只需改变相应的符号和数据的流向便可以重构实现小波逆变换。
5/3整数提升小波的预测式和更新式如式下所示。
利用提升变换原理得到反预测和反更新式如下所示。
2、边界延拓
离散小波变换时,我们一般不考虑边界问题,认为信号是无限长的序列,但是对于有限大小的离散二维图像往往是有边界的,为了防止小波变换在边界处发生边界效应(滤波器截去一部分后再进行小波变换),我们常常对二维的图像数据进行边界延拓以消除边界效应。零延拓、周期延拓、对称延拓是常用的边界延拓方法。为了降低边缘效应,在本设计中我采用的是对称延拓的方法。
对称延拓,就是以两端的数据为对称点,做对称延拓,由于图像数据行列均为偶数,所以在行列数据的首延拓两个数据,尾延拓一个数据。对称延拓不仅能很好的保留边界的连续性,而且实现方法比较简单。
3、5/3离散小波正变换
module column_dwt( clk, rst_n, data_c_in, dv_c_in, dv_l_out, dv_h_out, data_h, data_l );
input wire clk; //系统时钟
input wire rst_n; //系统复位信号
input wire dv_c_in; //输入数据有效信号,高电平器件输入的数据有效
input wire [7:0] data_c_in; //输入延拓后的数据
output reg dv_h_out; //高频输出有效时置高
output reg dv_l_out; //低频输出有效时置高
output reg signed [9:0] data_h; //列变换后的高频信息输出
output reg signed [9:0] data_l; //列变换后的低频信息输出
/************通过两个D触发器将奇偶序列分开************/
reg signed [9:0] data_one; //数据1
reg signed [9:0] data_two; //数据2
reg signed [9:0] data_three; //数据3
reg [8:0] data_cnt; //输入数据计数
/************通过两个D触发器将奇偶序列分开************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_one <= 10'd0;
data_two <= 10'd0;
data_three <= 10'd0;
data_cnt <= 9'd0;
end
else begin
if(dv_c_in)begin
data_cnt <= data_cnt + 1'b1;
data_three <= {1'b0,1'b0,data_c_in};
data_two <= data_three;
data_one <= data_two;
end
else begin
data_cnt <= 9'd0;
data_one <= 10'd0;
data_two <= 10'd0;
data_three <= 10'd0;
end
end
end
/************预测模块:产生高频分量************/
reg dv_h_flag;
reg signed [9:0] update_in;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_h <= 10'd0;
dv_h_out <= 1'b0;
dv_h_flag <= 1'b0;
update_in <= 10'b0;
end
else begin
if(data_cnt == 9'd3)begin
dv_h_out <= 1'b1;
dv_h_flag <= 1'b1;
update_in <= predict_data(data_one, data_two, data_three);
data_h <= predict_data(data_one, data_two, data_three);
end
else if((data_cnt != 9'd1)&&(data_cnt != 9'd3)&&(data_cnt%2 == 1'b1))begin
data_h <= predict_data(data_one, data_two, data_three);
update_in <= predict_data(data_one, data_two, data_three);
end
else if((data_cnt%2 == 1'b0)&&(data_cnt != 9'd2)&&(data_cnt != 9'd0))begin
update_in <= data_two;
end
else if(data_cnt == 9'd0)begin
if(dv_h_flag)begin
dv_h_out <= dv_h_out;
dv_h_flag <= 1'b0;
data_h <= data_h;
end
else begin
dv_h_out <= 1'b0;
data_h <= 10'd0;
end
update_in <= 10'd0;
end
end
end
/************更新控制模块:产生低频信息************/
reg [8:0] update_cnt;
reg signed [9:0] updata_one;
reg signed [9:0] updata_two;
reg signed [9:0] updata_three;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
update_cnt <= 9'd0;
updata_one <= 9'd0;
updata_two <= 9'd0;
updata_three <= 9'd0;
end
else begin
if(dv_h_out)begin
updata_three <= update_in;
updata_two <= updata_three;
updata_one <= updata_two;
update_cnt <= update_cnt + 1'b1;
end
else begin
update_cnt <= 9'd0;
updata_one <= 9'd0;
updata_two <= 9'd0;
updata_three <= 9'd0;
end
end
end
/************更新模块************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_l <= 10'd0;
dv_l_out <= 1'b0;
end
else begin
if(update_cnt == 9'd3)begin
dv_l_out <= 1'b1;
data_l <= updata_data(updata_one, updata_two, updata_three);
end
else if((update_cnt != 9'd1)&&(update_cnt != 9'd3)&&(update_cnt%2 == 1'b1))begin
data_l <= updata_data(updata_one, updata_two, updata_three);
end
else if(update_cnt == 9'd0)begin
dv_l_out <= 1'b0;
data_l <= 10'd0;
end
end
end
/************预测函数************/
function signed [9:0] predict_data;
input signed [9:0] one;
input signed [9:0] two;
input signed [9:0] three;
predict_data = two - {(one + three) >> 1};
endfunction
/************更新函数************/
function signed [9:0] updata_data;
input signed [9:0] one;
input signed [9:0] two;
input signed [9:0] three;
reg [9:0] sum;
begin
sum = one + three + 10'd2;
if(!sum[9])begin
updata_data = two + {(one + three + 10'd2) >> 2};
end
else begin
updata_data = two - {(~(one + three + 10'd2) + 10'd1) >> 2};
end
end
endfunction
endmodule