1 Sobel Derivatives {#tutorial_sobel_derivatives} 2 ================= 3 4 Goal 5 ---- 6 7 In this tutorial you will learn how to: 8 9 - Use the OpenCV function @ref cv::Sobel to calculate the derivatives from an image. 10 - Use the OpenCV function @ref cv::Scharr to calculate a more accurate derivative for a kernel of 11 size \f$3 \cdot 3\f$ 12 13 Theory 14 ------ 15 16 @note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. 17 18 -# In the last two tutorials we have seen applicative examples of convolutions. One of the most 19 important convolutions is the computation of derivatives in an image (or an approximation to 20 them). 21 -# Why may be important the calculus of the derivatives in an image? Let's imagine we want to 22 detect the *edges* present in the image. For instance: 23 24  25 26 You can easily notice that in an *edge*, the pixel intensity *changes* in a notorious way. A 27 good way to express *changes* is by using *derivatives*. A high change in gradient indicates a 28 major change in the image. 29 30 -# To be more graphical, let's assume we have a 1D-image. An edge is shown by the "jump" in 31 intensity in the plot below: 32 33  34 35 -# The edge "jump" can be seen more easily if we take the first derivative (actually, here appears 36 as a maximum) 37 38  39 40 -# So, from the explanation above, we can deduce that a method to detect edges in an image can be 41 performed by locating pixel locations where the gradient is higher than its neighbors (or to 42 generalize, higher than a threshold). 43 -# More detailed explanation, please refer to **Learning OpenCV** by Bradski and Kaehler 44 45 ### Sobel Operator 46 47 -# The Sobel Operator is a discrete differentiation operator. It computes an approximation of the 48 gradient of an image intensity function. 49 -# The Sobel Operator combines Gaussian smoothing and differentiation. 50 51 #### Formulation 52 53 Assuming that the image to be operated is \f$I\f$: 54 55 -# We calculate two derivatives: 56 -# **Horizontal changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{x}\f$ with odd 57 size. For example for a kernel size of 3, \f$G_{x}\f$ would be computed as: 58 59 \f[G_{x} = \begin{bmatrix} 60 -1 & 0 & +1 \\ 61 -2 & 0 & +2 \\ 62 -1 & 0 & +1 63 \end{bmatrix} * I\f] 64 65 -# **Vertical changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{y}\f$ with odd 66 size. For example for a kernel size of 3, \f$G_{y}\f$ would be computed as: 67 68 \f[G_{y} = \begin{bmatrix} 69 -1 & -2 & -1 \\ 70 0 & 0 & 0 \\ 71 +1 & +2 & +1 72 \end{bmatrix} * I\f] 73 74 -# At each point of the image we calculate an approximation of the *gradient* in that point by 75 combining both results above: 76 77 \f[G = \sqrt{ G_{x}^{2} + G_{y}^{2} }\f] 78 79 Although sometimes the following simpler equation is used: 80 81 \f[G = |G_{x}| + |G_{y}|\f] 82 83 @note 84 When the size of the kernel is `3`, the Sobel kernel shown above may produce noticeable 85 inaccuracies (after all, Sobel is only an approximation of the derivative). OpenCV addresses 86 this inaccuracy for kernels of size 3 by using the @ref cv::Scharr function. This is as fast 87 but more accurate than the standar Sobel function. It implements the following kernels: 88 \f[G_{x} = \begin{bmatrix} 89 -3 & 0 & +3 \\ 90 -10 & 0 & +10 \\ 91 -3 & 0 & +3 92 \end{bmatrix}\f]\f[G_{y} = \begin{bmatrix} 93 -3 & -10 & -3 \\ 94 0 & 0 & 0 \\ 95 +3 & +10 & +3 96 \end{bmatrix}\f] 97 @note 98 You can check out more information of this function in the OpenCV reference (@ref cv::Scharr ). 99 Also, in the sample code below, you will notice that above the code for @ref cv::Sobel function 100 there is also code for the @ref cv::Scharr function commented. Uncommenting it (and obviously 101 commenting the Sobel stuff) should give you an idea of how this function works. 102 103 Code 104 ---- 105 106 -# **What does this program do?** 107 - Applies the *Sobel Operator* and generates as output an image with the detected *edges* 108 bright on a darker background. 109 110 -# The tutorial code's is shown lines below. You can also download it from 111 [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp) 112 @include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp 113 114 Explanation 115 ----------- 116 117 -# First we declare the variables we are going to use: 118 @code{.cpp} 119 Mat src, src_gray; 120 Mat grad; 121 char* window_name = "Sobel Demo - Simple Edge Detector"; 122 int scale = 1; 123 int delta = 0; 124 int ddepth = CV_16S; 125 @endcode 126 -# As usual we load our source image *src*: 127 @code{.cpp} 128 src = imread( argv[1] ); 129 130 if( !src.data ) 131 { return -1; } 132 @endcode 133 -# First, we apply a @ref cv::GaussianBlur to our image to reduce the noise ( kernel size = 3 ) 134 @code{.cpp} 135 GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); 136 @endcode 137 -# Now we convert our filtered image to grayscale: 138 @code{.cpp} 139 cvtColor( src, src_gray, COLOR_RGB2GRAY ); 140 @endcode 141 -# Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the 142 function @ref cv::Sobel as shown below: 143 @code{.cpp} 144 Mat grad_x, grad_y; 145 Mat abs_grad_x, abs_grad_y; 146 147 /// Gradient X 148 Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); 149 /// Gradient Y 150 Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); 151 @endcode 152 The function takes the following arguments: 153 154 - *src_gray*: In our example, the input image. Here it is *CV_8U* 155 - *grad_x*/*grad_y*: The output image. 156 - *ddepth*: The depth of the output image. We set it to *CV_16S* to avoid overflow. 157 - *x_order*: The order of the derivative in **x** direction. 158 - *y_order*: The order of the derivative in **y** direction. 159 - *scale*, *delta* and *BORDER_DEFAULT*: We use default values. 160 161 Notice that to calculate the gradient in *x* direction we use: \f$x_{order}= 1\f$ and 162 \f$y_{order} = 0\f$. We do analogously for the *y* direction. 163 164 -# We convert our partial results back to *CV_8U*: 165 @code{.cpp} 166 convertScaleAbs( grad_x, abs_grad_x ); 167 convertScaleAbs( grad_y, abs_grad_y ); 168 @endcode 169 -# Finally, we try to approximate the *gradient* by adding both directional gradients (note that 170 this is not an exact calculation at all! but it is good for our purposes). 171 @code{.cpp} 172 addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); 173 @endcode 174 -# Finally, we show our result: 175 @code{.cpp} 176 imshow( window_name, grad ); 177 @endcode 178 179 Results 180 ------- 181 182 -# Here is the output of applying our basic detector to *lena.jpg*: 183 184  185