基于FPGA灰度图像的形态学腐蚀

余生颓废 提交于 2021-02-12 04:37:52

FPGA开源工作室

FPGA/图像处理/创业/职场

关注


基于FPGA灰度图像的形态学腐蚀

01

背景知识


数学形态学是一门建立在集论基础上的学科,是几何形态学分析和描述的有力工具。数学形态学的蓬勃发展,其并行快速,易于硬件实现,目前已经在计算机视觉、信号处理与图像分析、模式识别等方面得到了极为广泛的应用。

    腐蚀与膨胀是形态学滤波的两个基本运算,通过腐蚀和膨胀两种运算可以实现多种功能,主要如下:

(1) 消除噪声;

(2)分割出独立的图像元素;

(3)在图像中连接相邻的元素;

(4)寻找图像中明显的极大值和极小值区域;

(5)求出图像的梯度。

 


1 腐蚀膨胀示意图

1 a为大小为448X425像素的灰度级X射线图像;b使用半径为2个像素的圆盘形结构元对图像的腐蚀结果;c用相同的结构元对图像的膨胀结果。原图有Lixi公司提供。

形态学滤波之腐蚀

  腐蚀(erode)就是求局部最小值的操作。

从数学角度来看就是将图像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)表示作用域。

02

Matlab腐蚀源码


%%image erode

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 = imerode(img_b,a);

figure,imshow(img_c);

title('img_c 3x3');

img_d = imerode(img_b,b);

figure,imshow(img_d);

title('img_d 5x5');

img_e = imerode(img_b,c);

figure,imshow(img_e);

title('img_e 7x7');

matlab形态学腐蚀效果


 

 

03

FPGA实现形态学灰度图像腐蚀


 



3.1 腐蚀模块的设计

1)比较子模块

2)一维形态学腐蚀子模块

3)二维形态学腐蚀子模块

1) 比较子模块

为了代码更好的移植,我们将比较子模块设计为独立的子模块。

Erode:输出俩个数据的较小值。

 


(2)一维形态学腐蚀膨胀模块设计

我们要完成对nxn窗口的腐蚀或者膨胀首先我们要做图像行的一维腐蚀或膨胀。例如我们要做3x3窗口的腐蚀或膨胀,一维形态学腐蚀或膨胀如图所示:

 


(3) 二维形态学腐蚀与膨胀子模块设计

 


Erode模块源码


/*

Module name:  erode.v

Description:  

*/

`timescale 1ns/1ps

module erode(

       clk,

 rst_n,

 din,

 din_valid,

 dout,

 dout_valid,

 hs_in,

 vs_in,

 hs_out,

 vs_out

 );

parameter WIDTH = 8; // data bits is 8

parameter KSZ = 3;   // window 3x3

parameter ERO_DIL = 1; //ERO_DIL = 1 erode ;ERO_DIL = 0 dilate.

parameter IMG_WIDTH = 480; //image width 480

input clk;

input rst_n;

input [WIDTH-1:0] din;

input din_valid;

output [WIDTH-1:0] dout;

output dout_valid;

input hs_in;

input vs_in;

output hs_out;

output vs_out;

wire [WIDTH-1:0] morph1d_out;

wire  morph1d_data_valid;

wire [WIDTH-1:0] line_out[0:KSZ-1];

wire  line_data_valid[0:KSZ-1];

wire [WIDTH-1:0] min[0:KSZ-1];

wire [WIDTH-1:0] max[0:KSZ-1];

//------------------------------------------------------------------------------------

// instantiate a one-dimensional morphology erode or dilate

//------------------------------------------------------------------------------------

morph_1d #(WIDTH,KSZ,ERO_DIL)

      morph_1d_inst(

   .rst_n(rst_n),

.clk(clk),

.din(din),

.hs_in(hs_in),

.vs_in(vs_in),

.hs_out(hs_out),

.vs_out(vs_out),

.din_valid(din_valid),

.dout_valid(morph1d_data_valid),

.dout(morph1d_out)

);

//------------------------------------------------------

//ERO_DIL == 1 morphology erode

//-------------------------------------------------------

generate

  if(ERO_DIL == 1)

  begin: xhdl0

  assign min[0] = morph1d_out;

  assign line_data_valid[0]= morph1d_data_valid;

  genvar i;

  for(i = 0; i< KSZ -1; i = i + 1)

  begin :buf_line1_inst

    line_buffer #(WIDTH,IMG_WIDTH,9)

      line_buffer_inst(

        .rst_n(rst_n),

     .clk(clk),

     .din(min[i]),

     .dout(line_out[i+1]),

     .wr_en(line_data_valid[i]),

  .data_valid(line_data_valid[i+1])

     );

    minmax #(WIDTH,1)

     minmax_i(

      .clk(clk),  //pixel clock

   .rst_n(rst_n),

   .data_valid(line_data_valid[i+1]),

   .din(morph1d_out),

   .din_r(line_out[i+1]),

   .dout_min(min[i+1]),

   .dout_max(max[i+1])

   );

end

   assign dout = min[KSZ-1];

   assign   dout_valid = line_data_valid[KSZ-1];

end

endgenerate

//-------------------------------------------------------------------

// ERO_DIL == 0  morphology dilate

//------------------------------------------------------------------

generate

  if(~(ERO_DIL == 1))

  begin: xhdl1

  assign max[0] = morph1d_out;

  assign line_data_valid[0]= morph1d_data_valid;

  genvar i;

  for(i = 0; i< KSZ -2; i = i + 1)

  begin :buf_line1_inst

    line_buffer #(WIDTH,IMG_WIDTH,9)

      line_buffer_inst(

        .rst_n(rst_n),

     .clk(clk),

     .din(max[i]),

     .dout(line_out[i+1]),

     .wr_en(line_data_valid[i]),

  .data_valid(line_data_valid[i+1])

     );

  end

  begin :buf_cmp_inst

    minmax #(WIDTH,1)

     minmax_i(

      .clk(clk),  //pixel clock

   .rst_n(rst_n),

   .data_valid(line_data_valid[i+1]),

   .din(morph1d_out),

   .din_r(line_out[i+1]),

   .dout_min(min[i+1]),

   .dout_max(max[i+1])

   );

  end

   assign dout = max[i+1];

   assign   dout_valid = line_data_valid[i+1];

  end

endgenerate

endmodule

 

形态学腐蚀结果演示


 

NEWS


推荐阅读

                 《基于FPGA的二值图像的腐蚀算法的实现


欢迎留言提出您宝贵的意见

总之岁月漫长而我们值得等待。


 

 

 

 


本文分享自微信公众号 - FPGA开源工作室(leezym0317)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

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