【FPGA图像处理实战】- 图像膨胀

作者:FPGA入门到精通

图像膨胀算法是形态学图像处理中的一种基本操作,类似于“领域被扩张”的过程,与图像腐蚀相反。

这种操作可以将图像中的前景色进行扩张,其运行结果比原图的区域更大,适用于二值化图像。

本文介绍一下图像膨胀算法的基本原理、Python实现以及FPGA实现。

老规矩:源码在文章末尾

一、图像膨胀算法

1、基本原理

膨胀的运算符号是“⊕”,其运算规则是:A⊕B={x∣Bx∩A≠∅},该公式表示图像A用卷积模板B来进行膨胀处理。

注意这里要区分,不然分不清楚图像腐蚀和图像膨胀:

一幅二值图像的前景色和背景色,前景色可以是黑色,对应背景色是白色,前景色也可以是白色,对应背景色是黑色,图像膨胀和图像腐蚀处理的是前景色,也就是前景色会扩张或缩小。

这里给一个通俗点的膨胀过程解释:

(1)在执行膨胀操作时,我们通常选择一个小的结构元素(例如3x3或5x5的窗口),然后遍历整个图像。

(2)对于图像中的每一个像素点,对应结构元素的中心点。

(3)如果白色是前景,黑色是背景,那么膨胀操作时,检查原图像与结构元素覆盖区域中所有像素点,如果覆盖区域中有前景色白色像素点,则将这个中心点像素填入白色,这样就会图形边界会扩张,只有覆盖区域所有像素点的都是背景色黑色,才能保持这个像素的黑色值。

如果黑色是前景,白色是背景,那么膨胀操作时,检查原图像与结构元素覆盖区域中所有像素点,如果覆盖区域中有前景色黑色像素点,则将这个中心点像素填入黑色,这样就会图形边界会扩张,只有覆盖区域所有像素点的都是背景色白色,才能保持这个像素的白色值。

B结构元素是3*3窗口,示例如下:

B结构元素.JPG

红色框中的为中心点,值为1的表示结构元素的有效覆盖区域,为0表示不需要考虑的点。

通过上面这个分析解释,相信大家应该很容理解图像膨胀了。

2、应用场景

膨胀操作通常用来填补目标区域中的某些空洞、扩大物体的边界等。

填补空洞:图像中可能存在一些空洞区域,膨胀操作可以帮助我们填补这些区域,使得物体的边界更加完整。这种方法在图像分割、边缘检测和形状分析等任务中非常有用。

连接相邻元素:在图像中,可能存在一些断裂的线段或者区域。通过膨胀操作,可以扩大这些元素的边界,使得断裂的部分连接在一起,从而实现图像的修复。

二、Python实现

1、图像膨胀函数

dst = cv2.dilate(src,kernel,anchor,iterations)

函数参数说明:

(1)dst,目标图像

(2)src,原图像

(3)kernel,腐蚀操作的结构元素,默认为一个简单的 3x3 矩

(4)anchor,默认为Point(-1,-1),结构元素中心点,可以忽略

(5)iterations,迭代次数,默认值1

注意:opencv中默认图像的背景色是黑色

2、实现代码

import cv2import numpy as np
img = cv2.imread('1280_720.bmp')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
erode_img = cv2.dilate(img, kernel=np.ones((2, 2), np.uint8),                      iterations=3)
cv2.namedWindow("orignal", 0)cv2.resizeWindow("orignal", 300, 180)  # 设置窗口大小cv2.namedWindow("erode", 0)cv2.resizeWindow("erode", 300, 180)  # 设置窗口大小cv2.imshow('orignal', img)cv2.imshow('erode', erode_img)
cv2.waitKey(0)cv2.destroyAllWindows()

3、运行结果

运行结果.JPG

背景色是黑色,前景色是白色,从图中可以看出,图像膨胀后的图像,白色区域有扩张,黑色区域有明显减少。

三、FPGA实现

1、实现逻辑分析

图像膨胀的实现,需要多个算法模块才能实现,包括灰度二值化、3行缓存、图像膨胀算法模块。

图像膨胀.JPG

大家可以将前面学习的算法模块,拿过来串联一起就行,可以实现流水线式的图像处理。

我这里按照二值化图像一般认为黑色是前景色,白色是背景色来处理。

这里分析一下图像膨胀模块的实现关键逻辑:

图像膨胀采用模版1的结构化系数模版,那就可以简单理解为,只有3*3窗口中所有像素值都是255时,才能将当前像素值为255输出,其余全部为0,这样前景色黑色区域就扩张了。

2、FPGA实现关键源码

module image_dilate(
   input wire clk,
   input wire reset,   
   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

3、仿真测试结果图

仿真测试结果图.JPG

文章来源:FPGA入门到精通

最新文章

最新文章