From: tribta Date: Tue, 22 Aug 2017 11:28:23 +0000 (+0100) Subject: Tutorial Sobel Derivatives X-Git-Tag: accepted/tizen/6.0/unified/20201030.111113~539^2~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f7d85bfed86cdcbbb683dd66a885f9c2aadaccaf;p=platform%2Fupstream%2Fopencv.git Tutorial Sobel Derivatives --- diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown index 3112b08..f6010fc 100644 --- a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown +++ b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown @@ -1,13 +1,16 @@ 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 @@ -83,7 +86,7 @@ Assuming that the image to be operated is \f$I\f$: @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 \\ @@ -95,9 +98,9 @@ Assuming that the image to be operated is \f$I\f$: +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 @@ -107,28 +110,55 @@ 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. @@ -137,13 +167,20 @@ Explanation 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 ------- diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index 5ee75f3..f4c57cd 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -91,6 +91,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_sobel_derivatives + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán diff --git a/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp index 5209380..16661d8 100644 --- a/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp +++ b/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp @@ -30,6 +30,7 @@ int main( int argc, char** argv ) 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"; @@ -40,11 +41,14 @@ int main( int argc, char** argv ) //![variables] //![load] - String imageName = parser.get("@input"); // by default + String imageName = parser.get("@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] @@ -52,10 +56,12 @@ int main( int argc, char** argv ) 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] @@ -72,6 +78,7 @@ int main( int argc, char** argv ) //![sobel] //![convert] + // converting back to CV_8U convertScaleAbs(grad_x, abs_grad_x); convertScaleAbs(grad_y, abs_grad_y); //![convert] diff --git a/samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java b/samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java new file mode 100644 index 0000000..815c16b --- /dev/null +++ b/samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java @@ -0,0 +1,94 @@ +/** + * @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); + } +} diff --git a/samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py b/samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py new file mode 100644 index 0000000..4afe3af --- /dev/null +++ b/samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py @@ -0,0 +1,74 @@ +""" +@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:])