FPGA图像处理_形态学滤波实现(含源码)

1、数学形态学的定义
  数学形态学是一门建立在集论基础上的学科,以形态结构元素为基础对图像进行分析的数学工具,它的基本思想是,用具有一定形态的结构元素度量和提取图像中的对应形状,以达到对图像分析和识别的目的。数学形态学的应用可以简化图像数据,保持它们基本的形状特征,并除去不相干的结构。数学形态学的基本运算有4个:膨胀、腐蚀、开运算和闭运算。它们在二值图像中和灰度图像中各有特点。基于这些基本运算还可以推导和组合成各种数学形态学实用算法。
2、分类
1)二值形态学
  数学形态学中二值图像的形态变换是一种针对集合的处理过程。其形态算子的实质是表达物体或形状的集合与结构元素间的相互作用,结构元素的形状就决定了这种运算所提取的信号的形状信息。形态学图像处理是在图像中移动一个结构元素,然后将结构元素与下面的二值图像进行交、并等集合运算。
  二值形态膨胀与腐蚀可转化为集合的逻辑运算,算法简单,适于并行处理,且易于硬件实现,适于对二值图像进行图像分割、细化、抽取骨架、边缘提取、形状分析。但是,在不同的应用场合,结构元素的选择及其相应的处理算法是不一样的,对不同的目标图像需设计不同的结构元素和不同的处理算法。结构元素的大小、形状选择合适与否,将直接影响图像的形态运算结果。因此,很多学者结合自己的应用实际,提出了一系列的改进算法。如梁勇提出的用多方位形态学结构元素进行边缘检测算法,既有较好的边缘定位能力又有很好的噪声平滑能力;徐超提出的以最短线段结构元素构造准圆结构元素或序列结构元素生成准圆结构元素相结合的设计方法,用于骨架的提取,可大大减少形态学运算的计算量,并同时满足尺度、平移及旋转相容性,适于对形状进行分析和描述。
2)灰度数学形态学
  二值数学形态学可方便地推广到灰度图像空间。只是灰度数学形态学的运算对象不是集合而是图像函数。灰度数学形态学中开启和闭合运算的定义与在二值数学形态学中的定义一致。

本文介绍灰度图像形态学滤波的两个基本操作:膨胀和腐蚀,其主要功能包括:消除噪声、分割出独立的图像元素、在图像中连接相邻的元素、寻找图像中明显的极大值和极小值区域以及求出图像的梯度等,其余形态学滤波算法都是膨胀与腐蚀运算的变形。
  膨胀(dilate)就是求局部最大值的操作。从数学角度上来说,膨胀和腐蚀就是将图像(或图像的一部分区域,称之为A)与核(称之为B)进行卷积的一个过程。需要注意的是,核可以是任意的形状和大小,它拥有一个单独定义出来的参考点,我们称之为锚点(anchorpoint)。在多数情况下,核是一个小的中间带有参考点的十字形、实心矩形(一般是正方形)或者圆盘。其实,可以将核视为模板或者掩码。核B与图像卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指点的像素。
  腐蚀(erode)和膨胀是一对对立的操作,因此,腐蚀就是求局部的最小指。关于形态学滤波的原理大家可参考冈萨雷斯《数字图像处理》一书,本文重点介绍代码如何实现卷积核大小为3*3的腐蚀与膨胀运算:
膨胀运算:

`timescale 1ns / 1ps

module VIP_9Bit_Dilation_Detector(
    input               clk   ,
    input               rst_n ,
    input				per_frame_vsync,	//Prepared Image data vsync valid signal
	input				per_frame_href,		//Prepared Image data href vaild  signal
	input				per_frame_clken,	//Prepared Image data output/capture enable clock
	input	[8:0]	    per_img_9Bit,		//Prepared Image Bit flag outout(1: Value, 0:inValid)
    
    //Image data has been processd
	output				post_frame_vsync,	//Processed Image data vsync valid signal
	output				post_frame_href,	//Processed Image data href vaild  signal
	output				post_frame_clken,	//Processed Image data output/capture enable clock
	output	[8:0]	    post_img_9Bit		//Processed Image Bit flag outout(1: Value, 0:inValid)
    );
    
//----------------------------------------------------
//Generate 1Bit 3X3 Matrix for Video Image Processor.消耗2个时钟周期
//Image data has been processd
wire			matrix_frame_vsync;	//Prepared Image data vsync valid signal
wire			matrix_frame_href;	//Prepared Image data href vaild  signal
wire			matrix_frame_clken;	//Prepared Image data output/capture enable clock	
wire	[8:0]	matrix_p11, matrix_p12, matrix_p13;	//3X3 Matrix output
wire	[8:0]	matrix_p21, matrix_p22, matrix_p23;
wire	[8:0]	matrix_p31, matrix_p32, matrix_p33;
    
VIP_Matrix_Generate_3X3_9Bit VIP_Matrix_Generate_3X3_9Bit_inst
(
	//global clock
	.clk              (clk)        ,  				//cmos video pixel clock
	.rst_n            (rst_n)        ,				//global reset

	//Image data prepred to be processd
	.per_frame_vsync   (per_frame_vsync)       ,	//Prepared Image data vsync valid signal
	.per_frame_href    (per_frame_href)       ,		//Prepared Image data href vaild  signal
	.per_frame_clken   (per_frame_clken)       ,	//Prepared Image data output/capture enable clock
	.per_img_Y         (per_img_9Bit)       ,			//Prepared Image brightness input

	//Image data has been processd
	.matrix_frame_vsync  (matrix_frame_vsync)  ,	//Prepared Image data vsync valid signal
	.matrix_frame_href   (matrix_frame_href)  ,	//Prepared Image data href vaild  signal
	.matrix_frame_clken  (matrix_frame_clken)  ,	//Prepared Image data output/capture enable clock	
	.matrix_p11(matrix_p11),.matrix_p12(matrix_p12),.matrix_p13(matrix_p13),	//3X3 Matrix output
	.matrix_p21(matrix_p21),.matrix_p22(matrix_p22),.matrix_p23(matrix_p23),
	.matrix_p31(matrix_p31),.matrix_p32(matrix_p32),.matrix_p33(matrix_p33)
);

//对得到的3*3矩阵进行"卷积"运算   ,膨胀运算扩展到灰度图像中,就是寻找结构体下的最大值进行覆盖
//step1 找出每一行数据的最大值,消耗1个CLK
reg [8:0] max_row1;
reg [8:0] max_row2;
reg [8:0] max_row3;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        max_row1    <=  9'd0;
    else if(matrix_frame_href) begin
        if((matrix_p11 >= matrix_p12) && (matrix_p11 >= matrix_p13))
            max_row1    <=  matrix_p11;
        if((matrix_p12 >= matrix_p11) && (matrix_p12 >= matrix_p13))
            max_row1    <=  matrix_p12;
        if((matrix_p13 >= matrix_p11) && (matrix_p13 >= matrix_p12))
            max_row1    <=  matrix_p13;
     end
     else
        max_row1    <=  max_row1;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        max_row2    <=  9'd0;
    else if(matrix_frame_href) begin
        if((matrix_p21 >= matrix_p22) && (matrix_p21 >= matrix_p23))
            max_row2    <=  matrix_p21;
        if((matrix_p22 >= matrix_p21) && (matrix_p22 >= matrix_p23))
            max_row2    <=  matrix_p22;
        if((matrix_p23 >= matrix_p21) && (matrix_p23 >= matrix_p22))
            max_row2    <=  matrix_p23;
     end
     else
        max_row2    <=  max_row2;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        max_row3    <=  9'd0;
    else if(matrix_frame_href) begin
        if((matrix_p31 >= matrix_p32) && (matrix_p31 >= matrix_p33))
            max_row3    <=  matrix_p31;
        if((matrix_p32 >= matrix_p31) && (matrix_p32 >= matrix_p33))
            max_row3    <=  matrix_p32;
        if((matrix_p33 >= matrix_p31) && (matrix_p33 >= matrix_p32))
            max_row3    <=  matrix_p33;
     end
     else
        max_row3    <=  max_row3;
end

//step2 找出结构体下的最大值
reg [8:0] max;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        max <=  9'd0;
    else if((max_row1 >= max_row2) && (max_row1 >= max_row3))
        max <=  max_row1;
    else if((max_row2 >= max_row1) && (max_row2 >= max_row3))
        max <=  max_row2;
    else if((max_row3 >= max_row1) && (max_row3 >= max_row2))
        max <=  max_row3;
    else
        max <=  max;
end

assign post_img_9Bit = post_frame_href? max : 9'd0;

//控制信号也落后两个时钟周期,保持同步
reg [1:0]   post_frame_vsync_r;
reg [1:0]   post_frame_href_r;
reg [1:0]   post_frame_clken_r;


always @ (posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        post_frame_vsync_r    <=  2'b0;
        post_frame_href_r	  <=  2'b0;
        post_frame_clken_r    <=  2'b0;
    end
    else begin
        post_frame_vsync_r    <=  {post_frame_vsync_r[0],matrix_frame_vsync} ;
        post_frame_href_r	  <=  {post_frame_href_r[0],matrix_frame_href} ;
        post_frame_clken_r    <=  {post_frame_clken_r[0],matrix_frame_clken} ;
    end
end

assign post_frame_vsync = post_frame_vsync_r[1];
assign post_frame_href  = post_frame_href_r[1];
assign post_frame_clken = post_frame_clken_r[1];
endmodule

腐蚀运算:

`timescale 1ns / 1ps

module VIP_9Bit_Erosion_Detector(
    input               clk   ,
    input               rst_n ,
    input				per_frame_vsync,	//Prepared Image data vsync valid signal
	input				per_frame_href,		//Prepared Image data href vaild  signal
	input				per_frame_clken,	//Prepared Image data output/capture enable clock
	input	[8:0]	    per_img_9Bit,		//Prepared Image Bit flag outout(1: Value, 0:inValid)
    
    //Image data has been processd
	output				post_frame_vsync,	//Processed Image data vsync valid signal
	output				post_frame_href,	//Processed Image data href vaild  signal
	output				post_frame_clken,	//Processed Image data output/capture enable clock
	output	[8:0]	    post_img_9Bit		//Processed Image Bit flag outout(1: Value, 0:inValid)
    );

//----------------------------------------------------
//Generate 1Bit 3X3 Matrix for Video Image Processor.
//Image data has been processd
wire			matrix_frame_vsync;	//Prepared Image data vsync valid signal
wire			matrix_frame_href;	//Prepared Image data href vaild  signal
wire			matrix_frame_clken;	//Prepared Image data output/capture enable clock	
wire	[8:0]	matrix_p11, matrix_p12, matrix_p13;	//3X3 Matrix output
wire	[8:0]	matrix_p21, matrix_p22, matrix_p23;
wire	[8:0]	matrix_p31, matrix_p32, matrix_p33;
    
VIP_Matrix_Generate_3X3_9Bit VIP_Matrix_Generate_3X3_9Bit_inst
(
	//global clock
	.clk              (clk)        ,  				//cmos video pixel clock
	.rst_n            (rst_n)        ,				//global reset

	//Image data prepred to be processd
	.per_frame_vsync   (per_frame_vsync)       ,	//Prepared Image data vsync valid signal
	.per_frame_href    (per_frame_href)       ,		//Prepared Image data href vaild  signal
	.per_frame_clken   (per_frame_clken)       ,	//Prepared Image data output/capture enable clock
	.per_img_Y         (per_img_9Bit)       ,			//Prepared Image brightness input

	//Image data has been processd
	.matrix_frame_vsync  (matrix_frame_vsync)  ,	//Prepared Image data vsync valid signal
	.matrix_frame_href   (matrix_frame_href)  ,	//Prepared Image data href vaild  signal
	.matrix_frame_clken  (matrix_frame_clken)  ,	//Prepared Image data output/capture enable clock	
	.matrix_p11(matrix_p11),.matrix_p12(matrix_p12),.matrix_p13(matrix_p13),	//3X3 Matrix output
	.matrix_p21(matrix_p21),.matrix_p22(matrix_p22),.matrix_p23(matrix_p23),
	.matrix_p31(matrix_p31),.matrix_p32(matrix_p32),.matrix_p33(matrix_p33)
);

//对得到的3*3矩阵进行"卷积"运算   ,腐蚀运算扩展到灰度图像中,就是寻找结构体下的最小值进行覆盖
reg [8:0] min_row1;
reg [8:0] min_row2;
reg [8:0] min_row3;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        min_row1    <=  9'd0;
    else if(matrix_frame_href) begin
        if((matrix_p11 <= matrix_p12) && (matrix_p11 <= matrix_p13))
            min_row1    <=  matrix_p11;
        if((matrix_p12 <= matrix_p11) && (matrix_p12 <= matrix_p13))
            min_row1    <=  matrix_p12;
        if((matrix_p13 <= matrix_p11) && (matrix_p13 <= matrix_p12))
            min_row1    <=  matrix_p13;
     end
     else
        min_row1    <=  min_row1;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        min_row2    <=  9'd0;
    else if(matrix_frame_href) begin
        if((matrix_p21 <= matrix_p22) && (matrix_p21 <= matrix_p23))
            min_row2    <=  matrix_p21;
        if((matrix_p22 <= matrix_p21) && (matrix_p22 <= matrix_p23))
            min_row2    <=  matrix_p22;
        if((matrix_p23 <= matrix_p21) && (matrix_p23 <= matrix_p22))
            min_row2    <=  matrix_p23;
     end
     else
        min_row2    <=  min_row2;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        min_row3    <=  9'd0;
    else if(matrix_frame_href) begin
        if((matrix_p31 <= matrix_p32) && (matrix_p31 <= matrix_p33))
            min_row3    <=  matrix_p31;
        if((matrix_p32 <= matrix_p31) && (matrix_p32 <= matrix_p33))
            min_row3    <=  matrix_p32;
        if((matrix_p33 <= matrix_p31) && (matrix_p33 <= matrix_p32))
            min_row3    <=  matrix_p33;
     end
     else
        min_row3    <=  min_row3;
end

//step2 找出结构体下的最小值
reg [8:0] min;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        min <=  9'd0;
    else if((min_row1 <= min_row2) && (min_row1 <= min_row3))
        min <=  min_row1;
    else if((min_row2 <= min_row1) && (min_row2 <= min_row3))
        min <=  min_row2;
    else if((min_row3 <= min_row2) && (min_row3 <= min_row1))
        min <=  min_row3;
    else
        min <=  min;
end

assign post_img_9Bit = post_frame_href? min : 9'd0;

//控制信号也落后两个时钟周期,保持同步
reg [1:0]   post_frame_vsync_r;
reg [1:0]   post_frame_href_r;
reg [1:0]   post_frame_clken_r;


always @ (posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        post_frame_vsync_r    <=  2'b0;
        post_frame_href_r	  <=  2'b0;
        post_frame_clken_r    <=  2'b0;
    end
    else begin
        post_frame_vsync_r    <=  {post_frame_vsync_r[0],matrix_frame_vsync} ;
        post_frame_href_r	  <=  {post_frame_href_r[0],matrix_frame_href} ;
        post_frame_clken_r    <=  {post_frame_clken_r[0],matrix_frame_clken} ;
    end
end

assign post_frame_vsync = post_frame_vsync_r[1];
assign post_frame_href  = post_frame_href_r[1];
assign post_frame_clken = post_frame_clken_r[1];

endmodule

从代码可以看出,腐蚀与膨胀功能的实现并不难,重点在于卷积核如何生成,而这一部分内容,在我的另一篇文章FPGA图像处理_中值滤波实现(含源码)中有详细阐述,本文就介绍到这,谢谢阅读!
参考文献:牟新刚,周晓,郑晓亮.基于FPGA的数字图像处理原理及应用
阮秋琦.数字图像处理(MATLAB版)(第二版)》(本科教学版);

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA图像处理中的高斯滤波是一种常用的图像处理算法,可以用于去除图像中的高频噪声,并平滑图像,使得图像更加清晰和易于分析。这种滤波算法可以通过FPGA技术来实现,以提高图像处理的效率和实时性。 针对传统高斯滤波在保留图像边缘细节方面的不足,研究人员提出了一种基于FPGA的改进高斯滤波算法。这种算法可以在滤除高频噪声的同时,保留图像的边缘信息,并且能够实现高速实时的图像处理。该算法通过对当前图像的像素点与由图像全局求取的梯度阈值进行比对,决定是否对该像素点进行滤波处理。这样可以在保留图像边缘细节的同时,有效地滤除高频噪声。 另外一种方法是采用两个一维的高斯滤波进行两次滤波。首先对图像的行进行一维滤波,然后再对图像的列进行一维滤波。这种方法计算简单,降低了复杂度,同时也可以实现高斯滤波的效果。 综上所述,FPGA图像处理中的高斯滤波是一种有效的图像处理算法,可以提高图像质量和清晰度。同时,通过改进算法和优化计算方式,可以实现高速实时的图像处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [FPGA设计——图像处理(高斯滤波)](https://blog.csdn.net/weixin_34220834/article/details/92310397)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [基于FPGA的图像边缘保护高斯滤波算法实现](https://download.csdn.net/download/weixin_38737335/16690867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [简谈FPGA实现高斯滤波](https://blog.csdn.net/qq_40310273/article/details/113360987)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值