1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Update documentation ( tutorials )

This commit is contained in:
Suleyman TURKMEN
2016-07-18 16:32:05 +03:00
parent 55d0945149
commit bb6f65c199
34 changed files with 369 additions and 1333 deletions
@@ -71,7 +71,7 @@ Explanation
- Load an image (can be BGR or grayscale)
- Create two windows (one for dilation output, the other for erosion)
- Create a set of 02 Trackbars for each operation:
- Create a set of two Trackbars for each operation:
- The first trackbar "Element" returns either **erosion_elem** or **dilation_elem**
- The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the
corresponding operation.
@@ -81,23 +81,8 @@ Explanation
Let's analyze these two functions:
-# **erosion:**
@code{.cpp}
/* @function Erosion */
void Erosion( int, void* )
{
int erosion_type;
if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp erosion
Mat element = getStructuringElement( erosion_type,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
/// Apply the erosion operation
erode( src, erosion_dst, element );
imshow( "Erosion Demo", erosion_dst );
}
@endcode
- The function that performs the *erosion* operation is @ref cv::erode . As we can see, it
receives three arguments:
- *src*: The source image
@@ -105,11 +90,8 @@ Explanation
- *element*: This is the kernel we will use to perform the operation. If we do not
specify, the default is a simple `3x3` matrix. Otherwise, we can specify its
shape. For this, we need to use the function cv::getStructuringElement :
@code{.cpp}
Mat element = getStructuringElement( erosion_type,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
@endcode
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp kernel
We can choose any of three shapes for our kernel:
- Rectangular box: MORPH_RECT
@@ -129,23 +111,7 @@ Reference for more details.
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
Here we also have the option of defining our kernel, its anchor point and the size of the operator
to be used.
@code{.cpp}
/* @function Dilation */
void Dilation( int, void* )
{
int dilation_type;
if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement( dilation_type,
Size( 2*dilation_size + 1, 2*dilation_size+1 ),
Point( dilation_size, dilation_size ) );
/// Apply the dilation operation
dilate( src, dilation_dst, element );
imshow( "Dilation Demo", dilation_dst );
}
@endcode
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp dilation
Results
-------
@@ -16,8 +16,7 @@ Theory
------
@note The explanation below belongs to the book [Computer Vision: Algorithms and
Applications](http://szeliski.org/Book/) by Richard Szeliski and to *LearningOpenCV* .. container::
enumeratevisibleitemswithsquare
Applications](http://szeliski.org/Book/) by Richard Szeliski and to *LearningOpenCV*
- *Smoothing*, also called *blurring*, is a simple and frequently used image processing
operation.
@@ -96,96 +95,7 @@ Code
- **Downloadable code**: Click
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp)
- **Code at glance:**
@code{.cpp}
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;
char window_name[] = "Filter Demo 1";
/// Function headers
int display_caption( char* caption );
int display_dst( int delay );
/*
* function main
*/
int main( int argc, char** argv )
{
namedWindow( window_name, WINDOW_AUTOSIZE );
/// Load the source image
src = imread( "../images/lena.jpg", 1 );
if( display_caption( "Original Image" ) != 0 ) { return 0; }
dst = src.clone();
if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }
/// Applying Homogeneous blur
if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// Applying Gaussian blur
if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// Applying Median blur
if( display_caption( "Median Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// Applying Bilateral Filter
if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// Wait until user press a key
display_caption( "End: Press a key!" );
waitKey(0);
return 0;
}
int display_caption( char* caption )
{
dst = Mat::zeros( src.size(), src.type() );
putText( dst, caption,
Point( src.cols/4, src.rows/2),
FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
imshow( window_name, dst );
int c = waitKey( DELAY_CAPTION );
if( c >= 0 ) { return -1; }
return 0;
}
int display_dst( int delay )
{
imshow( window_name, dst );
int c = waitKey ( delay );
if( c >= 0 ) { return -1; }
return 0;
}
@endcode
@include samples/cpp/tutorial_code/ImgProc/Smoothing.cpp
Explanation
-----------
@@ -195,11 +105,8 @@ Explanation
-# **Normalized Block Filter:**
OpenCV offers the function @ref cv::blur to perform smoothing with this filter.
@code{.cpp}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
@endcode
@snippet cpp/tutorial_code/ImgProc/Smoothing.cpp blur
We specify 4 arguments (more details, check the Reference):
- *src*: Source image
@@ -213,11 +120,8 @@ Explanation
-# **Gaussian Filter:**
It is performed by the function @ref cv::GaussianBlur :
@code{.cpp}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
@endcode
@snippet cpp/tutorial_code/ImgProc/Smoothing.cpp gaussianblur
Here we use 4 arguments (more details, check the OpenCV reference):
- *src*: Source image
@@ -233,11 +137,8 @@ Explanation
-# **Median Filter:**
This filter is provided by the @ref cv::medianBlur function:
@code{.cpp}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
@endcode
@snippet cpp/tutorial_code/ImgProc/Smoothing.cpp medianblur
We use three arguments:
- *src*: Source image
@@ -247,11 +148,8 @@ Explanation
-# **Bilateral Filter**
Provided by OpenCV function @ref cv::bilateralFilter
@code{.cpp}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
@endcode
@snippet cpp/tutorial_code/ImgProc/Smoothing.cpp bilateralfilter
We use 5 arguments:
- *src*: Source image
@@ -81,17 +81,8 @@ Explanation
-----------
-# Create some needed variables:
@code{.cpp}
Mat src, src_gray;
Mat dst, detected_edges;
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp variables
int edgeThresh = 1;
int lowThreshold;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
char* window_name = "Edge Map";
@endcode
Note the following:
-# We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*)
@@ -100,29 +91,16 @@ Explanation
-# We set a maximum value for the lower Threshold of \f$100\f$.
-# Loads the source image:
@code{.cpp}
/// Load an image
src = imread( argv[1] );
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp load
if( !src.data )
{ return -1; }
@endcode
-# Create a matrix of the same type and size of *src* (to be *dst*)
@code{.cpp}
dst.create( src.size(), src.type() );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_mat
-# Convert the image to grayscale (using the function @ref cv::cvtColor :
@code{.cpp}
cvtColor( src, src_gray, COLOR_BGR2GRAY );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp convert_to_gray
-# Create a window to display the results
@code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_window
-# Create a Trackbar for the user to enter the lower threshold for our Canny detector:
@code{.cpp}
createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_trackbar
Observe the following:
-# The variable to be controlled by the Trackbar is *lowThreshold* with a limit of
@@ -132,13 +110,9 @@ Explanation
-# Let's check the *CannyThreshold* function, step by step:
-# First, we blur the image with a filter of kernel size 3:
@code{.cpp}
blur( src_gray, detected_edges, Size(3,3) );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp reduce_noise
-# Second, we apply the OpenCV function @ref cv::Canny :
@code{.cpp}
Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp canny
where the arguments are:
- *detected_edges*: Source image, grayscale
@@ -150,23 +124,16 @@ Explanation
internally)
-# We fill a *dst* image with zeros (meaning the image is completely black).
@code{.cpp}
dst = Scalar::all(0);
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp fill
-# Finally, we will use the function @ref cv::Mat::copyTo to map only the areas of the image that are
identified as edges (on a black background).
@code{.cpp}
src.copyTo( dst, detected_edges);
@endcode
@ref cv::Mat::copyTo copy the *src* image onto *dst*. However, it will only copy the pixels in the
locations where they have non-zero values. Since the output of the Canny detector is the edge
contours on a black background, the resulting *dst* will be black in all the area but the
detected edges.
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp copyto
-# We display our result:
@code{.cpp}
imshow( window_name, dst );
@endcode
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp display
Result
------
@@ -53,61 +53,29 @@ Explanation
-----------
-# First we declare the variables we are going to use:
@code{.cpp}
Mat src, dst;
int top, bottom, left, right;
int borderType;
Scalar value;
char* window_name = "copyMakeBorder Demo";
RNG rng(12345);
@endcode
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp variables
Especial attention deserves the variable *rng* which is a random number generator. We use it to
generate the random border color, as we will see soon.
-# As usual we load our source image *src*:
@code{.cpp}
src = imread( argv[1] );
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp load
if( !src.data )
{ return -1;
printf(" No data entered, please enter the path to an image file \n");
}
@endcode
-# After giving a short intro of how to use the program, we create a window:
@code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE );
@endcode
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp create_window
-# Now we initialize the argument that defines the size of the borders (*top*, *bottom*, *left* and
*right*). We give them a value of 5% the size of *src*.
@code{.cpp}
top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows);
left = (int) (0.05*src.cols); right = (int) (0.05*src.cols);
@endcode
-# The program begins a *while* loop. If the user presses 'c' or 'r', the *borderType* variable
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp init_arguments
-# The program runs in a **for** loop. If the user presses 'c' or 'r', the *borderType* variable
takes the value of *BORDER_CONSTANT* or *BORDER_REPLICATE* respectively:
@code{.cpp}
while( true )
{
c = waitKey(500);
if( (char)c == 27 )
{ break; }
else if( (char)c == 'c' )
{ borderType = BORDER_CONSTANT; }
else if( (char)c == 'r' )
{ borderType = BORDER_REPLICATE; }
@endcode
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp check_keypress
-# In each iteration (after 0.5 seconds), the variable *value* is updated...
@code{.cpp}
value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );
@endcode
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp update_value
with a random value generated by the **RNG** variable *rng*. This value is a number picked
randomly in the range \f$[0,255]\f$
-# Finally, we call the function @ref cv::copyMakeBorder to apply the respective padding:
@code{.cpp}
copyMakeBorder( src, dst, top, bottom, left, right, borderType, value );
@endcode
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp copymakeborder
The arguments are:
-# *src*: Source image
@@ -120,9 +88,7 @@ Explanation
pixels.
-# We display our output image in the image created previously
@code{.cpp}
imshow( window_name, dst );
@endcode
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp display
Results
-------
@@ -63,100 +63,25 @@ Code
-# 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/filter2D_demo.cpp)
@code{.cpp}
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
@include cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
using namespace cv;
/* @function main */
int main ( int argc, char** argv )
{
/// Declare variables
Mat src, dst;
Mat kernel;
Point anchor;
double delta;
int ddepth;
int kernel_size;
char* window_name = "filter2D Demo";
int c;
/// Load an image
src = imread( argv[1] );
if( !src.data )
{ return -1; }
/// Create window
namedWindow( window_name, WINDOW_AUTOSIZE );
/// Initialize arguments for the filter
anchor = Point( -1, -1 );
delta = 0;
ddepth = -1;
/// Loop - Will filter the image with different kernel sizes each 0.5 seconds
int ind = 0;
while( true )
{
c = waitKey(500);
/// Press 'ESC' to exit the program
if( (char)c == 27 )
{ break; }
/// Update kernel size for a normalized box filter
kernel_size = 3 + 2*( ind%5 );
kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
/// Apply filter
filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
imshow( window_name, dst );
ind++;
}
return 0;
}
@endcode
Explanation
-----------
-# Load an image
@code{.cpp}
src = imread( argv[1] );
if( !src.data )
{ return -1; }
@endcode
-# Create a window to display the result
@code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE );
@endcode
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp load
-# Initialize the arguments for the linear filter
@code{.cpp}
anchor = Point( -1, -1 );
delta = 0;
ddepth = -1;
@endcode
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp init_arguments
-# Perform an infinite loop updating the kernel size and applying our linear filter to the input
image. Let's analyze that more in detail:
-# First we define the kernel our filter is going to use. Here it is:
@code{.cpp}
kernel_size = 3 + 2*( ind%5 );
kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
@endcode
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp update_kernel
The first line is to update the *kernel_size* to odd values in the range: \f$[3,11]\f$. The second
line actually builds the kernel by setting its value to a matrix filled with \f$1's\f$ and
normalizing it by dividing it between the number of elements.
-# After setting the kernel, we can generate the filter by using the function @ref cv::filter2D :
@code{.cpp}
filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
@endcode
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp apply_filter
The arguments denote:
-# *src*: Source image
@@ -48,63 +48,33 @@ Explanation
-----------
-# Load an image
@code{.cpp}
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
@endcode
@snippet samples/cpp/houghcircles.cpp load
-# Convert it to grayscale:
@code{.cpp}
cvtColor( src, src_gray, COLOR_BGR2GRAY );
@endcode
-# Apply a Gaussian blur to reduce noise and avoid false circle detection:
@code{.cpp}
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
@endcode
@snippet samples/cpp/houghcircles.cpp convert_to_gray
-# Apply a Median blur to reduce noise and avoid false circle detection:
@snippet samples/cpp/houghcircles.cpp reduce_noise
-# Proceed to apply Hough Circle Transform:
@code{.cpp}
vector<Vec3f> circles;
HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
@endcode
@snippet samples/cpp/houghcircles.cpp houghcircles
with the arguments:
- *src_gray*: Input image (grayscale).
- *gray*: Input image (grayscale).
- *circles*: A vector that stores sets of 3 values: \f$x_{c}, y_{c}, r\f$ for each detected
circle.
- *HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in
OpenCV.
- *dp = 1*: The inverse ratio of resolution.
- *min_dist = src_gray.rows/8*: Minimum distance between detected centers.
- *min_dist = gray.rows/16*: Minimum distance between detected centers.
- *param_1 = 200*: Upper threshold for the internal Canny edge detector.
- *param_2* = 100\*: Threshold for center detection.
- *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default.
- *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default.
-# Draw the detected circles:
@code{.cpp}
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
@endcode
@snippet samples/cpp/houghcircles.cpp draw
You can see that we will draw the circle(s) on red and the center(s) with a small green dot
-# Display the detected circle(s):
@code{.cpp}
namedWindow( "Hough Circle Transform Demo", WINDOW_AUTOSIZE );
imshow( "Hough Circle Transform Demo", src );
@endcode
-# Wait for the user to exit the program
@code{.cpp}
waitKey(0);
@endcode
-# Display the detected circle(s) and wait for the user to exit the program:
@snippet samples/cpp/houghcircles.cpp display
Result
------
@@ -58,33 +58,15 @@ Explanation
-----------
-# Create some needed variables:
@code{.cpp}
Mat src, src_gray, dst;
int kernel_size = 3;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
char* window_name = "Laplace Demo";
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp variables
-# Loads the source image:
@code{.cpp}
src = imread( argv[1] );
if( !src.data )
{ return -1; }
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp load
-# Apply a Gaussian blur to reduce noise:
@code{.cpp}
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp reduce_noise
-# Convert the image to grayscale using @ref cv::cvtColor
@code{.cpp}
cvtColor( src, src_gray, COLOR_RGB2GRAY );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp convert_to_gray
-# Apply the Laplacian operator to the grayscale image:
@code{.cpp}
Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp laplacian
where the arguments are:
- *src_gray*: The input image.
@@ -96,13 +78,9 @@ Explanation
- *scale*, *delta* and *BORDER_DEFAULT*: We leave them as default values.
-# Convert the output from the Laplacian operator to a *CV_8U* image:
@code{.cpp}
convertScaleAbs( dst, abs_dst );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp convert
-# Display the result in a window:
@code{.cpp}
imshow( window_name, abs_dst );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp display
Results
-------
@@ -115,40 +115,16 @@ Explanation
-----------
-# First we declare the variables we are going to use:
@code{.cpp}
Mat src, src_gray;
Mat grad;
char* window_name = "Sobel Demo - Simple Edge Detector";
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
@endcode
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
-# As usual we load our source image *src*:
@code{.cpp}
src = imread( argv[1] );
if( !src.data )
{ return -1; }
@endcode
@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 )
@code{.cpp}
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
-# Now we convert our filtered image to grayscale:
@code{.cpp}
cvtColor( src, src_gray, COLOR_RGB2GRAY );
@endcode
@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:
@code{.cpp}
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
/// Gradient Y
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
The function takes the following arguments:
- *src_gray*: In our example, the input image. Here it is *CV_8U*
@@ -162,19 +138,12 @@ Explanation
\f$y_{order} = 0\f$. We do analogously for the *y* direction.
-# We convert our partial results back to *CV_8U*:
@code{.cpp}
convertScaleAbs( grad_x, abs_grad_x );
convertScaleAbs( grad_y, abs_grad_y );
@endcode
@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).
@code{.cpp}
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
-# Finally, we show our result:
@code{.cpp}
imshow( window_name, grad );
@endcode
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
Results
-------
@@ -81,76 +81,7 @@ Code
This 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/ImgProc/Morphology_2.cpp)
@code{.cpp}
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
/// Global variables
Mat src, dst;
int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;
char* window_name = "Morphology Transformations Demo";
/* Function Headers */
void Morphology_Operations( int, void* );
/* @function main */
int main( int argc, char** argv )
{
/// Load an image
src = imread( argv[1] );
if( !src.data )
{ return -1; }
/// Create window
namedWindow( window_name, WINDOW_AUTOSIZE );
/// Create Trackbar to select Morphology operation
createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
/// Create Trackbar to select kernel type
createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
&morph_elem, max_elem,
Morphology_Operations );
/// Create Trackbar to choose kernel size
createTrackbar( "Kernel size:\n 2n +1", window_name,
&morph_size, max_kernel_size,
Morphology_Operations );
/// Default start
Morphology_Operations( 0, 0 );
waitKey(0);
return 0;
}
/*
* @function Morphology_Operations
*/
void Morphology_Operations( int, void* )
{
// Since MORPH_X : 2,3,4,5 and 6
int operation = morph_operator + 2;
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
/// Apply the specified morphology operation
morphologyEx( src, dst, operation, element );
imshow( window_name, dst );
}
@endcode
@include cpp/tutorial_code/ImgProc/Morphology_2.cpp
Explanation
-----------
@@ -158,47 +89,23 @@ Explanation
-# Let's check the general structure of the program:
- Load an image
- Create a window to display results of the Morphological operations
- Create 03 Trackbars for the user to enter parameters:
- The first trackbar **"Operator"** returns the kind of morphology operation to use
- Create three Trackbars for the user to enter parameters:
- The first trackbar **Operator** returns the kind of morphology operation to use
(**morph_operator**).
@code{.cpp}
createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat",
window_name, &morph_operator, max_operator,
Morphology_Operations );
@endcode
- The second trackbar **"Element"** returns **morph_elem**, which indicates what kind of
@snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp create_trackbar1
- The second trackbar **Element** returns **morph_elem**, which indicates what kind of
structure our kernel is:
@code{.cpp}
createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
&morph_elem, max_elem,
Morphology_Operations );
@endcode
- The final trackbar **"Kernel Size"** returns the size of the kernel to be used
@snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp create_trackbar2
- The final trackbar **Kernel Size** returns the size of the kernel to be used
(**morph_size**)
@code{.cpp}
createTrackbar( "Kernel size:\n 2n +1", window_name,
&morph_size, max_kernel_size,
Morphology_Operations );
@endcode
@snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp create_trackbar3
- Every time we move any slider, the user's function **Morphology_Operations** will be called
to effectuate a new morphology operation and it will update the output image based on the
current trackbar values.
@code{.cpp}
/*
* @function Morphology_Operations
*/
void Morphology_Operations( int, void* )
{
// Since MORPH_X : 2,3,4,5 and 6
int operation = morph_operator + 2;
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
/// Apply the specified morphology operation
morphologyEx( src, dst, operation, element );
imshow( window_name, dst );
}
@endcode
@snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp morphology_operations
We can observe that the key function to perform the morphology transformations is @ref
cv::morphologyEx . In this example we use four arguments (leaving the rest as defaults):
@@ -216,9 +123,7 @@ Explanation
As you can see the values range from \<2-6\>, that is why we add (+2) to the values
entered by the Trackbar:
@code{.cpp}
int operation = morph_operator + 2;
@endcode
@snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp operation
- **element**: The kernel to be used. We use the function @ref cv::getStructuringElement
to define our own structure.
@@ -77,13 +77,7 @@ Let's check the general structure of the program:
- Load an image (in this case it is defined in the program, the user does not have to enter it
as an argument)
@code{.cpp}
/// Test image - Make sure it s divisible by 2^{n}
src = imread( "../images/chicky_512.jpg" );
if( !src.data )
{ printf(" No data! -- Exiting the program \n");
return -1; }
@endcode
@snippet cpp/tutorial_code/ImgProc/Pyramids.cpp load
- Create a Mat object to store the result of the operations (*dst*) and one to save temporal
results (*tmp*).
@@ -95,40 +89,15 @@ Let's check the general structure of the program:
@endcode
- Create a window to display the result
@code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE );
imshow( window_name, dst );
@endcode
@snippet cpp/tutorial_code/ImgProc/Pyramids.cpp create_window
- Perform an infinite loop waiting for user input.
@code{.cpp}
while( true )
{
int c;
c = waitKey(10);
if( (char)c == 27 )
{ break; }
if( (char)c == 'u' )
{ pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
printf( "** Zoom In: Image x 2 \n" );
}
else if( (char)c == 'd' )
{ pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
printf( "** Zoom Out: Image / 2 \n" );
}
imshow( window_name, dst );
tmp = dst;
}
@endcode
@snippet cpp/tutorial_code/ImgProc/Pyramids.cpp infinite_loop
Our program exits if the user presses *ESC*. Besides, it has two options:
- **Perform upsampling (after pressing 'u')**
@code{.cpp}
pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 )
@endcode
We use the function @ref cv::pyrUp with 03 arguments:
@snippet cpp/tutorial_code/ImgProc/Pyramids.cpp pyrup
We use the function @ref cv::pyrUp with three arguments:
- *tmp*: The current image, it is initialized with the *src* original image.
- *dst*: The destination image (to be shown on screen, supposedly the double of the
@@ -136,11 +105,8 @@ Let's check the general structure of the program:
- *Size( tmp.cols*2, tmp.rows\*2 )\* : The destination size. Since we are upsampling,
@ref cv::pyrUp expects a size double than the input image (in this case *tmp*).
- **Perform downsampling (after pressing 'd')**
@code{.cpp}
pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 )
@endcode
Similarly as with @ref cv::pyrUp , we use the function @ref cv::pyrDown with 03
arguments:
@snippet cpp/tutorial_code/ImgProc/Pyramids.cpp pyrdown
Similarly as with @ref cv::pyrUp , we use the function @ref cv::pyrDown with three arguments:
- *tmp*: The current image, it is initialized with the *src* original image.
- *dst*: The destination image (to be shown on screen, supposedly half the input
@@ -151,15 +117,13 @@ Let's check the general structure of the program:
both dimensions). Otherwise, an error will be shown.
- Finally, we update the input image **tmp** with the current image displayed, so the
subsequent operations are performed on it.
@code{.cpp}
tmp = dst;
@endcode
@snippet cpp/tutorial_code/ImgProc/Pyramids.cpp update_tmp
Results
-------
- After compiling the code above we can test it. The program calls an image **chicky_512.jpg**
that comes in the *tutorial_code/image* folder. Notice that this image is \f$512 \times 512\f$,
that comes in the *samples/data* folder. Notice that this image is \f$512 \times 512\f$,
hence a downsample won't generate any error (\f$512 = 2^{9}\f$). The original image is shown below:
![](images/Pyramids_Tutorial_Original_Image.jpg)
@@ -106,51 +106,23 @@ Explanation
-# Let's check the general structure of the program:
- Load an image. If it is BGR we convert it to Grayscale. For this, remember that we can use
the function @ref cv::cvtColor :
@code{.cpp}
src = imread( argv[1], 1 );
@snippet cpp/tutorial_code/ImgProc/Threshold.cpp load
/// Convert the image to Gray
cvtColor( src, src_gray, COLOR_BGR2GRAY );
@endcode
- Create a window to display the result
@code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE );
@endcode
@snippet cpp/tutorial_code/ImgProc/Threshold.cpp window
- Create \f$2\f$ trackbars for the user to enter user input:
- **Type of thresholding**: Binary, To Zero, etc...
- **Threshold value**
@code{.cpp}
createTrackbar( trackbar_type,
window_name, &threshold_type,
max_type, Threshold_Demo );
@snippet cpp/tutorial_code/ImgProc/Threshold.cpp trackbar
createTrackbar( trackbar_value,
window_name, &threshold_value,
max_value, Threshold_Demo );
@endcode
- Wait until the user enters the threshold value, the type of thresholding (or until the
program exits)
- Whenever the user changes the value of any of the Trackbars, the function *Threshold_Demo*
is called:
@code{.cpp}
/*
* @function Threshold_Demo
*/
void Threshold_Demo( int, void* )
{
/* 0: Binary
1: Binary Inverted
2: Threshold Truncated
3: Threshold to Zero
4: Threshold to Zero Inverted
*/
@snippet cpp/tutorial_code/ImgProc/Threshold.cpp Threshold_Demo
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );
imshow( window_name, dst );
}
@endcode
As you can see, the function @ref cv::threshold is invoked. We give \f$5\f$ parameters:
- *src_gray*: Our input image