Sobel Derivatives {#tutorial_sobel_derivatives}
=================
+@prev_tutorial{tutorial_copyMakeBorder}
+@next_tutorial{tutorial_laplace_operator}
+
Goal
----
In this tutorial you will learn how to:
-- Use the OpenCV function @ref cv::Sobel to calculate the derivatives from an image.
-- Use the OpenCV function @ref cv::Scharr to calculate a more accurate derivative for a kernel of
+- Use the OpenCV function **Sobel()** to calculate the derivatives from an image.
+- Use the OpenCV function **Scharr()** to calculate a more accurate derivative for a kernel of
size \f$3 \cdot 3\f$
Theory
@note
When the size of the kernel is `3`, the Sobel kernel shown above may produce noticeable
inaccuracies (after all, Sobel is only an approximation of the derivative). OpenCV addresses
- this inaccuracy for kernels of size 3 by using the @ref cv::Scharr function. This is as fast
+ this inaccuracy for kernels of size 3 by using the **Scharr()** function. This is as fast
but more accurate than the standar Sobel function. It implements the following kernels:
\f[G_{x} = \begin{bmatrix}
-3 & 0 & +3 \\
+3 & +10 & +3
\end{bmatrix}\f]
@note
- You can check out more information of this function in the OpenCV reference (@ref cv::Scharr ).
- Also, in the sample code below, you will notice that above the code for @ref cv::Sobel function
- there is also code for the @ref cv::Scharr function commented. Uncommenting it (and obviously
+ You can check out more information of this function in the OpenCV reference - **Scharr()** .
+ Also, in the sample code below, you will notice that above the code for **Sobel()** function
+ there is also code for the **Scharr()** function commented. Uncommenting it (and obviously
commenting the Sobel stuff) should give you an idea of how this function works.
Code
- Applies the *Sobel Operator* and generates as output an image with the detected *edges*
bright on a darker background.
--# The tutorial code's is shown lines below. You can also download it from
- [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
- @include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
+-# The tutorial code's is shown lines below.
+
+@add_toggle_cpp
+You can also download it from
+[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
+@include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+You can also download it from
+[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java)
+@include samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java
+@end_toggle
+
+@add_toggle_python
+You can also download it from
+[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py)
+@include samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py
+@end_toggle
Explanation
-----------
--# First we declare the variables we are going to use:
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
--# As usual we load our source image *src*:
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
--# First, we apply a @ref cv::GaussianBlur to our image to reduce the noise ( kernel size = 3 )
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
--# Now we convert our filtered image to grayscale:
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
--# Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the
- function @ref cv::Sobel as shown below:
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
+#### Declare variables
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
+
+#### Load source image
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
+
+#### Reduce noise
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
+
+#### Grayscale
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
+
+#### Sobel Operator
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
+
+- We calculate the "derivatives" in *x* and *y* directions. For this, we use the
+ function **Sobel()** as shown below:
The function takes the following arguments:
- *src_gray*: In our example, the input image. Here it is *CV_8U*
- - *grad_x*/*grad_y*: The output image.
+ - *grad_x* / *grad_y* : The output image.
- *ddepth*: The depth of the output image. We set it to *CV_16S* to avoid overflow.
- *x_order*: The order of the derivative in **x** direction.
- *y_order*: The order of the derivative in **y** direction.
Notice that to calculate the gradient in *x* direction we use: \f$x_{order}= 1\f$ and
\f$y_{order} = 0\f$. We do analogously for the *y* direction.
--# We convert our partial results back to *CV_8U*:
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
--# Finally, we try to approximate the *gradient* by adding both directional gradients (note that
- this is not an exact calculation at all! but it is good for our purposes).
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
--# Finally, we show our result:
- @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
+#### Convert output to a CV_8U image
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
+
+#### Gradient
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
+
+We try to approximate the *gradient* by adding both directional gradients (note that
+this is not an exact calculation at all! but it is good for our purposes).
+
+#### Show results
+
+@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
Results
-------
- @subpage tutorial_sobel_derivatives
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
cout << "\nPress 'ESC' to exit program.\nPress 'R' to reset values ( ksize will be -1 equal to Scharr function )";
//![variables]
+ // First we declare the variables we are going to use
Mat image,src, src_gray;
Mat grad;
const String window_name = "Sobel Demo - Simple Edge Detector";
//![variables]
//![load]
- String imageName = parser.get<String>("@input"); // by default
+ String imageName = parser.get<String>("@input");
+ // As usual we load our source image (src)
image = imread( imageName, IMREAD_COLOR ); // Load an image
+ // Check if image is loaded fine
if( image.empty() )
{
+ printf("Error opening image: %s\n", imageName.c_str());
return 1;
}
//![load]
for (;;)
{
//![reduce_noise]
+ // Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
GaussianBlur(image, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
//![reduce_noise]
//![convert_to_gray]
+ // Convert the image to grayscale
cvtColor(src, src_gray, COLOR_BGR2GRAY);
//![convert_to_gray]
//![sobel]
//![convert]
+ // converting back to CV_8U
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
//![convert]
--- /dev/null
+/**
+ * @file SobelDemo.java
+ * @brief Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector
+ */
+
+import org.opencv.core.*;
+import org.opencv.highgui.HighGui;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+class SobelDemoRun {
+
+ public void run(String[] args) {
+
+ //! [declare_variables]
+ // First we declare the variables we are going to use
+ Mat src, src_gray = new Mat();
+ Mat grad = new Mat();
+ String window_name = "Sobel Demo - Simple Edge Detector";
+ int scale = 1;
+ int delta = 0;
+ int ddepth = CvType.CV_16S;
+ //! [declare_variables]
+
+ //! [load]
+ // As usual we load our source image (src)
+ // Check number of arguments
+ if (args.length == 0){
+ System.out.println("Not enough parameters!");
+ System.out.println("Program Arguments: [image_path]");
+ System.exit(-1);
+ }
+
+ // Load the image
+ src = Imgcodecs.imread(args[0]);
+
+ // Check if image is loaded fine
+ if( src.empty() ) {
+ System.out.println("Error opening image: " + args[0]);
+ System.exit(-1);
+ }
+ //! [load]
+
+ //! [reduce_noise]
+ // Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
+ Imgproc.GaussianBlur( src, src, new Size(3, 3), 0, 0, Core.BORDER_DEFAULT );
+ //! [reduce_noise]
+
+ //! [convert_to_gray]
+ // Convert the image to grayscale
+ Imgproc.cvtColor( src, src_gray, Imgproc.COLOR_RGB2GRAY );
+ //! [convert_to_gray]
+
+ //! [sobel]
+ /// Generate grad_x and grad_y
+ Mat grad_x = new Mat(), grad_y = new Mat();
+ Mat abs_grad_x = new Mat(), abs_grad_y = new Mat();
+
+ /// Gradient X
+ //Imgproc.Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, Core.BORDER_DEFAULT );
+ Imgproc.Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, Core.BORDER_DEFAULT );
+
+ /// Gradient Y
+ //Imgproc.Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, Core.BORDER_DEFAULT );
+ Imgproc.Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, Core.BORDER_DEFAULT );
+ //! [sobel]
+
+ //![convert]
+ // converting back to CV_8U
+ Core.convertScaleAbs( grad_x, abs_grad_x );
+ Core.convertScaleAbs( grad_y, abs_grad_y );
+ //![convert]
+
+ //! [add_weighted]
+ /// Total Gradient (approximate)
+ Core.addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
+ //! [add_weighted]
+
+ //! [display]
+ HighGui.imshow( window_name, grad );
+ HighGui.waitKey(0);
+ //! [display]
+
+ System.exit(0);
+ }
+}
+
+public class SobelDemo {
+ public static void main(String[] args) {
+ // Load the native library.
+ System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+ new SobelDemoRun().run(args);
+ }
+}
--- /dev/null
+"""
+@file sobel_demo.py
+@brief Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector
+"""
+import sys
+import cv2
+
+
+def main(argv):
+ ## [variables]
+ # First we declare the variables we are going to use
+ window_name = ('Sobel Demo - Simple Edge Detector')
+ scale = 1
+ delta = 0
+ ddepth = cv2.CV_16S
+ ## [variables]
+
+ ## [load]
+ # As usual we load our source image (src)
+ # Check number of arguments
+ if len(argv) < 1:
+ print ('Not enough parameters')
+ print ('Usage:\nmorph_lines_detection.py < path_to_image >')
+ return -1
+
+ # Load the image
+ src = cv2.imread(argv[0], cv2.IMREAD_COLOR)
+
+ # Check if image is loaded fine
+ if src is None:
+ print ('Error opening image: ' + argv[0])
+ return -1
+ ## [load]
+
+ ## [reduce_noise]
+ # Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
+ src = cv2.GaussianBlur(src, (3, 3), 0)
+ ## [reduce_noise]
+
+ ## [convert_to_gray]
+ # Convert the image to grayscale
+ gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
+ ## [convert_to_gray]
+
+ ## [sobel]
+ # Gradient-X
+ # grad_x = cv2.Scharr(gray,ddepth,1,0)
+ grad_x = cv2.Sobel(gray, ddepth, 1, 0, ksize=3, scale=scale, delta=delta, borderType=cv2.BORDER_DEFAULT)
+
+ # Gradient-Y
+ # grad_y = cv2.Scharr(gray,ddepth,0,1)
+ grad_y = cv2.Sobel(gray, ddepth, 0, 1, ksize=3, scale=scale, delta=delta, borderType=cv2.BORDER_DEFAULT)
+ ## [sobel]
+
+ ## [convert]
+ # converting back to uint8
+ abs_grad_x = cv2.convertScaleAbs(grad_x)
+ abs_grad_y = cv2.convertScaleAbs(grad_y)
+ ## [convert]
+
+ ## [blend]
+ ## Total Gradient (approximate)
+ grad = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)
+ ## [blend]
+
+ ## [display]
+ cv2.imshow(window_name, grad)
+ cv2.waitKey(0)
+ ## [display]
+
+ return 0
+
+if __name__ == "__main__":
+ main(sys.argv[1:])