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