Commit f7d85bfe authored by tribta's avatar tribta

Tutorial Sobel Derivatives

parent 3250f11f
Sobel Derivatives {#tutorial_sobel_derivatives} Sobel Derivatives {#tutorial_sobel_derivatives}
================= =================
@prev_tutorial{tutorial_copyMakeBorder}
@next_tutorial{tutorial_laplace_operator}
Goal Goal
---- ----
In this tutorial you will learn how to: 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 **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 **Scharr()** to calculate a more accurate derivative for a kernel of
size \f$3 \cdot 3\f$ size \f$3 \cdot 3\f$
Theory Theory
...@@ -83,7 +86,7 @@ Assuming that the image to be operated is \f$I\f$: ...@@ -83,7 +86,7 @@ Assuming that the image to be operated is \f$I\f$:
@note @note
When the size of the kernel is `3`, the Sobel kernel shown above may produce noticeable 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 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: but more accurate than the standar Sobel function. It implements the following kernels:
\f[G_{x} = \begin{bmatrix} \f[G_{x} = \begin{bmatrix}
-3 & 0 & +3 \\ -3 & 0 & +3 \\
...@@ -95,9 +98,9 @@ Assuming that the image to be operated is \f$I\f$: ...@@ -95,9 +98,9 @@ Assuming that the image to be operated is \f$I\f$:
+3 & +10 & +3 +3 & +10 & +3
\end{bmatrix}\f] \end{bmatrix}\f]
@note @note
You can check out more information of this function in the OpenCV reference (@ref cv::Scharr ). 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 @ref cv::Sobel function Also, in the sample code below, you will notice that above the code for **Sobel()** function
there is also code for the @ref cv::Scharr function commented. Uncommenting it (and obviously 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. commenting the Sobel stuff) should give you an idea of how this function works.
Code Code
...@@ -107,28 +110,55 @@ Code ...@@ -107,28 +110,55 @@ Code
- Applies the *Sobel Operator* and generates as output an image with the detected *edges* - Applies the *Sobel Operator* and generates as output an image with the detected *edges*
bright on a darker background. bright on a darker background.
-# The tutorial code's is shown lines below. You can also download it from -# The tutorial code's is shown lines below.
[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 @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 Explanation
----------- -----------
-# First we declare the variables we are going to use: #### Declare variables
@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 variables
@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 ) #### Load source image
@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 load
@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 #### Reduce noise
function @ref cv::Sobel as shown below:
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel @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: The function takes the following arguments:
- *src_gray*: In our example, the input image. Here it is *CV_8U* - *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. - *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. - *x_order*: The order of the derivative in **x** direction.
- *y_order*: The order of the derivative in **y** direction. - *y_order*: The order of the derivative in **y** direction.
...@@ -137,13 +167,20 @@ Explanation ...@@ -137,13 +167,20 @@ Explanation
Notice that to calculate the gradient in *x* direction we use: \f$x_{order}= 1\f$ and 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. \f$y_{order} = 0\f$. We do analogously for the *y* direction.
-# We convert our partial results back to *CV_8U*: #### Convert output to a CV_8U image
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
-# Finally, we try to approximate the *gradient* by adding both directional gradients (note that @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
this is not an exact calculation at all! but it is good for our purposes).
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend #### Gradient
-# Finally, we show our result:
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display @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 Results
------- -------
......
...@@ -91,6 +91,8 @@ In this section you will learn about the image processing (manipulation) functio ...@@ -91,6 +91,8 @@ In this section you will learn about the image processing (manipulation) functio
- @subpage tutorial_sobel_derivatives - @subpage tutorial_sobel_derivatives
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
......
...@@ -30,6 +30,7 @@ int main( int argc, char** argv ) ...@@ -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 )"; cout << "\nPress 'ESC' to exit program.\nPress 'R' to reset values ( ksize will be -1 equal to Scharr function )";
//![variables] //![variables]
// First we declare the variables we are going to use
Mat image,src, src_gray; Mat image,src, src_gray;
Mat grad; Mat grad;
const String window_name = "Sobel Demo - Simple Edge Detector"; const String window_name = "Sobel Demo - Simple Edge Detector";
...@@ -40,11 +41,14 @@ int main( int argc, char** argv ) ...@@ -40,11 +41,14 @@ int main( int argc, char** argv )
//![variables] //![variables]
//![load] //![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 image = imread( imageName, IMREAD_COLOR ); // Load an image
// Check if image is loaded fine
if( image.empty() ) if( image.empty() )
{ {
printf("Error opening image: %s\n", imageName.c_str());
return 1; return 1;
} }
//![load] //![load]
...@@ -52,10 +56,12 @@ int main( int argc, char** argv ) ...@@ -52,10 +56,12 @@ int main( int argc, char** argv )
for (;;) for (;;)
{ {
//![reduce_noise] //![reduce_noise]
// Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
GaussianBlur(image, src, Size(3, 3), 0, 0, BORDER_DEFAULT); GaussianBlur(image, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
//![reduce_noise] //![reduce_noise]
//![convert_to_gray] //![convert_to_gray]
// Convert the image to grayscale
cvtColor(src, src_gray, COLOR_BGR2GRAY); cvtColor(src, src_gray, COLOR_BGR2GRAY);
//![convert_to_gray] //![convert_to_gray]
...@@ -72,6 +78,7 @@ int main( int argc, char** argv ) ...@@ -72,6 +78,7 @@ int main( int argc, char** argv )
//![sobel] //![sobel]
//![convert] //![convert]
// converting back to CV_8U
convertScaleAbs(grad_x, abs_grad_x); convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y); convertScaleAbs(grad_y, abs_grad_y);
//![convert] //![convert]
......
/**
* @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);
}
}
"""
@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:])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment