基于FPGA灰度图像的形态学膨胀算法的实现

谁说我不能喝 提交于 2021-02-12 04:27:49

基于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膨胀源码:

%%image dilate

clc

clear all

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:       137194782@qq.com

*/

`timescale 1ns/1ps

module minmax(

      clk,  //pixel clock

   rst_n,

   data_valid,

   din,

   din_r,

   dout_min,

   dout_max

   );

parameter WIDTH = 8; // data width 8 bit  

parameter USE_REG = 1; // USE_REG = 1 Data delay 1ns output.  USE_REG = 0 Don't delay.   

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;     

wire minmax_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

assign minmax_flag = (din > din_r) ? 1'b1:1'b0;

// min

assign min_temp = (minmax_flag == 1'b1) ? din_r : din;

// max

assign max_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:             

*/

`timescale 1ns/1ps

`define WIDTH 8

`define CLK_PERIOD 10

module minmax_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;

minmax minmax_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;  

always @(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

always @(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;

wire vs;

wire de;

 

wire o_hs;

wire o_vs;

wire o_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_ctrl tft_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)

);

*/

dilate dilate_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)

);

assign TFT_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开源工作室(leezym0317)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!