FPGA图像处理(六)------ 图像腐蚀and图像膨胀

默认迭代次数为1,只进行一次腐蚀、膨胀

一、图像腐蚀

1.相关定义 

2.图像腐蚀效果图

 

3.fpga实现 

彩色图像灰度化,灰度图像二值化,图像缓存生成滤波模块(3*3),图像腐蚀算法

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Description: 图像腐蚀 (前景色是黑色(0),背景色是白色(1)  腐蚀黑色)
//////////////////////////////////////////////////////////////////////////////////
module image_erode(
   input wire           clk             ,
   input wire           reset           ,
   
   input wire [10:0]    img_width       ,
   input wire [9:0]     img_height      ,
   
   input wire           valid_i         ,
   input wire [23:0]    last_line_data  ,
   input wire [23:0]    cur_line_data   ,
   input wire [23:0]    next_line_data  ,
   
   output reg           valid_o         ,
   output reg [23:0]    img_data_o
);
    //常量声明
    parameter N = 3; //窗口大小
    //结构系数模版为{1,1,1,
    //              1,1,1,
    //              1,1,1}
 
    //变量声明
    reg         valid_d1;
    reg [23:0]  last_line_data_d1, last_line_data_d2;
    reg [23:0]  cur_line_data_d1 , cur_line_data_d2 ;
    reg [23:0]  next_line_data_d1, next_line_data_d2;

    //中心点位置,为cur_line_data_d1
    always@(posedge clk or posedge reset) begin
        if(reset) begin
            valid_d1 <= 0;
            {last_line_data_d1, last_line_data_d2} <= 0;
            {cur_line_data_d1 , cur_line_data_d2 } <= 0;
            {next_line_data_d1, next_line_data_d2} <= 0;
        end else begin
            valid_d1 <= valid_i;
            last_line_data_d1 <= last_line_data;
            last_line_data_d2 <= last_line_data_d1;
            cur_line_data_d1  <= cur_line_data;
            cur_line_data_d2  <= cur_line_data_d1;
            next_line_data_d1 <= next_line_data;
            next_line_data_d2 <= next_line_data_d1;
        end
    end

    //模板窗口范围内判断,前景色是黑色,背景色是白色,腐蚀处理就是前景色黑色减少
    //简单理解也就是,3*3窗口中所有像素值都是0时,才能将当前像素值为0输出

    always@(posedge clk or posedge reset) begin
        if(reset) begin
            valid_o <= 0;
            img_data_o <= 0;
        end 
        else if(valid_d1) begin
            if({last_line_data_d2, last_line_data_d1, last_line_data,
                cur_line_data_d2 , cur_line_data_d1 , cur_line_data ,
                next_line_data_d2, next_line_data_d1, next_line_data} == {27{8'd0}}) begin

                img_data_o <= cur_line_data_d1;
                    
            end 
            else begin
                img_data_o <= {3{8'd255}};   
            end
            valid_o <= 1'b1;
        end 
        else begin
            valid_o <= 0;
            img_data_o <= 0;
        end
    end
      
endmodule

明显可以看书汉字部分,经过腐蚀运算之后,白色字体变宽了(要是清晰显示文字,应该腐蚀白色,效果可能更好一点) 


二、图像膨胀

1.相关定义

 2.图像膨胀与图像腐蚀的联系

 3.FPGA实现

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Description: 图像膨胀 (前景色是黑色,背景色是白色  只要覆盖区域有前景色则膨胀黑色)
//////////////////////////////////////////////////////////////////////////////////
module image_dilate(
   input  wire          clk             ,
   input  wire          reset           ,
    
   input  wire [10:0]   img_width       ,
   input  wire [9:0]    img_height      ,
    
   input  wire          valid_i         ,
   input  wire [23:0]   last_line_data  ,
   input  wire [23:0]   cur_line_data   ,
   input  wire [23:0]   next_line_data  , 
   
   output reg           valid_o         ,
   output reg [23:0]    img_data_o      
);
    //常量声明
    parameter N = 3; //窗口大小
    //结构系数模版为{1,1,1,1,1,1,1,1,1}

    //变量声明
    reg valid_d1;
    reg [23:0] last_line_data_d1, last_line_data_d2;
    reg [23:0] cur_line_data_d1 , cur_line_data_d2 ;
    reg [23:0] next_line_data_d1, next_line_data_d2;

    //中心点位置,为cur_line_data_d1
    always@(posedge clk or posedge reset) begin
        if(reset) begin
            valid_d1 <= 0;
            {last_line_data_d1, last_line_data_d2} <= 0;
            {cur_line_data_d1 , cur_line_data_d2 } <= 0;
            {next_line_data_d1, next_line_data_d2} <= 0;
        end else begin
            valid_d1 <= valid_i;
            last_line_data_d1 <= last_line_data;
            last_line_data_d2 <= last_line_data_d1;
            cur_line_data_d1  <= cur_line_data;
            cur_line_data_d2  <= cur_line_data_d1;
            next_line_data_d1 <= next_line_data;
            next_line_data_d2 <= next_line_data;
        end
    end

    //模板窗口范围内判断,前景色是黑色,背景色是白色,膨胀处理就是前景色黑色扩张
    //简单理解也就是,3*3窗口中所有像素值都是255(白)时,才能将当前像素值为255输出
    always@(posedge clk or posedge reset) begin
        if(reset) begin
            valid_o <= 0;
            img_data_o <= 0;
        end else if(valid_d1) begin
            if({last_line_data_d2, last_line_data_d1, last_line_data,
                cur_line_data_d2 , cur_line_data_d1 , cur_line_data ,
                next_line_data_d2, next_line_data_d1, next_line_data} == {27{8'd255}}) begin

                img_data_o <= cur_line_data_d1;
                    
            end else begin
                img_data_o <= 0;   
            end
            valid_o <= 1'b1;
        end else begin
            valid_o <= 0;
            img_data_o <= 0;
        end
    end

endmodule

 三、图像处理的开运算,闭运算和梯度运算

1.相关定义 

2.fpga实现 

开运算:

闭运算 :

梯度运算:

module image_process_top(
   input wire clk,
   input wire reset,
   
   input wire [10:0] img_width,
   input wire [9:0] img_height,
   
   input wire valid_i,
   input wire [23:0] img_data_i,
   
   output wire valid_o,
   output wire [23:0] img_data_o
    );

    //参数定义
    wire rgb2gray_valid;
    wire [23:0] rgb2gray_data;

    wire binary_valid;
    wire [23:0] binary_data;

    wire line_valid;
    wire [23:0] last_line_data, cur_line_data, next_line_data;
    
    wire erode_valid;
    wire [23:0] erode_data;
    
    wire dilate_valid;
    wire [23:0] dilate_data;
    
    wire line1_valid;
    wire [23:0] last_line1_data, cur_line1_data, next_line1_data;
    
    //灰度化处理
    image_rgb2gray u_image_rgb2gray(
    .clk        ( clk        ),
    .reset      ( reset      ),
    .valid_i    ( valid_i    ),
    .img_data_i ( img_data_i ),
    .valid_o    ( rgb2gray_valid    ),
    .img_data_o  ( rgb2gray_data  )
    );


    //二值化处理
     image_binary u_image_binary(
    .clk        ( clk        ),
    .reset      ( reset      ),
    .valid_i    ( rgb2gray_valid    ),
    .img_data_i ( rgb2gray_data ),
    .valid_o    ( binary_valid    ),
    .img_data_o  ( binary_data  )
    );

    //////////////////////////开运算
/*
    //3行缓存
    image_line_buffer u_image_line_buffer(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( binary_valid ),
    .img_data_i     ( binary_data ),
    .valid_o        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data  ( next_line_data  )
    );


    //图像腐蚀
    image_erode u_image_erode(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data ( next_line_data ),
    .valid_o        ( erode_valid    ),
    .img_data_o     ( erode_data     )
    );

    //3行缓存
    image_line_buffer u_image_line_buffer1(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( erode_valid ),
    .img_data_i     ( erode_data ),
    .valid_o        ( line1_valid        ),
    .last_line_data ( last_line1_data ),
    .cur_line_data  ( cur_line1_data  ),
    .next_line_data  ( next_line1_data  )
    );

    //图像膨胀
    image_dilate u_image_dilate(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( line1_valid        ),
    .last_line_data ( last_line1_data ),
    .cur_line_data  ( cur_line1_data  ),
    .next_line_data ( next_line1_data ),
    .valid_o        ( valid_o        ),
    .img_data_o     ( img_data_o     )
    );
*/

    //////////////////////////闭运算
/*
    //3行缓存
    image_line_buffer u_image_line_buffer(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( binary_valid ),
    .img_data_i     ( binary_data ),
    .valid_o        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data  ( next_line_data  )
    );


    //图像膨胀
    image_dilate u_image_dilate(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data ( next_line_data ),
    .valid_o        ( dilate_valid    ),
    .img_data_o     ( dilate_data     )
    );

    //3行缓存
    image_line_buffer u_image_line_buffer1(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( dilate_valid ),
    .img_data_i     ( dilate_data ),
    .valid_o        ( line1_valid        ),
    .last_line_data ( last_line1_data ),
    .cur_line_data  ( cur_line1_data  ),
    .next_line_data  ( next_line1_data  )
    );

    //图像腐蚀
    image_erode u_image_erode(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( line1_valid        ),
    .last_line_data ( last_line1_data ),
    .cur_line_data  ( cur_line1_data  ),
    .next_line_data ( next_line1_data ),
    .valid_o        ( valid_o        ),
    .img_data_o     ( img_data_o     )
    );
*/

    //////////////////////////梯度运算

    //3行缓存
    image_line_buffer u_image_line_buffer(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( binary_valid ),
    .img_data_i     ( binary_data ),
    .valid_o        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data  ( next_line_data  )
    );


    //图像膨胀
    image_dilate u_image_dilate(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data ( next_line_data ),
    .valid_o        ( dilate_valid    ),
    .img_data_o     ( dilate_data     )
    );

    //图像腐蚀
    image_erode u_image_erode(
    .clk            ( clk            ),
    .reset          ( reset          ),
    .img_width      ( img_width      ),
    .img_height     ( img_height     ),
    .valid_i        ( line_valid        ),
    .last_line_data ( last_line_data ),
    .cur_line_data  ( cur_line_data  ),
    .next_line_data ( next_line_data ),
    .valid_o        ( erode_valid    ),
    .img_data_o     ( erode_data     )
    );

    assign valid_o = dilate_valid;
    assign img_data_o = (dilate_data == 0)&&(erode_data == {3{8'd255}}) ? 0 : {3{8'd255}};

endmodule

### 如何用Verilog 实现图像处理中的腐蚀膨胀算法 #### 腐蚀膨胀基本原理 在图像处理中,腐蚀膨胀属于形态学操作的一部分。这些操作通常用于修改图像的形状特征,如去除噪声、细化或加粗边界等。具体来说: - **腐蚀**是指对于每一个像素点,如果该点及其邻域内的所有像素都满足一定条件,则保留此点;否则将其置零。 - **膨胀**则是指只要有一个相邻像素符合条件就设置当前像素为有效。 这两种变换可以通过定义一个称为“结构元素”的小模板来进行[^1]。 #### FPGA 上的 Verilog 实现方法 为了高效地执行上述两种运算,在FPGA平台上可以利用其高度并行化的特性来加速计算过程。以下是具体的实现思路: ##### 数据流控制逻辑 考虑到输入数据可能来自外部存储器或其他IP核(比如Sobel算子的结果),因此需要先建立好合适的数据传输路径以及同步机制。特别是当涉及到多帧连续处理时更要注意这一点[^2]。 ##### 结构体定义与移位寄存器 针对特定大小的结构元(例如3×3矩阵),可以在代码内部创建相应维度的状态机或者移位RAM (Shift-RAM),以便于快速访问周围邻居节点的信息。这有助于简化后续比较判断语句的设计难度[^4]。 ```verilog // 定义3x3结构元素作为参数传递给模块 parameter STRUCTURE_ELEMENT_SIZE = 9; wire [STRUCTURE_ELEMENT_SIZE-1:0] structure_element; reg [7:0] shift_reg [8:0]; // 创建9个8-bit宽的移位寄存器实例 integer i; always @(posedge clk or negedge rst_n) begin : SHIFT_REG_INIT if (!rst_n) for(i=0;i<9;i=i+1) shift_reg[i] <= 8'b0; end ``` ##### 并行处理单元 因为每次只需要考虑局部区域内的几个固定位置关系即可完成一次完整的腐蚀/膨胀判定工作,所以非常适合采用流水线技术进一步提升吞吐量。同时也可以根据实际需求调整不同阶段之间的延迟时间差以达到最佳性能表现[^3]。 ```verilog module erosion_dilation( input wire clk, input wire rst_n, input wire ena, // enable signal input wire [7:0] pixel_in,// 输入单个像素值 output reg [7:0] result // 输出结果 ); parameter WIDTH = 3; // 结构元素宽度 // ...省略部分初始化代码... always @(*) begin case(state) EROSION: begin // 执行腐蚀操作的具体逻辑 // 假设structure_match表示匹配状态 result = structure_match ? pixel_in : 8'b0; end DILATION: begin // 执行膨胀操作的具体逻辑 // 同样假设structure_hit代表命中情况 result = structure_hit | pixel_in; end endcase end endmodule ``` 以上展示了如何使用Verilog编写一段能够运行在FPGA上的程序片段,用来分别实施腐蚀膨胀这两个重要的形态学滤波功能。当然这只是非常基础的例子,真实应用场景可能会更加复杂一些,包括但不限于支持更大尺寸的结构元素、优化资源利用率等方面的工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值