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

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

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

  

susan算子检测边缘点python 检测边缘的sobel算子_数据

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

                   

susan算子检测边缘点python 检测边缘的sobel算子_数据_02

  可大略的简化成:

                  

susan算子检测边缘点python 检测边缘的sobel算子_susan算子检测边缘点python_03

  根据该公式可以编写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.*****.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

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

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

  Y通道数据图像显示:

susan算子检测边缘点python 检测边缘的sobel算子_susan算子检测边缘点python_04

  Sobel处理后的图像显示:

susan算子检测边缘点python 检测边缘的sobel算子_susan算子检测边缘点python_05

  实验成功