mirror of
https://github.com/opencv/opencv.git
synced 2025-06-10 19:24:07 +08:00
Tutorial Sobel Derivatives
This commit is contained in:
parent
3250f11f0c
commit
f7d85bfed8
@ -1,13 +1,16 @@
|
|||||||
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$:
|
|||||||
@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$:
|
|||||||
+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,24 +110,51 @@ 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)
|
|
||||||
|
@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
|
@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
|
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
|
||||||
-# As usual we load our source image *src*:
|
|
||||||
|
#### Load source image
|
||||||
|
|
||||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
|
@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 )
|
|
||||||
|
#### Reduce noise
|
||||||
|
|
||||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
|
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
|
||||||
-# Now we convert our filtered image to grayscale:
|
|
||||||
|
#### Grayscale
|
||||||
|
|
||||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
|
@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:
|
#### Sobel Operator
|
||||||
|
|
||||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
|
@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*
|
||||||
@ -137,12 +167,19 @@ 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
|
@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).
|
#### Gradient
|
||||||
|
|
||||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
|
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
|
||||||
-# Finally, we show our result:
|
|
||||||
|
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
|
@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
|
|||||||
|
|
||||||
- @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 )
|
|||||||
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 )
|
|||||||
//![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 )
|
|||||||
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 )
|
|||||||
//![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]
|
||||||
|
94
samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java
Normal file
94
samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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:])
|
Loading…
Reference in New Issue
Block a user