基於FPGA灰度影象的膨脹演算法的實現
基於FPGA灰度影象的膨脹演算法的實現
1 背景知識
腐蝕與膨脹是形態學濾波的兩個基本運算,通過腐蝕和膨脹兩種運算可以實現多種功能,主要如下:
(1) 消除噪聲;
(2)分割出獨立的影象元素;
(3)在影象中連線相鄰的元素;
(4)尋找影象中明顯的極大值和極小值區域;
(5)求出影象的梯度。
圖1 腐蝕膨脹示意圖
圖1 a為大小為448X425畫素的灰度級X射線影象;b使用半徑為2個畫素的圓盤形結構元對影象的腐蝕結果;c用相同的結構元對影象的膨脹結果。原圖有Lixi公司提供。
1)形態學濾波之膨脹
膨脹(dialate)就是求區域性最大值的操作。
從數學角度來看就是將影象f和核(結構元)b進行卷積的一個過程。
當b的原點位於(x,y)處時,用一個平坦的結構元b在(x,y)處對影象f的膨脹,定義為影象f中與b重合區域的最大值,即:
為了方便起見,將膨脹操作記為:
(x,y)表示當前輸入影象的行列座標;
f(x,y)表示座標點(x,y)處的影象畫素值;
g(x,y)表示座標點(x,y)處的濾波結果;
(s,t)表示作用域。
2 matlab模擬灰度影象的膨脹
Matlab膨脹原始碼:
%%imagedilate
clc
clearall
img_a= imread('flower.bmp');
figure,imshow(img_a);
title('img_a rgb');
img_b= rgb2gray(img_a);
figure,imshow(img_b);
title('img_b gary');
a= [1,1,1;
1,1,1;
1,1,1]; %structural element
b= [1,1,1,1,1;
1,1,1,1,1;
1,1,1,1,1;
1,1,1,1,1;
1,1,1,1,1];
c = [1,1,1,1,1,1,1;
1,1,1,1,1,1,1;
1,1,1,1,1,1,1;
1,1,1,1,1,1,1;
1,1,1,1,1,1,1;
1,1,1,1,1,1,1;
1,1,1,1,1,1,1];
img_c= imdilate(img_b,a);
figure,imshow(img_c);
title('img_c 3x3');
img_d= imdilate(img_b,b);
figure,imshow(img_d);
title('img_d 5x5');
img_e= imdilate(img_b,c);
figure,imshow(img_e);
title('img_e 7x7');
3.1 膨脹模組的設計
1)比較子模組
2)一維形態學膨脹子模組
3)二維形態學膨脹子模組
(1) 比較子模組
為了程式碼更好的移植,我們將比較子模組設計為獨立的子模組。
Erode:輸出倆個數據的較小值。
比較子模組原始碼:
/*
Module name: minmax.v
Description:
Data: 2018/03/14
Engineer: lipu
e-mail: [email protected]
*/
`timescale1ns/1ps
moduleminmax(
clk, //pixel clock
rst_n,
data_valid,
din,
din_r,
dout_min,
dout_max
);
parameterWIDTH = 8; // data width 8 bit
parameterUSE_REG = 1; // USE_REG = 1Data delay 1ns output. USE_REG = 0 Don'tdelay.
input clk; //pixel clock
input rst_n;
input data_valid;
input [WIDTH-1:0] din;
input [WIDTH-1:0] din_r;
output[WIDTH-1:0] dout_min;
output[WIDTH-1:0] dout_max;
wireminmax_flag;
wire[WIDTH-1:0] min_temp;
wire[WIDTH-1:0] max_temp;
reg [WIDTH-1:0] min_reg;
reg [WIDTH-1:0] max_reg;
// min or max flag
assignminmax_flag = (din > din_r) ? 1'b1:1'b0;
// min
assignmin_temp = (minmax_flag == 1'b1) ? din_r : din;
// max
assignmax_temp = (minmax_flag == 1'b1) ? din : din_r;
// USE_REG == 1
generate
if(USE_REG== 1)
begin: MAP0
always @(posedge clk) begin
if(data_valid) begin
min_reg <= #1 min_temp;
max_reg <= #1 max_temp;
end
end
assign dout_min = min_reg;
assign dout_max = max_reg;
end
endgenerate
//USE_REG == 0
generate
if(~(USE_REG== 1))
begin: MAP1
assign dout_min = min_temp;
assign dout_max = max_temp;
end
endgenerate
endmodule
比較子模組模擬原始碼:
/*
Module name: minmax_tb.v
Description:
*/
`timescale1ns/1ps
`defineWIDTH 8
`defineCLK_PERIOD 10
moduleminmax_tb();
reg clk; //pixel clock
reg rst_n;
reg data_valid;
reg [`WIDTH-1:0] din;
reg [`WIDTH-1:0] din_r;
wire [`WIDTH-1:0] dout_min;
wire [`WIDTH-1:0] dout_max;
minmaxminmax_inst(
.clk(clk), //pixel clock
.rst_n(rst_n),
.data_valid(data_valid),
.din(din),
.din_r(din_r),
.dout_min(dout_min),
.dout_max(dout_max)
);
initial begin
clk = 0;
rst_n = 0;
data_valid = 0;
#(`CLK_PERIOD*10);
rst_n = 1;
#(`CLK_PERIOD*10);
data_valid = 1;
#(`CLK_PERIOD*100);
data_valid = 0;
#(`CLK_PERIOD*10);
$stop;
end
always#(`CLK_PERIOD/2) clk = ~clk;
[email protected](posedge clk or negedge rst_n) begin
if(!rst_n)
din <= 8'd0;
else if(data_valid)
din <= {$random}%255;
else
din <= 8'b0;
end
[email protected](posedge clk or negedge rst_n) begin
if(!rst_n)
din_r <= 8'd0;
else if(data_valid)
din_r <= din;
else
din_r <= 8'b0;
end
Endmodule
比較子模組模擬波形:
t | t+1 | t+2 | t+3 | t+4 | t+5 | t+6 | t+7 | t+8 | t+9 | t+10 | |
din | 128 | 42 | 232 | 92 | 72 | 77 | 95 | 37 | 216 | 184 | 198 |
din_r | X | 128 | 42 | 232 | 92 | 72 | 77 | 95 | 37 | 216 | 184 |
dout_min | X | X | 42 | 42 | 92 | 72 | 72 | 77 | 37 | 37 | 184 |
dout_max | X | X | 128 | 232 | 232 | 92 | 77 | 95 | 95 | 216 | 216 |
當我們需要做膨脹演算法時,資料取dout_max;當我們需要做腐蝕演算法時,資料取dout_min。
(2)一維形態學膨脹模組設計
我們要完成對nxn視窗的腐蝕或者膨脹首先我們要做影象行的一維腐蝕或膨脹。例如我們要做3x3視窗的腐蝕或膨脹,一維形態學腐蝕或膨脹如圖所示:
(3) 二維形態學腐蝕與膨脹子模組設計
形態學膨脹結果演示:
頂層原始碼:
////////////////////////////////////////////////////////////////
wire[15:0] rgb;
wire hs;
wirevs;
wirede;
wireo_hs;
wireo_vs;
wireo_de;
wire[7 : 0] o_y_8b;
wire[7 : 0] o_cb_8b;
wire[7 : 0] o_cr_8b;
wire[7 : 0] dout;
//assign TFT_rgb ={o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]}; //Y
//assign TFT_rgb = {o_cb_8b[7:3],o_cb_8b[7:2],o_cb_8b[7:3]}; //cb
//assign TFT_rgb ={o_cr_8b[7:3],o_cr_8b[7:2],o_cr_8b[7:3]}; //cr
tft_ctrltft_ctrl(
.Clk9M(clk9M), //系統輸入時鐘9MHZ
.Rst_n(Rst_n), //復位輸入,低電平復位
.data_in({Rd_data[7:0],Rd_data[15:8]}), //待顯示資料
.hcount(), //TFT行掃描計數器
.vcount(), //TFT場掃描計數器
.TFT_RGB(rgb), //TFT資料輸出
.TFT_HS(hs), //TFT行同步訊號
.TFT_VS(vs), //TFT場同步訊號
.TFT_CLK(TFT_clk), //TFT畫素時鐘
.TFT_DE(de), //TFT資料使能
.TFT_begin(tft_begin),
.TFT_PWM(TFT_pwm) //TFT背光控制
);
rgb_to_ycbcr rgb_to_ycbcr_inst(
.clk(TFT_clk),
.i_r_8b({rgb[15:11],3'b0}),
.i_g_8b({rgb[10:5],2'b0}),
.i_b_8b({rgb[4:0],3'b0}),
.i_h_sync(hs),
.i_v_sync(vs),
.i_data_en(de),
.o_y_8b(o_y_8b),
.o_cb_8b(o_cb_8b),
.o_cr_8b(o_cr_8b),
.o_h_sync(o_hs),
.o_v_sync(o_vs),
.o_data_en(o_de)
);
/*
erode erode_inst(
.clk(TFT_clk),
.rst_n(Rst_n),
.hs_in(o_hs),
.vs_in(o_vs),
.din(o_y_8b),
.din_valid(o_de),
.dout(dout),
.dout_valid(TFT_de),
.hs_out(TFT_hs),
.vs_out(TFT_vs)
);
*/
dilatedilate_inst(
.clk(TFT_clk),
.rst_n(Rst_n),
.hs_in(o_hs),
.vs_in(o_vs),
.din(o_y_8b),
.din_valid(o_de),
.dout(dout),
.dout_valid(TFT_de),
.hs_out(TFT_hs),
.vs_out(TFT_vs)
);
assignTFT_rgb = {dout[7:3],dout[7:2],dout[7:3]}; //Y
//assign TFT_rgb ={o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]}; //Y
歡迎大家關注我的微信公眾號:FPGA開源工作室: