Skip to content

Commit f7d85bf

Browse files
committed
Tutorial Sobel Derivatives
1 parent 3250f11 commit f7d85bf

File tree

5 files changed

+243
-29
lines changed

5 files changed

+243
-29
lines changed

doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
Sobel Derivatives {#tutorial_sobel_derivatives}
22
=================
33

4+
@prev_tutorial{tutorial_copyMakeBorder}
5+
@next_tutorial{tutorial_laplace_operator}
6+
47
Goal
58
----
69

710
In this tutorial you will learn how to:
811

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
12+
- Use the OpenCV function **Sobel()** to calculate the derivatives from an image.
13+
- Use the OpenCV function **Scharr()** to calculate a more accurate derivative for a kernel of
1114
size \f$3 \cdot 3\f$
1215

1316
Theory
@@ -83,7 +86,7 @@ Assuming that the image to be operated is \f$I\f$:
8386
@note
8487
When the size of the kernel is `3`, the Sobel kernel shown above may produce noticeable
8588
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
89+
this inaccuracy for kernels of size 3 by using the **Scharr()** function. This is as fast
8790
but more accurate than the standar Sobel function. It implements the following kernels:
8891
\f[G_{x} = \begin{bmatrix}
8992
-3 & 0 & +3 \\
@@ -95,9 +98,9 @@ Assuming that the image to be operated is \f$I\f$:
9598
+3 & +10 & +3
9699
\end{bmatrix}\f]
97100
@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+
You can check out more information of this function in the OpenCV reference - **Scharr()** .
102+
Also, in the sample code below, you will notice that above the code for **Sobel()** function
103+
there is also code for the **Scharr()** function commented. Uncommenting it (and obviously
101104
commenting the Sobel stuff) should give you an idea of how this function works.
102105

103106
Code
@@ -107,28 +110,55 @@ Code
107110
- Applies the *Sobel Operator* and generates as output an image with the detected *edges*
108111
bright on a darker background.
109112

110-
-# The tutorial code's is shown lines below. You can also download it from
111-
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
112-
@include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
113+
-# The tutorial code's is shown lines below.
114+
115+
@add_toggle_cpp
116+
You can also download it from
117+
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
118+
@include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
119+
@end_toggle
120+
121+
@add_toggle_java
122+
You can also download it from
123+
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java)
124+
@include samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java
125+
@end_toggle
126+
127+
@add_toggle_python
128+
You can also download it from
129+
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py)
130+
@include samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py
131+
@end_toggle
113132

114133
Explanation
115134
-----------
116135

117-
-# First we declare the variables we are going to use:
118-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
119-
-# As usual we load our source image *src*:
120-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
121-
-# First, we apply a @ref cv::GaussianBlur to our image to reduce the noise ( kernel size = 3 )
122-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
123-
-# Now we convert our filtered image to grayscale:
124-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
125-
-# Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the
126-
function @ref cv::Sobel as shown below:
127-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
136+
#### Declare variables
137+
138+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
139+
140+
#### Load source image
141+
142+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
143+
144+
#### Reduce noise
145+
146+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
147+
148+
#### Grayscale
149+
150+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
151+
152+
#### Sobel Operator
153+
154+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
155+
156+
- We calculate the "derivatives" in *x* and *y* directions. For this, we use the
157+
function **Sobel()** as shown below:
128158
The function takes the following arguments:
129159

130160
- *src_gray*: In our example, the input image. Here it is *CV_8U*
131-
- *grad_x*/*grad_y*: The output image.
161+
- *grad_x* / *grad_y* : The output image.
132162
- *ddepth*: The depth of the output image. We set it to *CV_16S* to avoid overflow.
133163
- *x_order*: The order of the derivative in **x** direction.
134164
- *y_order*: The order of the derivative in **y** direction.
@@ -137,13 +167,20 @@ Explanation
137167
Notice that to calculate the gradient in *x* direction we use: \f$x_{order}= 1\f$ and
138168
\f$y_{order} = 0\f$. We do analogously for the *y* direction.
139169

140-
-# We convert our partial results back to *CV_8U*:
141-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
142-
-# Finally, we try to approximate the *gradient* by adding both directional gradients (note that
143-
this is not an exact calculation at all! but it is good for our purposes).
144-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
145-
-# Finally, we show our result:
146-
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
170+
#### Convert output to a CV_8U image
171+
172+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
173+
174+
#### Gradient
175+
176+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
177+
178+
We try to approximate the *gradient* by adding both directional gradients (note that
179+
this is not an exact calculation at all! but it is good for our purposes).
180+
181+
#### Show results
182+
183+
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
147184

148185
Results
149186
-------

doc/tutorials/imgproc/table_of_content_imgproc.markdown

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ In this section you will learn about the image processing (manipulation) functio
9191

9292
- @subpage tutorial_sobel_derivatives
9393

94+
*Languages:* C++, Java, Python
95+
9496
*Compatibility:* \> OpenCV 2.0
9597

9698
*Author:* Ana Huamán

samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ int main( int argc, char** argv )
3030
cout << "\nPress 'ESC' to exit program.\nPress 'R' to reset values ( ksize will be -1 equal to Scharr function )";
3131

3232
//![variables]
33+
// First we declare the variables we are going to use
3334
Mat image,src, src_gray;
3435
Mat grad;
3536
const String window_name = "Sobel Demo - Simple Edge Detector";
@@ -40,22 +41,27 @@ int main( int argc, char** argv )
4041
//![variables]
4142

4243
//![load]
43-
String imageName = parser.get<String>("@input"); // by default
44+
String imageName = parser.get<String>("@input");
45+
// As usual we load our source image (src)
4446
image = imread( imageName, IMREAD_COLOR ); // Load an image
4547

48+
// Check if image is loaded fine
4649
if( image.empty() )
4750
{
51+
printf("Error opening image: %s\n", imageName.c_str());
4852
return 1;
4953
}
5054
//![load]
5155

5256
for (;;)
5357
{
5458
//![reduce_noise]
59+
// Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
5560
GaussianBlur(image, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
5661
//![reduce_noise]
5762

5863
//![convert_to_gray]
64+
// Convert the image to grayscale
5965
cvtColor(src, src_gray, COLOR_BGR2GRAY);
6066
//![convert_to_gray]
6167

@@ -72,6 +78,7 @@ int main( int argc, char** argv )
7278
//![sobel]
7379

7480
//![convert]
81+
// converting back to CV_8U
7582
convertScaleAbs(grad_x, abs_grad_x);
7683
convertScaleAbs(grad_y, abs_grad_y);
7784
//![convert]
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @file SobelDemo.java
3+
* @brief Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector
4+
*/
5+
6+
import org.opencv.core.*;
7+
import org.opencv.highgui.HighGui;
8+
import org.opencv.imgcodecs.Imgcodecs;
9+
import org.opencv.imgproc.Imgproc;
10+
11+
class SobelDemoRun {
12+
13+
public void run(String[] args) {
14+
15+
//! [declare_variables]
16+
// First we declare the variables we are going to use
17+
Mat src, src_gray = new Mat();
18+
Mat grad = new Mat();
19+
String window_name = "Sobel Demo - Simple Edge Detector";
20+
int scale = 1;
21+
int delta = 0;
22+
int ddepth = CvType.CV_16S;
23+
//! [declare_variables]
24+
25+
//! [load]
26+
// As usual we load our source image (src)
27+
// Check number of arguments
28+
if (args.length == 0){
29+
System.out.println("Not enough parameters!");
30+
System.out.println("Program Arguments: [image_path]");
31+
System.exit(-1);
32+
}
33+
34+
// Load the image
35+
src = Imgcodecs.imread(args[0]);
36+
37+
// Check if image is loaded fine
38+
if( src.empty() ) {
39+
System.out.println("Error opening image: " + args[0]);
40+
System.exit(-1);
41+
}
42+
//! [load]
43+
44+
//! [reduce_noise]
45+
// Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
46+
Imgproc.GaussianBlur( src, src, new Size(3, 3), 0, 0, Core.BORDER_DEFAULT );
47+
//! [reduce_noise]
48+
49+
//! [convert_to_gray]
50+
// Convert the image to grayscale
51+
Imgproc.cvtColor( src, src_gray, Imgproc.COLOR_RGB2GRAY );
52+
//! [convert_to_gray]
53+
54+
//! [sobel]
55+
/// Generate grad_x and grad_y
56+
Mat grad_x = new Mat(), grad_y = new Mat();
57+
Mat abs_grad_x = new Mat(), abs_grad_y = new Mat();
58+
59+
/// Gradient X
60+
//Imgproc.Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, Core.BORDER_DEFAULT );
61+
Imgproc.Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, Core.BORDER_DEFAULT );
62+
63+
/// Gradient Y
64+
//Imgproc.Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, Core.BORDER_DEFAULT );
65+
Imgproc.Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, Core.BORDER_DEFAULT );
66+
//! [sobel]
67+
68+
//![convert]
69+
// converting back to CV_8U
70+
Core.convertScaleAbs( grad_x, abs_grad_x );
71+
Core.convertScaleAbs( grad_y, abs_grad_y );
72+
//![convert]
73+
74+
//! [add_weighted]
75+
/// Total Gradient (approximate)
76+
Core.addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
77+
//! [add_weighted]
78+
79+
//! [display]
80+
HighGui.imshow( window_name, grad );
81+
HighGui.waitKey(0);
82+
//! [display]
83+
84+
System.exit(0);
85+
}
86+
}
87+
88+
public class SobelDemo {
89+
public static void main(String[] args) {
90+
// Load the native library.
91+
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
92+
new SobelDemoRun().run(args);
93+
}
94+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
@file sobel_demo.py
3+
@brief Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector
4+
"""
5+
import sys
6+
import cv2
7+
8+
9+
def main(argv):
10+
## [variables]
11+
# First we declare the variables we are going to use
12+
window_name = ('Sobel Demo - Simple Edge Detector')
13+
scale = 1
14+
delta = 0
15+
ddepth = cv2.CV_16S
16+
## [variables]
17+
18+
## [load]
19+
# As usual we load our source image (src)
20+
# Check number of arguments
21+
if len(argv) < 1:
22+
print ('Not enough parameters')
23+
print ('Usage:\nmorph_lines_detection.py < path_to_image >')
24+
return -1
25+
26+
# Load the image
27+
src = cv2.imread(argv[0], cv2.IMREAD_COLOR)
28+
29+
# Check if image is loaded fine
30+
if src is None:
31+
print ('Error opening image: ' + argv[0])
32+
return -1
33+
## [load]
34+
35+
## [reduce_noise]
36+
# Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
37+
src = cv2.GaussianBlur(src, (3, 3), 0)
38+
## [reduce_noise]
39+
40+
## [convert_to_gray]
41+
# Convert the image to grayscale
42+
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
43+
## [convert_to_gray]
44+
45+
## [sobel]
46+
# Gradient-X
47+
# grad_x = cv2.Scharr(gray,ddepth,1,0)
48+
grad_x = cv2.Sobel(gray, ddepth, 1, 0, ksize=3, scale=scale, delta=delta, borderType=cv2.BORDER_DEFAULT)
49+
50+
# Gradient-Y
51+
# grad_y = cv2.Scharr(gray,ddepth,0,1)
52+
grad_y = cv2.Sobel(gray, ddepth, 0, 1, ksize=3, scale=scale, delta=delta, borderType=cv2.BORDER_DEFAULT)
53+
## [sobel]
54+
55+
## [convert]
56+
# converting back to uint8
57+
abs_grad_x = cv2.convertScaleAbs(grad_x)
58+
abs_grad_y = cv2.convertScaleAbs(grad_y)
59+
## [convert]
60+
61+
## [blend]
62+
## Total Gradient (approximate)
63+
grad = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)
64+
## [blend]
65+
66+
## [display]
67+
cv2.imshow(window_name, grad)
68+
cv2.waitKey(0)
69+
## [display]
70+
71+
return 0
72+
73+
if __name__ == "__main__":
74+
main(sys.argv[1:])

0 commit comments

Comments
 (0)