基于Sobel算子的图像边缘检测

  索贝尔算子(Sobeloperator)主要用于获得数字图像的一阶梯度,是一种离散性差分算子。它是prewitt算子的改进形式,改进之处在于sobel算子认为,邻域的像素对当前像素产生的影响不是等价的,所以距离不同的像素具有不同的权值,对算子结果产生的影响也不同。一般来说,距离越远,产生的影响越小。

  在边缘检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边缘的 ;另一个是检测垂直边缘的 。与Prewitt算子相比,Sobel算子对于象素的位置的影响做了加权,可以降低边缘模糊程度,因此效果更好。
Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边缘的 ,另一个是检测垂直边缘的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。将Sobel算子矩阵中的所有2改为根号2,就能得到各向同性Sobel的矩阵。

  Sobel算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:

  

  图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小:

                   

  可大略的简化成:

                  

  根据该公式可以编写Verilog代码,难点主要在于3*3矩阵的构建。笔者这里是通过使用两个FIFO来进行矩阵构建的,具体代码如下:

  Sobel_Edge.v

  1 //**************************************************************************
  2 // *** file name      : Sobel_Edge.v
  3 // *** version        : 1.0
  4 // *** Description    : Sobel algorithm for edge detection
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.08.18
  8 // *** Changes        : Initial
  9 //**************************************************************************
 10 `timescale 1ns/1ps
 11 module Sobel_Edge
 12 #(
 13     parameter                    THRESHOLD = 40
 14 )
 15 (
 16     input                        i_sys_clk          ,
 17     input                        i_sys_rstn         ,
 18     input                        i_frame_rst        ,
 19     input                        i_edge_en          ,
 20     input            [9:0]       i_s_stream_data    ,
 21     input                        i_s_stream_valid   ,
 22     output                       o_s_stream_ready   ,
 23     output           [25:0]      o_m_stream_data    ,
 24     output                       o_m_stream_valid   ,
 25     input                        i_m_stream_ready
 26 );
 27 
 28     wire                        w_rst_all          ;
 29     wire                        w_valid            ;
 30     wire            [9:0]       w_matrix_00        ;
 31     wire            [9:0]       w_matrix_10        ;
 32     wire            [9:0]       w_matrix_20        ;
 33     wire            [9:0]       w_matrix_10T       ;
 34     wire            [9:0]       w_matrix_20T       ;
 35     wire                        w_line0_rd         ;
 36     wire                        w_line1_rd         ;
 37     wire                        w_line2_rd         ;
 38     wire                        w_empty            ;
 39     wire                        w_prog_full        ;
 40 
 41     reg                         r_1st_line_en      ;
 42     reg                         r_2rd_line_en      ;
 43     reg                         r_edge_en          ;
 44     reg              [9:0]      r_matrix_01        ;
 45     reg              [9:0]      r_matrix_02        ;
 46     reg              [9:0]      r_matrix_11        ;
 47     reg              [9:0]      r_matrix_12        ;
 48     reg              [9:0]      r_matrix_21        ;
 49     reg              [9:0]      r_matrix_22        ;
 50 
 51     assign w_rst_all   = i_frame_rst & (~i_sys_rstn);
 52     assign w_valid     = o_s_stream_ready & i_s_stream_valid;
 53     assign w_matrix_00 = i_s_stream_data;
 54 
 55     always@(posedge i_sys_clk)
 56     begin
 57         r_edge_en <= i_edge_en;
 58     end
 59 /******************************************************************************\
 60 Generate 3 * 3 matrix
 61 \******************************************************************************/
 62     assign w_line0_rd = w_valid;
 63     assign w_line1_rd = w_valid & r_1st_line_en;
 64     assign w_line2_rd = w_valid & r_2rd_line_en;
 65 
 66     always@(posedge i_sys_clk)
 67     begin
 68         if(w_rst_all)
 69         begin
 70             r_1st_line_en <= 'd0;
 71             r_2rd_line_en <= 'd0;
 72         end
 73         else if(w_valid & w_matrix_00[8])
 74         begin
 75             r_1st_line_en <= 1'b1;
 76             r_2rd_line_en <= r_1st_line_en;
 77         end
 78     end
 79 
 80     fifo_2048x10 row1_fifo
 81     (
 82         .clk             (i_sys_clk             ),
 83         .srst            (w_rst_all             ),
 84         .din             (w_matrix_00           ),
 85         .wr_en           (w_line0_rd            ),
 86         .dout            (w_matrix_10T          ),
 87         .rd_en           (w_line1_rd            ),
 88         .full            (                      ),
 89         .empty           (                      )
 90     );
 91     fifo_2048x10 row2_fifo
 92     (
 93         .clk             (i_sys_clk             ),
 94         .srst            (w_rst_all             ),
 95         .din             (w_matrix_10T          ),
 96         .wr_en           (w_line1_rd            ),
 97         .dout            (w_matrix_20T          ),
 98         .rd_en           (w_line2_rd            ),
 99         .full            (                      ),
100         .empty           (                      )
101     );
102     assign w_matrix_10 = w_line1_rd ? w_matrix_10T : w_matrix_00;
103     assign w_matrix_20 = w_line2_rd ? w_matrix_20T : w_matrix_10;
104 
105     always@(posedge i_sys_clk)
106     begin
107         if(w_valid)
108         begin
109             r_matrix_01 <= w_matrix_00;
110             r_matrix_11 <= w_matrix_10;
111             r_matrix_21 <= w_matrix_20;
112 
113             r_matrix_02 <= r_matrix_01;
114             r_matrix_12 <= r_matrix_11;
115             r_matrix_22 <= r_matrix_21;
116         end
117     end
118 /******************************************************************************\
119 Data processing
120 \******************************************************************************/
121     wire            [11:0]        w_add_x0      ;
122     wire            [11:0]        w_add_x2      ;
123     wire            [11:0]        w_add_y0      ;
124     wire            [11:0]        w_add_y2      ;
125     wire            [11:0]        w_abs_x       ;
126     wire            [11:0]        w_abs_y       ;
127     wire            [12:0]        w_abs_add     ;
128     wire            [9:0]         w_fifo_out    ;
129     reg             [9:0]         r_fifo_din    ;
130     reg                           r_fifo_wr     ;
131 
132     assign w_add_x0  = {1'b0,w_matrix_00} + {r_matrix_01,1'b0} + {1'b0,r_matrix_02};    //First row
133     assign w_add_x2  = {1'b0,w_matrix_20} + {r_matrix_21,1'b0} + {1'b0,r_matrix_22};    //Third row
134     assign w_add_y0  = {1'b0,w_matrix_00} + {w_matrix_10,1'b0} + {1'b0,w_matrix_20};    //First column
135     assign w_add_y2  = {1'b0,r_matrix_02} + {r_matrix_12,1'b0} + {1'b0,r_matrix_22};    //Third column
136 
137     assign w_abs_x   = w_add_x0 > w_add_x2 ? w_add_x0 - w_add_x2 : w_add_x2 - w_add_x0;
138     assign w_abs_y   = w_add_y0 > w_add_y2 ? w_add_y0 - w_add_y2 : w_add_y2 - w_add_y0;
139     assign w_abs_add = w_abs_x + w_abs_y;
140 
141     always@(posedge i_sys_clk)
142     begin
143         if(w_rst_all)
144         begin
145             r_fifo_din <= 'd0;
146             r_fifo_wr  <= 'd0;
147         end
148         else if(r_edge_en)
149         begin
150             r_fifo_din <= (w_abs_add > THRESHOLD) ? {w_matrix_00[9:8],8'h00} : {w_matrix_00[9:8],8'hff};
151             r_fifo_wr  <= w_valid;
152         end
153         else
154         begin
155             r_fifo_din <= w_matrix_00;
156             r_fifo_wr  <= w_valid;
157         end
158     end
159 
160     fifo_2048x10_f2000 dout_fifo
161     (
162         .clk                 (i_sys_clk            ),
163         .srst                (w_rst_all            ),
164         .din                 (r_fifo_din           ),
165         .wr_en               (r_fifo_wr            ),
166         .dout                (w_fifo_out           ),
167         .rd_en               (i_m_stream_ready     ),
168         .full                (                     ),
169         .empty               (w_empty              ),
170         .prog_full           (w_prog_full          )
171     );
172     assign o_m_stream_data  = {w_fifo_out,w_fifo_out[7:0],w_fifo_out[7:0]};
173     assign o_m_stream_valid = ~w_empty & i_m_stream_ready;
174     assign o_s_stream_ready = ~w_prog_full;
175 endmodule

  笔者的工程是用OV5640的1280*720的分辨率做的实验,所以这里要保证图像数据的完整性,则FIFO的深度必须要大于或者等于一行有效像素(这里为1280)的数值。这里说明下,笔者输入的数据是有RGB转换成YUV的Y通道的8bit数据,其中高2位分别为:每帧图像的第一个像素点,每行像素的最后一点。该代码是可能会有点缺陷,每帧图像的前两行及前两列的数据可能会有一些问题。实际显示可能不是很明显,甚至可以忽略。

  实验结果如下,第一张图为YUV中Y通道的显示结果,第二图为Sobel边缘检测后的结果。

  Y通道数据图像显示:

  Sobel处理后的图像显示:

  实验成功

posted on 2022-09-21 14:21  Galois_V  阅读(668)  评论(0编辑  收藏  举报