diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst b/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst new file mode 100644 index 0000000000..45a43a41bd --- /dev/null +++ b/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-Calib3D: + +*calib3d* module. Camera calibration and 3D reconstruction +----------------------------------------------------------- + +Although we got most of our images in a 2D format they do come from a 3D world. Here you will learn how to find out from the 2D images information about the 3D world. + +.. include:: ../../definitions/noContent.rst diff --git a/doc/tutorials/core/adding_images/adding_images.rst b/doc/tutorials/core/adding_images/adding_images.rst new file mode 100644 index 0000000000..701d5734a3 --- /dev/null +++ b/doc/tutorials/core/adding_images/adding_images.rst @@ -0,0 +1,119 @@ +.. _Adding_Images: + +Adding (blending) two images using OpenCV +******************************************* + +Goal +===== + +In this tutorial you will learn how to: + +* What is *linear blending* and why it is useful. +* Add two images using :add_weighted:`addWeighted <>` + +Cool Theory +================= + +.. note:: + + The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski + +From our previous tutorial, we know already a bit of *Pixel operators*. An interesting dyadic (two-input) operator is the *linear blend operator*: + +.. math:: + + g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x) + +By varying :math:`\alpha` from :math:`0 \rightarrow 1` this operator can be used to perform a temporal *cross-disolve* between two images or videos, as seen in slide shows and film production (cool, eh?) + +Code +===== + +As usual, after the not-so-lengthy explanation, let's go to the code. Here it is: + +.. code-block:: cpp + + #include + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + double alpha = 0.5; double beta; double input; + + Mat src1, src2, dst; + + /// Ask the user enter alpha + std::cout<<" Simple Linear Blender "<>input; + + /// We use the alpha provided by the user iff it is between 0 and 1 + if( alpha >= 0 && alpha <= 1 ) + { alpha = input; } + + /// Read image ( same size, same type ) + src1 = imread("../../images/LinuxLogo.jpg"); + src2 = imread("../../images/WindowsLogo.jpg"); + + if( !src1.data ) { printf("Error loading src1 \n"); return -1; } + if( !src2.data ) { printf("Error loading src2 \n"); return -1; } + + /// Create Windows + namedWindow("Linear Blend", 1); + + beta = ( 1.0 - alpha ); + addWeighted( src1, alpha, src2, beta, 0.0, dst); + + imshow( "Linear Blend", dst ); + + waitKey(0); + return 0; + } + +Explanation +============ + +#. Since we are going to perform: + + .. math:: + + g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x) + + We need two source images (:math:`f_{0}(x)` and :math:`f_{1}(x)`). So, we load them in the usual way: + + .. code-block:: cpp + + src1 = imread("../../images/LinuxLogo.jpg"); + src2 = imread("../../images/WindowsLogo.jpg"); + + .. warning:: + + Since we are *adding* *src1* and *src2*, they both have to be of the same size (width and height) and type. + +#. Now we need to generate the :math:`g(x)` image. For this, the function :add_weighted:`addWeighted <>` comes quite handy: + + .. code-block:: cpp + + beta = ( 1.0 - alpha ); + addWeighted( src1, alpha, src2, beta, 0.0, dst); + + since :add_weighted:`addWeighted <>` produces: + + .. math:: + + dst = \alpha \cdot src1 + \beta \cdot src2 + \gamma + + In this case, :math:`\gamma` is the argument :math:`0.0` in the code above. + +#. Create windows, show the images and wait for the user to end the program. + +Result +======= + +.. image:: images/Adding_Images_Tutorial_Result_0.png + :alt: Blending Images Tutorial - Final Result + :align: center diff --git a/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.png b/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.png new file mode 100644 index 0000000000..1f2a5bb37b Binary files /dev/null and b/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.rst b/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.rst new file mode 100644 index 0000000000..068ebc10d3 --- /dev/null +++ b/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.rst @@ -0,0 +1,265 @@ +.. _Drawing_1: + +Basic Drawing +**************** + +Goals +====== +In this tutorial you will learn how to: + +* Use :point:`Point <>` to define 2D points in an image. +* Use :scalar:`Scalar <>` and why it is useful +* Draw a **line** by using the OpenCV function :line:`line <>` +* Draw an **ellipse** by using the OpenCV function :ellipse:`ellipse <>` +* Draw a **rectangle** by using the OpenCV function :rectangle:`rectangle <>` +* Draw a **circle** by using the OpenCV function :circle:`circle <>` +* Draw a **filled polygon** by using the OpenCV function :fill_poly:`fillPoly <>` + +OpenCV Theory +=============== + +For this tutorial, we will heavily use two structures: :point:`Point <>` and :scalar:`Scalar <>`: + +Point +------- +It represents a 2D point, specified by its image coordinates :math:`x` and :math:`y`. We can define it as: + +.. code-block:: cpp + + Point pt; + pt.x = 10; + pt.y = 8; + +or + +.. code-block:: cpp + + Point pt = Point(10, 8); + +Scalar +------- +* Represents a 4-element vector. The type Scalar is widely used in OpenCV for passing pixel values. +* In this tutorial, we will use it extensively to represent RGB color values (3 parameters). It is not necessary to define the last argument if it is not going to be used. +* Let's see an example, if we are asked for a color argument and we give: + + .. code-block:: cpp + + Scalar( a, b, c ) + + We would be defining a RGB color such as: *Red = c*, *Green = b* and *Blue = a* + + +Code +===== +* This code is in your OpenCV sample folder. Otherwise you can grab it from `here `_ + +Explanation +============= + +#. Since we plan to draw two examples (an atom and a rook), we have to create 02 images and two windows to display them. + + .. code-block:: cpp + + /// Windows names + char atom_window[] = "Drawing 1: Atom"; + char rook_window[] = "Drawing 2: Rook"; + + /// Create black empty images + Mat atom_image = Mat::zeros( w, w, CV_8UC3 ); + Mat rook_image = Mat::zeros( w, w, CV_8UC3 ); + +#. We created functions to draw different geometric shapes. For instance, to draw the atom we used *MyEllipse* and *MyFilledCircle*: + + .. code-block:: cpp + + /// 1. Draw a simple atom: + + /// 1.a. Creating ellipses + MyEllipse( atom_image, 90 ); + MyEllipse( atom_image, 0 ); + MyEllipse( atom_image, 45 ); + MyEllipse( atom_image, -45 ); + + /// 1.b. Creating circles + MyFilledCircle( atom_image, Point( w/2.0, w/2.0) ); + +#. And to draw the rook we employed *MyLine*, *rectangle* and a *MyPolygon*: + + .. code-block:: cpp + + /// 2. Draw a rook + + /// 2.a. Create a convex polygon + MyPolygon( rook_image ); + + /// 2.b. Creating rectangles + rectangle( rook_image, + Point( 0, 7*w/8.0 ), + Point( w, w), + Scalar( 0, 255, 255 ), + -1, + 8 ); + + /// 2.c. Create a few lines + MyLine( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) ); + MyLine( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) ); + MyLine( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) ); + MyLine( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) ); + +#. Let's check what is inside each of these functions: + + * *MyLine* + + .. code-block:: cpp + + void MyLine( Mat img, Point start, Point end ) + { + int thickness = 2; + int lineType = 8; + line( img, + start, + end, + Scalar( 0, 0, 0 ), + thickness, + lineType ); + } + + As we can see, *MyLine* just call the function :line:`line <>`, which does the following: + + * Draw a line from Point **start** to Point **end** + * The line is displayed in the image **img** + * The line color is defined by **Scalar( 0, 0, 0)** which is the RGB value correspondent to **Black** + * The line thickness is set to **thickness** (in this case 2) + * The line is a 8-connected one (**lineType** = 8) + + * *MyEllipse* + + .. code-block:: cpp + + void MyEllipse( Mat img, double angle ) + { + int thickness = 2; + int lineType = 8; + + ellipse( img, + Point( w/2.0, w/2.0 ), + Size( w/4.0, w/16.0 ), + angle, + 0, + 360, + Scalar( 255, 0, 0 ), + thickness, + lineType ); + } + + From the code above, we can observe that the function :ellipse:`ellipse <>` draws an ellipse such that: + + * The ellipse is displayed in the image **img** + * The ellipse center is located in the point **(w/2.0, w/2.0)** and is enclosed in a box of size **(w/4.0, w/16.0)** + * The ellipse is rotated **angle** degrees + * The ellipse extends an arc between **0** and **360** degrees + * The color of the figure will be **Scalar( 255, 255, 0)** which means blue in RGB value. + * The ellipse's **thickness** is 2. + + + * *MyFilledCircle* + + .. code-block:: cpp + + void MyFilledCircle( Mat img, Point center ) + { + int thickness = -1; + int lineType = 8; + + circle( img, + center, + w/32.0, + Scalar( 0, 0, 255 ), + thickness, + lineType ); + } + + Similar to the ellipse function, we can observe that *circle* receives as arguments: + + * The image where the circle will be displayed (**img**) + * The center of the circle denoted as the Point **center** + * The radius of the circle: **w/32.0** + * The color of the circle: **Scalar(0, 0, 255)** which means *Red* in RGB + * Since **thickness** = -1, the circle will be drawn filled. + + * *MyPolygon* + + .. code-block:: cpp + + void MyPolygon( Mat img ) + { + int lineType = 8; + + /** Create some points */ + Point rook_points[1][20]; + rook_points[0][0] = Point( w/4.0, 7*w/8.0 ); + rook_points[0][1] = Point( 3*w/4.0, 7*w/8.0 ); + rook_points[0][2] = Point( 3*w/4.0, 13*w/16.0 ); + rook_points[0][3] = Point( 11*w/16.0, 13*w/16.0 ); + rook_points[0][4] = Point( 19*w/32.0, 3*w/8.0 ); + rook_points[0][5] = Point( 3*w/4.0, 3*w/8.0 ); + rook_points[0][6] = Point( 3*w/4.0, w/8.0 ); + rook_points[0][7] = Point( 26*w/40.0, w/8.0 ); + rook_points[0][8] = Point( 26*w/40.0, w/4.0 ); + rook_points[0][9] = Point( 22*w/40.0, w/4.0 ); + rook_points[0][10] = Point( 22*w/40.0, w/8.0 ); + rook_points[0][11] = Point( 18*w/40.0, w/8.0 ); + rook_points[0][12] = Point( 18*w/40.0, w/4.0 ); + rook_points[0][13] = Point( 14*w/40.0, w/4.0 ); + rook_points[0][14] = Point( 14*w/40.0, w/8.0 ); + rook_points[0][15] = Point( w/4.0, w/8.0 ); + rook_points[0][16] = Point( w/4.0, 3*w/8.0 ); + rook_points[0][17] = Point( 13*w/32.0, 3*w/8.0 ); + rook_points[0][18] = Point( 5*w/16.0, 13*w/16.0 ); + rook_points[0][19] = Point( w/4.0, 13*w/16.0) ; + + const Point* ppt[1] = { rook_points[0] }; + int npt[] = { 20 }; + + fillPoly( img, + ppt, + npt, + 1, + Scalar( 255, 255, 255 ), + lineType ); + } + + To draw a filled polygon we use the function :fill_poly:`fillPoly <>`. We note that: + + * The polygon will be drawn on **img** + * The vertices of the polygon are the set of points in **ppt** + * The total number of vertices to be drawn are **npt** + * The number of polygons to be drawn is only **1** + * The color of the polygon is defined by **Scalar( 255, 255, 255)**, which is the RGB value for *white* + + * *rectangle* + + .. code-block:: cpp + + rectangle( rook_image, + Point( 0, 7*w/8.0 ), + Point( w, w), + Scalar( 0, 255, 255 ), + -1, + 8 ); + + Finally we have the :rectangle:`rectangle <>` function (we did not create a special function for this guy). We note that: + + * The rectangle will be drawn on **rook_image** + * Two opposite vertices of the rectangle are defined by ** Point( 0, 7*w/8.0 )** and **Point( w, w)** + * The color of the rectangle is given by **Scalar(0, 255, 255)** which is the RGB value for *yellow* + * Since the thickness value is given by **-1**, the rectangle will be filled. + +Result +======= + +Compiling and running your program should give you a result like this: + +.. image:: images/Drawing_1_Tutorial_Result_0.png + :alt: Drawing Tutorial 1 - Final Result + :align: center diff --git a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png new file mode 100644 index 0000000000..73a95301a6 Binary files /dev/null and b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0a.png b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0a.png new file mode 100644 index 0000000000..dedf7ee8a3 Binary files /dev/null and b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0a.png differ diff --git a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0b.png b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0b.png new file mode 100644 index 0000000000..649798c191 Binary files /dev/null and b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0b.png differ diff --git a/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst b/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst new file mode 100644 index 0000000000..08e804d9c6 --- /dev/null +++ b/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst @@ -0,0 +1,199 @@ +.. _Basic_Linear_Transform: + +Changing the contrast and brightness of an image! +*************************************************** + +Goal +===== + +In this tutorial you will learn how to: + +* Access pixel values + +* Initialize a matrix with zeros + +* Learn what :saturate_cast:`saturate_cast <>` does and why it is useful + +* Get some cool info about pixel transformations + +Cool Theory +================= + +.. note:: + The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski + +Image Processing +-------------------- + +* A general image processing operator is a function that takes one or more input images and produces an output image. + +* Image transforms can be seen as: + + * Point operators (pixel transforms) + * Neighborhood (area-based) operators + + +Pixel Transforms +^^^^^^^^^^^^^^^^^ + +* In this kind of image processing transform, each output pixel's value depends on only the corresponding input pixel value (plus, potentially, some globally collected information or parameters). + +* Examples of such operators include *brightness and contrast adjustments* as well as color correction and transformations. + +Brightness and contrast adjustments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* Two commonly used point processes are *multiplication* and *addition* with a constant: + + .. math:: + + g(x) = \alpha f(x) + \beta + +* The parameters :math:`\alpha > 0` and :math:`\beta` are often called the *gain* and *bias* parameters; sometimes these parameters are said to control *contrast* and *brightness* respectively. + +* You can think of :math:`f(x)` as the source image pixels and :math:`g(x)` as the output image pixels. Then, more conveniently we can write the expression as: + + .. math:: + + g(i,j) = \alpha \cdot f(i,j) + \beta + + where :math:`i` and :math:`j` indicates that the pixel is located in the *i-th* row and *j-th* column. + +Code +===== + +* The following code performs the operation :math:`g(i,j) = \alpha \cdot f(i,j) + \beta` +* Here it is: + +.. code-block:: cpp + + #include + #include + #include + + using namespace cv; + + double alpha; /**< Simple contrast control */ + int beta; /**< Simple brightness control */ + + int main( int argc, char** argv ) + { + /// Read image given by user + Mat image = imread( argv[1] ); + Mat new_image = Mat::zeros( image.size(), image.type() ); + + /// Initialize values + std::cout<<" Basic Linear Transforms "<>alpha; + std::cout<<"* Enter the beta value [0-100]: "; std::cin>>beta; + + /// Do the operation new_image(i,j) = alpha*image(i,j) + beta + for( int y = 0; y < image.rows; y++ ) + { for( int x = 0; x < image.cols; x++ ) + { for( int c = 0; c < 3; c++ ) + { + new_image.at(y,x)[c] = saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); + } + } + } + + /// Create Windows + namedWindow("Original Image", 1); + namedWindow("New Image", 1); + + /// Show stuff + imshow("Original Image", image); + imshow("New Image", new_image); + + /// Wait until user press some key + waitKey(); + return 0; + } + +Explanation +============ + +#. We begin by creating parameters to save :math:`\alpha` and :math:`\beta` to be entered by the user: + + .. code-block:: cpp + + double alpha; + int beta; + + +#. We load an image using :imread:`imread <>` and save it in a Mat object: + + .. code-block:: cpp + + Mat image = imread( argv[1] ); + +#. Now, since we will make some transformations to this image, we need a new Mat object to store it. Also, we want this to have the following features: + + * Initial pixel values equal to zero + * Same size and type as the original image + + .. code-block:: cpp + + Mat new_image = Mat::zeros( image.size(), image.type() ); + + We observe that :mat_zeros:`Mat::zeros <>` returns a Matlab-style zero initializer based on *image.size()* and *image.type()* + +#. Now, to perform the operation :math:`g(i,j) = \alpha \cdot f(i,j) + \beta` we will access to each pixel in image. Since we are operating with RGB images, we will have three values per pixel (R, G and B), so we will also access them separately. Here is the piece of code: + + .. code-block:: cpp + + for( int y = 0; y < image.rows; y++ ) + { for( int x = 0; x < image.cols; x++ ) + { for( int c = 0; c < 3; c++ ) + { new_image.at(y,x)[c] = saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); } + } + } + + Notice the following: + + * To access each pixel in the images we are using this syntax: *image.at(y,x)[c]* where *y* is the row, *x* is the column and *c* is R, G or B (0, 1 or 2). + + * Since the operation :math:`\alpha \cdot p(i,j) + \beta` can give values out of range or not integers (if :math:`\alpha` is float), we use :saturate_cast:`saturate_cast <>` to make sure the values are valid. + + +#. Finally, we create windows and show the images, the usual way. + + .. code-block:: cpp + + namedWindow("Original Image", 1); + namedWindow("New Image", 1); + + imshow("Original Image", image); + imshow("New Image", new_image); + + waitKey(0); + +.. note:: + + Instead of using the **for** loops to access each pixel, we could have simply used this command: + + .. code-block:: cpp + + image.convertTo(new_image, -1, alpha, beta); + + where :convert_to:`convertTo <>` would effectively perform *new_image = a*image + beta*. However, we wanted to show you how to access each pixel. In any case, both methods give the same result. + +Result +======= + +* Running our code and using :math:`\alpha = 2.2` and :math:`\beta = 50` + + .. code-block:: bash + + $ ./BasicLinearTransforms lena.png + Basic Linear Transforms + ------------------------- + * Enter the alpha value [1.0-3.0]: 2.2 + * Enter the beta value [0-100]: 50 + +* We get this: + +.. image:: images/Basic_Linear_Transform_Tutorial_Result_0.png + :height: 400px + :alt: Basic Linear Transform - Final Result + :align: center diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.png b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.png new file mode 100644 index 0000000000..bef4df653a Binary files /dev/null and b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_a.png b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_a.png new file mode 100644 index 0000000000..978df3f668 Binary files /dev/null and b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_a.png differ diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_b.png b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_b.png new file mode 100644 index 0000000000..904dc044d0 Binary files /dev/null and b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_b.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.png new file mode 100644 index 0000000000..003f44d01d Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_1.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_1.png new file mode 100644 index 0000000000..0334503d6b Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_1.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.png new file mode 100644 index 0000000000..9287b20e1b Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.png new file mode 100644 index 0000000000..482c3bffa5 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_4.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_4.png new file mode 100644 index 0000000000..e0e63812d9 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_4.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.png new file mode 100644 index 0000000000..b0482fddf4 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_6.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_6.png new file mode 100644 index 0000000000..40a079222f Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_6.png differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.png new file mode 100644 index 0000000000..b47a588811 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.png differ diff --git a/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst b/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst new file mode 100644 index 0000000000..fda9b04b04 --- /dev/null +++ b/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst @@ -0,0 +1,285 @@ +.. _Drawing_2: + +Fancy Drawing! +**************** + +Goals +====== + +In this tutorial you will learn how to: + +* Use the *Random Number generator class* (:rng:`RNG <>`) and how to get a random number from a uniform distribution. +* Display Text on an OpenCV window by using the function :put_text:`putText <>` + +Code +===== +* In the previous tutorial we drew diverse geometric figures, giving as input parameters such as coordinates (in the form of :point:`Points <>`), color, thickness, etc. You might have noticed that we gave specific values for these arguments. + +* In this tutorial, we intend to use *random* values for the drawing parameters. Also, we intend to populate our image with a big number of geometric figures. Since we will be initializing them in a random fashion, this process will be automatic and made by using *loops* + +* This code is in your OpenCV sample folder. Otherwise you can grab it from `here `_ + +Explanation +============ + +#. Let's start by checking out the *main* function. We observe that first thing we do is creating a *Random Number Generator* object (RNG): + + .. code-block:: cpp + + RNG rng( 0xFFFFFFFF ); + + RNG implements a random number generator. In this example, *rng* is a RNG element initialized with the value *0xFFFFFFFF* + +#. Then we create a matrix initialized to *zeros* (which means that it will appear as black), specifying its height, width and its type: + + .. code-block:: cpp + + /// Initialize a matrix filled with zeros + Mat image = Mat::zeros( window_height, window_width, CV_8UC3 ); + + /// Show it in a window during DELAY ms + imshow( window_name, image ); + +#. Then we proceed to draw crazy stuff. After taking a look at the code, you can see that it is mainly divided in 8 sections, defined as functions: + + .. code-block:: cpp + + /// Now, let's draw some lines + c = Drawing_Random_Lines(image, window_name, rng); + if( c != 0 ) return 0; + + /// Go on drawing, this time nice rectangles + c = Drawing_Random_Rectangles(image, window_name, rng); + if( c != 0 ) return 0; + + /// Draw some ellipses + c = Drawing_Random_Ellipses( image, window_name, rng ); + if( c != 0 ) return 0; + + /// Now some polylines + c = Drawing_Random_Polylines( image, window_name, rng ); + if( c != 0 ) return 0; + + /// Draw filled polygons + c = Drawing_Random_Filled_Polygons( image, window_name, rng ); + if( c != 0 ) return 0; + + /// Draw circles + c = Drawing_Random_Circles( image, window_name, rng ); + if( c != 0 ) return 0; + + /// Display text in random positions + c = Displaying_Random_Text( image, window_name, rng ); + if( c != 0 ) return 0; + + /// Displaying the big end! + c = Displaying_Big_End( image, window_name, rng ); + + All of these functions follow the same pattern, so we will analyze only a couple of them, since the same explanation applies for all. + +#. Checking out the function **Drawing_Random_Lines**: + + .. code-block:: cpp + + /** + * @function Drawing_Random_Lines + */ + int Drawing_Random_Lines( Mat image, char* window_name, RNG rng ) + { + int lineType = 8; + Point pt1, pt2; + + for( int i = 0; i < NUMBER; i++ ) + { + pt1.x = rng.uniform( x_1, x_2 ); + pt1.y = rng.uniform( y_1, y_2 ); + pt2.x = rng.uniform( x_1, x_2 ); + pt2.y = rng.uniform( y_1, y_2 ); + + line( image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), 8 ); + imshow( window_name, image ); + if( waitKey( DELAY ) >= 0 ) + { return -1; } + } + + return 0; + } + + We can observe the following: + + * The *for* loop will repeat **NUMBER** times. Since the function :line:`line <>` is inside this loop, that means that **NUMBER** lines will be generated. + * The line extremes are given by *pt1* and *pt2*. For *pt1* we can see that: + + .. code-block:: cpp + + pt1.x = rng.uniform( x_1, x_2 ); + pt1.y = rng.uniform( y_1, y_2 ); + + * We know that **rng** is a *Random number generator* object. In the code above we are calling **rng.uniform(a,b)**. This generates a radombly uniformed distribution between the values **a** and **b** (inclusive in **a**, exclusive in **b**). + + * From the explanation above, we deduce that the extremes *pt1* and *pt2* will be random values, so the lines positions will be quite impredictable, giving a nice visual effect (check out the Result section below). + + * As another observation, we notice that in the :line:`line <>` arguments, for the *color* input we enter: + + .. code-block:: cpp + + randomColor(rng) + + Let's check the function implementation: + + .. code-block:: cpp + + static Scalar randomColor( RNG& rng ) + { + int icolor = (unsigned) rng; + return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 ); + } + + As we can see, the return value is an *Scalar* with 3 randomly initialized values, which are used as the *R*, *G* and *B* parameters for the line color. Hence, the color of the lines will be random too! + +#. The explanation above applies for the other functions generating circles, ellipses, polygones, etc. The parameters such as *center* and *vertices* are also generated randomly. + +#. Before finishing, we also should take a look at the functions *Display_Random_Text* and *Displaying_Big_End*, since they both have a few interesting features: + +#. **Display_Random_Text:** + + .. code-block:: cpp + + int Displaying_Random_Text( Mat image, char* window_name, RNG rng ) + { + int lineType = 8; + + for ( int i = 1; i < NUMBER; i++ ) + { + Point org; + org.x = rng.uniform(x_1, x_2); + org.y = rng.uniform(y_1, y_2); + + putText( image, "Testing text rendering", org, rng.uniform(0,8), + rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType); + + imshow( window_name, image ); + if( waitKey(DELAY) >= 0 ) + { return -1; } + } + + return 0; + } + + Everything looks familiar but the expression: + + .. code-block:: cpp + + putText( image, "Testing text rendering", org, rng.uniform(0,8), + rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType); + + + So, what does the function :put_text:`putText <>` do? In our example: + + * Draws the text **"Testing text rendering"** in **image** + * The bottom-left corner of the text will be located in the Point **org** + * The font type is a random integer value in the range: :math:`[0, 8>`. + * The scale of the font is denoted by the expression **rng.uniform(0, 100)x0.05 + 0.1** (meaning its range is: :math:`[0.1, 5.1>`) + * The text color is random (denoted by **randomColor(rng)**) + * The text thickness ranges between 1 and 10, as specified by **rng.uniform(1,10)** + + As a result, we will get (analagously to the other drawing functions) **NUMBER** texts over our image, in random locations. + +#. **Displaying_Big_End** + + .. code-block:: cpp + + int Displaying_Big_End( Mat image, char* window_name, RNG rng ) + { + Size textsize = getTextSize("OpenCV forever!", CV_FONT_HERSHEY_COMPLEX, 3, 5, 0); + Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2); + int lineType = 8; + + Mat image2; + + for( int i = 0; i < 255; i += 2 ) + { + image2 = image - Scalar::all(i); + putText( image2, "OpenCV forever!", org, CV_FONT_HERSHEY_COMPLEX, 3, + Scalar(i, i, 255), 5, lineType ); + + imshow( window_name, image2 ); + if( waitKey(DELAY) >= 0 ) + { return -1; } + } + + return 0; + } + + Besides the function **getTextSize** (which gets the size of the argument text), the new operation we can observe is inside the *foor* loop: + + .. code-block:: cpp + + image2 = image - Scalar::all(i) + + So, **image2** is the substraction of **image** and **Scalar::all(i)**. In fact, what happens here is that every pixel of **image2** will be the result of substracting every pixel of **image** minus the value of **i** (remember that for each pixel we are considering three values such as R, G and B, so each of them will be affected) + + Also remember that the substraction operation *always* performs internally a **saturate** operation, which means that the result obtained will always be inside the allowed range (no negative and between 0 and 255 for our example). + + +Result +======== + +As you just saw in the Code section, the program will sequentially execute diverse drawing functions, which will produce: + +#. First a random set of *NUMBER* lines will appear on screen such as it can be seen in this screenshot: + + .. image:: images/Drawing_2_Tutorial_Result_0.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 0 + :align: center + +#. Then, a new set of figures, these time *rectangles* will follow: + + .. image:: images/Drawing_2_Tutorial_Result_1.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 1 + :align: center + +#. Now some ellipses will appear, each of them with random position, size, thickness and arc length: + + .. image:: images/Drawing_2_Tutorial_Result_2.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 2 + :align: center + +#. Now, *polylines* with 03 segments will appear on screen, again in random configurations. + + .. image:: images/Drawing_2_Tutorial_Result_3.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 3 + :align: center + +#. Filled polygons (in this example triangles) will follow: + + .. image:: images/Drawing_2_Tutorial_Result_4.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 4 + :align: center + +#. The last geometric figure to appear: circles! + + .. image:: images/Drawing_2_Tutorial_Result_5.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 5 + :align: center + +#. Near the end, the text *"Testing Text Rendering"* will appear in a variety of fonts, sizes, colors and positions. + + .. image:: images/Drawing_2_Tutorial_Result_6.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 6 + :align: center + +#. And the big end (which by the way expresses a big truth too): + + .. image:: images/Drawing_2_Tutorial_Result_7.png + :height: 300px + :alt: Drawing Tutorial 2 - Final Result 7 + :align: center + diff --git a/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.png b/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.png new file mode 100644 index 0000000000..e86aee1b37 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.png b/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.png new file mode 100644 index 0000000000..3d2fcdc9ee Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.png b/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.png new file mode 100644 index 0000000000..9cfbef6002 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.png b/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.png new file mode 100644 index 0000000000..2711552b0b Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.png b/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.png new file mode 100644 index 0000000000..2f9b038058 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.png b/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.png new file mode 100644 index 0000000000..3152ea591e Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.png differ diff --git a/doc/tutorials/core/table_of_content_core/table_of_content_core.rst b/doc/tutorials/core/table_of_content_core/table_of_content_core.rst new file mode 100644 index 0000000000..54fd5d1549 --- /dev/null +++ b/doc/tutorials/core/table_of_content_core/table_of_content_core.rst @@ -0,0 +1,88 @@ +.. _Table-Of-Content-Core: + +*core* module. The Core Functionality +----------------------------------------------------------- + +Here you will learn the about the basic building blocks of the library. A must read and know for understanding how to manipulate the images on a pixel level. + +.. toctree:: + :hidden: + + ../adding_images/adding_images + ../basic_linear_transform/basic_linear_transform + ../basic_geometric_drawing/basic_geometric_drawing + ../random_generator_and_text/random_generator_and_text + +.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n + +* :ref:`Adding_Images` + + =============== ====================================================== + |Beginners_4| *Title:* **Linear Blending** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to blend two images! + + =============== ====================================================== + +.. |Beginners_4| image:: images/Adding_Images_Tutorial_Result_0.png + :height: 100pt + :width: 100pt + +* :ref:`Basic_Linear_Transform` + + =============== ==================================================== + |Bas_Lin_Tran| *Title:* **Changing the contrast and brightness of an image** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to change our image appearance! + + =============== ==================================================== + + .. |Bas_Lin_Tran| image:: images/Basic_Linear_Transform_Tutorial_Result_0.png + :height: 100pt + :width: 100pt + + + +* :ref:`Drawing_1` + + =============== ====================================================== + |Beginners_6| *Title:* **Basic Drawing** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to draw simple geometry with OpenCV! + + =============== ====================================================== + +.. |Beginners_6| image:: images/Drawing_1_Tutorial_Result_0.png + :height: 100pt + :width: 100pt + + +* :ref:`Drawing_2` + + =============== ====================================================== + |Beginners_7| *Title:* **Cool Drawing** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will draw some *fancy-looking* stuff using OpenCV! + + =============== ====================================================== + + .. |Beginners_7| image:: images/Drawing_2_Tutorial_Result_7.png + :height: 100pt + :width: 100pt + diff --git a/doc/tutorials/definitions/README.txt b/doc/tutorials/definitions/README.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/doc/tutorials/definitions/noContent.rst b/doc/tutorials/definitions/noContent.rst new file mode 100644 index 0000000000..e9fe6064a6 --- /dev/null +++ b/doc/tutorials/definitions/noContent.rst @@ -0,0 +1,3 @@ + +.. note:: + Unfortunetly we have no tutorials into this section. Nevertheless, our tutorial writting team is working on it. If you have a tutorial suggestion or you have writen yourself a tutorial (or coded a sample code) that you would like to see here please contact us via our :opencv_group:`user group <>`. \ No newline at end of file diff --git a/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst b/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst new file mode 100644 index 0000000000..725af28d80 --- /dev/null +++ b/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-Feature2D: + +*feature2d* module. 2D Features framework +----------------------------------------------------------- + +Learn about how to use the feature points detectors, descriptors and matching framework found inside OpenCV. + +.. include:: ../../definitions/noContent.rst diff --git a/doc/tutorials/general/table_of_content_general/table_of_content_general.rst b/doc/tutorials/general/table_of_content_general/table_of_content_general.rst new file mode 100644 index 0000000000..36dbac2b60 --- /dev/null +++ b/doc/tutorials/general/table_of_content_general/table_of_content_general.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-General: + +General tutorials +----------------------------------------------------------- + +These tutorials are the bottom of the iceberg as they link together multiple of the modules presented above in order to solve complex problems. + +.. include:: ../../definitions/noContent.rst diff --git a/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst b/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst new file mode 100644 index 0000000000..1c2e91d9e4 --- /dev/null +++ b/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-GPU: + +*gpu* module. GPU-Accelerated Computer Vision +----------------------------------------------------------- + +Squeeze out every little computation power from your system by using the power of your video card to run the OpenCV algorithms. + +.. include:: ../../definitions/noContent.rst diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.png b/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.png new file mode 100644 index 0000000000..d3b85ba523 Binary files /dev/null and b/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.png differ diff --git a/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst b/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst new file mode 100644 index 0000000000..56f80ce49e --- /dev/null +++ b/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst @@ -0,0 +1,26 @@ +.. _Table-Of-Content-HighGui: + +*highgui* module. High Level GUI and Media +----------------------------------------------------------- + +This section contains valuable tutorials about how to read/save your image/video files and how to use the built-in graphical user interface of the library. + +.. toctree:: + :hidden: + + ../trackbar/trackbar + +* :ref:`Adding_Trackbars` + + =============== ====================================================== + |Beginners_5| *Title:* **Creating Trackbars** + + *Compatibility:* > OpenCV 2.0 + + We will learn how to add a Trackbar to our applications + + =============== ====================================================== + + .. |Beginners_5| image:: images/Adding_Trackbars_Tutorial_Cover.png + :height: 100pt + :width: 100pt diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Cover.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Cover.png new file mode 100644 index 0000000000..8dfab5ba73 Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Cover.png differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.png new file mode 100644 index 0000000000..29149f0253 Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.png differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.png new file mode 100644 index 0000000000..4c8aba3ce2 Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.png differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1a.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1a.png new file mode 100644 index 0000000000..feec159437 Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1a.png differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1b.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1b.png new file mode 100644 index 0000000000..5873859e31 Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1b.png differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png new file mode 100644 index 0000000000..a74327f8aa Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png differ diff --git a/doc/tutorials/highgui/trackbar/trackbar.rst b/doc/tutorials/highgui/trackbar/trackbar.rst new file mode 100644 index 0000000000..c5b77abed1 --- /dev/null +++ b/doc/tutorials/highgui/trackbar/trackbar.rst @@ -0,0 +1,162 @@ +.. _Adding_Trackbars: + +Adding a Trackbar to our applications! +*************************************** + +* In the previous tutorials (about *linear blending* and the *brightness and contrast adjustments*) you might have noted that we needed to give some **input** to our programs, such as :math:`\alpha` and :math:`beta`. We accomplished that by entering this data using the Terminal + +* Well, it is time to use some fancy GUI tools. OpenCV provides some GUI utilities (*highgui.h*) for you. An example of this is a **Trackbar** + + .. image:: images/Adding_Trackbars_Tutorial_Trackbar.png + :alt: Trackbar example + :align: center + +* In this tutorial we will just modify our two previous programs so that they get the input information from the trackbar. + + +Goals +====== + +In this tutorial you will learn how to: + +* Add a Trackbar in an OpenCV window by using :create_trackbar:`createTrackbar <>` + +Code +===== + +Let's modify the program made in the tutorial :ref:`Adding_Images`. We will let the user enter the :math:`\alpha` value by using the Trackbar. + +.. code-block:: cpp + + #include + #include + + using namespace cv; + + /// Global Variables + const int alpha_slider_max = 100; + int alpha_slider; + double alpha; + double beta; + + /// Matrices to store images + Mat src1; + Mat src2; + Mat dst; + + /** + * @function on_trackbar + * @brief Callback for trackbar + */ + void on_trackbar( int, void* ) + { + alpha = (double) alpha_slider/alpha_slider_max ; + beta = ( 1.0 - alpha ); + + addWeighted( src1, alpha, src2, beta, 0.0, dst); + + imshow( "Linear Blend", dst ); + } + + int main( int argc, char** argv ) + { + /// Read image ( same size, same type ) + src1 = imread("../../images/LinuxLogo.jpg"); + src2 = imread("../../images/WindowsLogo.jpg"); + + if( !src1.data ) { printf("Error loading src1 \n"); return -1; } + if( !src2.data ) { printf("Error loading src2 \n"); return -1; } + + /// Initialize values + alpha_slider = 0; + + /// Create Windows + namedWindow("Linear Blend", 1); + + /// Create Trackbars + char TrackbarName[50]; + sprintf( TrackbarName, "Alpha x %d", alpha_slider_max ); + + createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar ); + + /// Show some stuff + on_trackbar( alpha_slider, 0 ); + + /// Wait until user press some key + waitKey(0); + return 0; + } + + +Explanation +============ + +We only analyze the code that is related to Trackbar: + +#. First, we load 02 images, which are going to be blended. + + .. code-block:: cpp + + src1 = imread("../../images/LinuxLogo.jpg"); + src2 = imread("../../images/WindowsLogo.jpg"); + +#. To create a trackbar, first we have to create the window in which it is going to be located. So: + + .. code-block:: cpp + + namedWindow("Linear Blend", 1); + +#. Now we can create the Trackbar: + + .. code-block:: cpp + + createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar ); + + Note the following: + + * Our Trackbar has a label **TrackbarName** + * The Trackbar is located in the window named **"Linear Blend"** + * The Trackbar values will be in the range from :math:`0` to **alpha_slider_max** (the minimum limit is always **zero**). + * The numerical value of Trackbar is stored in **alpha_slider** + * Whenever the user moves the Trackbar, the callback function **on_trackbar** is called + +#. Finally, we have to define the callback function **on_trackbar** + + .. code-block:: cpp + + void on_trackbar( int, void* ) + { + alpha = (double) alpha_slider/alpha_slider_max ; + beta = ( 1.0 - alpha ); + + addWeighted( src1, alpha, src2, beta, 0.0, dst); + + imshow( "Linear Blend", dst ); + } + + Note that: + + * We use the value of **alpha_slider** (integer) to get a double value for **alpha**. + * **alpha_slider** is updated each time the trackbar is displaced by the user. + * We define *src1*, *src2*, *dist*, *alpha*, *alpha_slider* and *beta* as global variables, so they can be used everywhere. + +Result +======= + +* Our program produces the following output: + + .. image:: images/Adding_Trackbars_Tutorial_Result_0.png + :alt: Adding Trackbars - Windows Linux + :align: center + +* As a manner of practice, you can also add 02 trackbars for the program made in :ref:`Basic_Linear_Transform`. One trackbar to set :math:`\alpha` and another for :math:`\beta`. The output might look like: + + .. image:: images/Adding_Trackbars_Tutorial_Result_1.png + :alt: Adding Trackbars - Lena + :height: 500px + :align: center + + + + + diff --git a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst new file mode 100644 index 0000000000..aa7b7b30bd --- /dev/null +++ b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst @@ -0,0 +1,280 @@ +.. _Morphology_1: + +Eroding and Dilating +********************** + +Goal +===== + +In this tutorial you will learn how to: + +* Apply two very common morphology operators: Dilation and Erosion. For this purpose, you will use the following OpenCV functions: + + * :erode:`erode <>` + * :dilate:`dilate <>` + +Cool Theory +============ + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + +Morphological Operations +-------------------------- + +* In short: A set of operations that process images based on shapes. Morphological operations apply a *structuring element* to an input image and generate an output image. + +* The most basic morphological operations are two: Erosion and Dilation. They have a wide array of uses, i.e. : + + * Removing noise + + * Isolation of individual elements and joining disparate elements in an image. + + * Finding of intensity bumps or holes in an image + +* We will explain dilation and erosion briefly, using the following image as an example: + + .. image:: images/Morphology_1_Tutorial_Theory_Original_Image.png + :alt: Original image + :height: 100px + :align: center + +Dilation +^^^^^^^^^ + +* This operations consists of convoluting an image :math:`A` with some kernel (:math:`B`), which can have any shape or size, usually a square or circle. + +* The kernel :math:`B` has a defined *anchor point*, usually being the center of the kernel. + +* As the kernel :math:`B` is scanned over the image, we compute the maximal pixel value overlapped by :math:`B` and replace the image pixel in the anchor point position with that maximal value. As you can deduce, this maximizing operation causes bright regions within an image to "grow" (therefore the name *dilation*). Take as an example the image above. Applying dilation we can get: + + .. image:: images/Morphology_1_Tutorial_Theory_Dilation.png + :alt: Dilation result - Theory example + :height: 100px + :align: center + +The background (bright) dilates around the black regions of the letter. + +Erosion +^^^^^^^^ + +* This operation is the sister of dilation. What this does is to compute a local minimum over the area of the kernel. + +* As the kernel :math:`B` is scanned over the image, we compute the minimal pixel value overlapped by :math:`B` and replace the image pixel under the anchor point with that minimal value. + +* Analagously to the example for dilation, we can apply the erosion operator to the original image (shown above). You can see in the result below that the bright areas of the image (the background, apparently), get thinner, whereas the dark zones (the "writing"( gets bigger. + + .. image:: images/Morphology_1_Tutorial_Theory_Erosion.png + :alt: Erosion result - Theory example + :height: 100px + :align: center + + +Code +====== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include "highgui.h" + #include + #include + + using namespace cv; + + /// Global variables + Mat src, erosion_dst, dilation_dst; + + int erosion_elem = 0; + int erosion_size = 0; + int dilation_elem = 0; + int dilation_size = 0; + int const max_elem = 2; + int const max_kernel_size = 21; + + /** Function Headers */ + void Erosion( int, void* ); + void Dilation( int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load an image + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + + /// Create windows + namedWindow( "Erosion Demo", CV_WINDOW_AUTOSIZE ); + namedWindow( "Dilation Demo", CV_WINDOW_AUTOSIZE ); + cvMoveWindow( "Dilation Demo", src.cols, 0 ); + + /// Create Erosion Trackbar + createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo", + &erosion_elem, max_elem, + Erosion ); + + createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo", + &erosion_size, max_kernel_size, + Erosion ); + + /// Create Dilation Trackbar + createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo", + &dilation_elem, max_elem, + Dilation ); + + createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo", + &dilation_size, max_kernel_size, + Dilation ); + + /// Default start + Erosion( 0, 0 ); + Dilation( 0, 0 ); + + waitKey(0); + return 0; + } + + /** @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; } + + 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 ); + } + + /** @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 ); + } + + +Explanation +============= + +#. Most of the stuff shown is known by you (if you have any doubt, please refer to the tutorials in previous sections). Let's check the general structure of the program: + + * Load an image (can be RGB or grayscale) + + * Create two windows (one for dilation output, the other for erosion) + + * Create a set of 02 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. + + * Every time we move any slider, the user's function **Erosion** or **Dilation** will be called and it will update the output image based on the current trackbar values. + + Let's analyze these two functions: + +#. **erosion:** + + .. code-block:: 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; } + + 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 ); + } + + * The function that performs the *erosion* operation is :erode:`erode <>`. As we can see, it receives three arguments: + + * *src*: The source image + * *erosion_dst*: The output image + * *element*: This is the kernel we will use to perform the operation. If we do not specify, the default is a simple :math:`3x3` matrix. Otherwise, we can specify its shape. For this, we need to use the function :get_structuring_element:`getStructuringElement <>`: + + .. code-block:: cpp + + Mat element = getStructuringElement( erosion_type, + Size( 2*erosion_size + 1, 2*erosion_size+1 ), + Point( erosion_size, erosion_size ) ); + + We can choose any of three shapes for our kernel: + + * Rectangular box: MORPH_RECT + * Cross: MORPH_CROSS + * Ellipse: MORPH_ELLIPSE + + Then, we just have to specify the size of our kernel and the *anchor point*. If not specified, it is assumed to be in the center. + + * That is all. We are ready to perform the erosion of our image. + + .. note:: + Additionally, there is another parameter that allows you to perform multiple erosions (iterations) at once. We are not using it in this simple tutorial, though. You can check out the Reference for more details. + + +#. **dilation:** + +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-block:: 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 ); + } + + + +Results +======== + +* Compile the code above and execute it with an image as argument. For instance, using this image: + + .. image:: images/Morphology_1_Tutorial_Original_Image.png + :alt: Original image + :height: 200px + :align: center + + We get the results below. Varying the indices in the Trackbars give different output images, naturally. Try them out! You can even try to add a third Trackbar to control the number of iterations. + + .. image:: images/Morphology_1_Tutorial_Cover.png + :alt: Dilation and Erosion application + :height: 400px + :align: center + diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.png new file mode 100644 index 0000000000..90e8c22c96 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.png new file mode 100644 index 0000000000..9c86e5fc9e Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.png new file mode 100644 index 0000000000..501f7f84b1 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.png new file mode 100644 index 0000000000..fafe56c249 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png new file mode 100644 index 0000000000..475d9c72b6 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png new file mode 100644 index 0000000000..da734dfb13 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png new file mode 100644 index 0000000000..ed04720860 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png differ diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst new file mode 100644 index 0000000000..6fc7012979 --- /dev/null +++ b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst @@ -0,0 +1,298 @@ +.. _Smoothing: + +Smoothing Images +****************** + +Goal +===== + +In this tutorial you will learn how to: + +* Apply diverse linear filters to smooth images using OpenCV functions such as: + + * :blur:`blur <>` + * :gaussian_blur:`GaussianBlur <>` + * :median_blur:`medianBlur <>` + * :bilateral_filter:`bilateralFilter <>` + +Cool Theory +============ + +.. note:: + The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski and to *LearningOpenCV* + +* *Smoothing*, also called *blurring*, is a simple and frequently used image processing operation. + +* There are many reasons for smoothing. In this tutorial we will focus on smoothing in order to reduce noise (other uses will be seen in the following tutorials). + +* To perform a smoothing operation we will apply a *filter* to our image. The most common type of filters are *linear*, in which an output pixel's value (i.e. :math:`g(i,j)`) is determined as a weighted sum of input pixel values (i.e. :math:`f(i+k,j+l)`) : + + .. math:: + g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l) + + :math:`h(k,l)` is called the *kernel*, which is nothing more than the coefficients of the filter. + + + It helps to visualize a *filter* as a window of coefficients sliding across the image. + +* There are many kind of filters, here we will mention the most used: + +Normalized Box Filter +----------------------- + +* This filter is the simplest of all! Each output pixel is the *mean* of its kernel neighbors ( all of them contribute with equal weights) + +* Just in case, the kernel is below: + +.. math:: + + K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix} + 1 & 1 & 1 & ... & 1 \\ + 1 & 1 & 1 & ... & 1 \\ + . & . & . & ... & 1 \\ + . & . & . & ... & 1 \\ + 1 & 1 & 1 & ... & 1 + \end{bmatrix} + + +Gaussian Filter +--------------- +* Probably the most useful filter (although not the fastest). Gaussian filtering is done by convolving each point in the input array with a *Gaussian kernel* and then summing them all to produce the output array. + +* Just to make the picture clearer, remember how a 1D Gaussian kernel look like? + + .. image:: images/Smoothing_Tutorial_theory_gaussian_0.jpg + :height: 200px + :align: center + + Assuming that an image is 1D, you can notice that the pixel located in the middle would have the biggest weight. The weight of its neighbors decreases as the spatial distance between them and the center pixel increases. + +.. note:: + + * Remember that a 2D Gaussian can be represented as : + + .. math:: + + G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } + + where :math:`\mu` is the mean (the peak) and :math:`\sigma` represents the variance (per each of the variables :math:`x` and :math:`y`) + + + +Median Filter +-------------- + +The median filter run through each element of the signal (in this case the image) and replace each pixel with the **median** of its neighboring pixels (located in a square neighborhood around the evaluated pixel). + + +Bilateral Filter +----------------- + +* So far, we have explained some filters which main goal is to *smooth* an input image. However, sometimes the filters do not only dissolve the noise, but also smooth away the *edges*. To avoid this (at certain extent at least), we can use a bilateral filter. + +* In an analogous way as the Gaussian filter, the bilateral filter also considers the neighboring pixels with weights assigned to each of them. These weights have two components, the first of which is the same weighting used by the Gaussian filter. The second component takes into account the difference in intensity between the neighboring pixels and the evaluated one. + +* For a more detailed explanation you can check `this link `_ + + + + +Code +====== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/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, CV_WINDOW_AUTOSIZE ); + + /// Load the source image + src = imread( "../images/lena.png", 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), + CV_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; + } + + + +Explanation +============= + +#. Let's check the OpenCV functions that involve only the smoothing procedure, since the rest is already known by now. + +#. **Normalized Block Filter:** + + OpenCV offers the function :blur:`blur <>` to perform smoothing with this filter. + + .. code-block:: 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; } } + + + We specify 4 arguments (more details, check the Reference): + + * *src*: Source image + + * *dst*: Destination image + + * *Size( w,h )*: Defines the size of the kernel to be used ( of width *w* pixels and height *h* pixels) + + * *Point(-1, -1)*: Indicates where the anchor point (the pixel evaluated) is located with respect to the neighborhood. If there is a negative value, then the center of the kernel is considered the anchor point. + +#. **Gaussian Filter:** + + It is performed by the function :gaussian_blur:`GaussianBlur <>` : + + .. code-block:: 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; } } + + Here we use 4 arguments (more details, check the OpenCV reference): + + * *src*: Source image + + * *dst*: Destination image + + * *Size(w, h)*: The size of the kernel to be used (the neighbors to be considered). :math:`w` and :math:`h` have to be odd and positive numbers otherwise thi size will be calculated using the :math:`\sigma_{x}` and :math:`\sigma_{y}` arguments. + + * :math:`\sigma_{x}`: The standard deviation in x. Writing :math:`0` implies that :math:`\sigma_{x}` is calculated using kernel size. + + * :math:`\sigma_{y}`: The standard deviation in y. Writing :math:`0` implies that :math:`\sigma_{y}` is calculated using kernel size. + + +#. **Median Filter:** + + This filter is provided by the :median_blur:`medianBlur <>` function: + + .. code-block:: cpp + + for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) + { medianBlur ( src, dst, i ); + if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } + + We use three arguments: + + * *src*: Source image + + * *dst*: Destination image, must be the same type as *src* + + * *i*: Size of the kernel (only one because we use a square window). Must be odd. + + +#. **Bilateral Filter** + + Provided by OpenCV function :bilateral_filter:`bilateralFilter <>` + + .. code-block:: 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; } } + + We use 5 arguments: + + * *src*: Source image + + * *dst*: Destination image + + * *d*: The diameter of each pixel neighborhood. + + * :math:`\sigma_{Color}`: Standard deviation in the color space. + + * :math:`\sigma_{Space}`: Standard deviation in the coordinate space (in pixel terms) + + +Results +======== + +* The code opens an image (in this case *lena.png*) and display it under the effects of the 4 filters explained. + +* Here is a snapshot of the image smoothed using *medianBlur*: + + .. image:: images/Smoothing_Tutorial_Result_Median_Filter.png + :alt: Smoothing with a median filter + :align: center diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Cover.png b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Cover.png new file mode 100644 index 0000000000..45406171bf Binary files /dev/null and b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.png b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.png new file mode 100644 index 0000000000..b8cf7ca224 Binary files /dev/null and b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.png differ diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_theory_gaussian_0.jpg b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_theory_gaussian_0.jpg new file mode 100644 index 0000000000..e8725b15b0 Binary files /dev/null and b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_theory_gaussian_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst new file mode 100644 index 0000000000..1741111275 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst @@ -0,0 +1,284 @@ +.. _canny_detector: + +Canny Edge Detector +******************** + +Goal +===== + +In this tutorial you will learn how to: + +a. Use the OpenCV function :canny:`Canny <>` to implement the Canny Edge Detector. + +Theory +======= + +#. The *Canny Edge detector* was developed by John F. Canny in 1986. Also known to many as the *optimal detector*, Canny algorithm aims to satisfy three main criteria: + + * **Low error rate:** Meaning a good detection of only existent edges. + * **Good localization:** The distance between edge pixels detected and real edge pixels have to be minimized. + * **Minimal response:** Only one detector response per edge. + +Steps +------ + +#. Filter out any noise. The Gaussian filter is used for this purpose. An example of a Gaussian kernel of :math:`size = 5` that might be used is shown below: + + .. math:: + + K = \dfrac{1}{159}\begin{bmatrix} + 2 & 4 & 5 & 4 & 2 \\ + 4 & 9 & 12 & 9 & 4 \\ + 5 & 12 & 15 & 12 & 5 \\ + 4 & 9 & 12 & 9 & 4 \\ + 2 & 4 & 5 & 4 & 2 + \end{bmatrix} + + +#. Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel: + + a. Apply a pair of convolution masks (in :math:`x` and :math:`y` directions: + + .. math:: + + G_{x} = \begin{bmatrix} + -1 & 0 & +1 \\ + -2 & 0 & +2 \\ + -1 & 0 & +1 + \end{bmatrix} + + G_{y} = \begin{bmatrix} + -1 & -2 & -1 \\ + 0 & 0 & 0 \\ + +1 & +2 & +1 + \end{bmatrix} + + b. Find the gradient strength and direction with: + + .. math:: + \begin{array}{l} + G = \sqrt{ G_{x}^{2} + G_{y}^{2} } \\ + \theta = \arctan(\dfrac{ G_{y} }{ G_{x} }) + \end{array} + + The direction is rounded to one of four possible angles (namely 0, 45, 90 or 135) + +#. *Non-maximum* suppression is applied. This removes pixels that are not considered to be part of an edge. Hence, only thin lines (candidate edges) will remain. + +#. *Hysteresis*: The final step. Canny does use two thresholds (upper and lower): + + a. If a pixel gradient is higher than the *upper* threshold, the pixel is accepted as an edge + b. If a pixel gradient value is below the *lower* threshold, then it is rejected. + c. If the pixel gradient is between the two thresholds, then it will be accepted only if it is connected to a pixel that is above the *upper* threshold. + + Canny recommended a *upper*:*lower* ratio between 2:1 and 3:1. + +#. For more details, you can always consult your favorite Computer Vision book. + +Code +===== + +#. **What does this program do?** + + * Asks the user to enter a numerical value to set the lower threshold for our *Canny Edge Detector* (by means of a Trackbar) + * Applies the *Canny Detector* and generates a **mask** (bright lines representing the edges on a black background). + * Applies the mask obtained on the original image and display it in a window. + +#. The tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + using namespace cv; + + /// Global variables + + Mat src, src_gray; + Mat dst, detected_edges; + + int edgeThresh = 1; + int lowThreshold; + int const max_lowThreshold = 100; + int ratio = 3; + int kernel_size = 3; + char* window_name = "Edge Map"; + + /** + * @function CannyThreshold + * @brief Trackbar callback - Canny thresholds input with a ratio 1:3 + */ + void CannyThreshold(int, void*) + { + /// Reduce noise with a kernel 3x3 + blur( src_gray, detected_edges, Size(3,3) ); + + /// Canny detector + Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); + + /// Using Canny's output as a mask, we display our result + dst = Scalar::all(0); + + src.copyTo( dst, detected_edges); + imshow( window_name, dst ); + } + + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load an image + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + + /// Create a matrix of the same type and size as src (for dst) + dst.create( src.size(), src.type() ); + + /// Convert the image to grayscale + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Create a window + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + /// Create a Trackbar for user to enter threshold + createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold ); + + /// Show the image + CannyThreshold(0, 0); + + /// Wait until user exit program by pressing a key + waitKey(0); + + return 0; + } + +Explanation +============ + +#. Create some needed variables: + + .. code-block:: cpp + + Mat src, src_gray; + Mat dst, detected_edges; + + int edgeThresh = 1; + int lowThreshold; + int const max_lowThreshold = 100; + int ratio = 3; + int kernel_size = 3; + char* window_name = "Edge Map"; + + Note the following: + + a. We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*) + b. We set the kernel size of :math:`3` (for the Sobel operations to be performed internally by the Canny function) + c. We set a maximum value for the lower Threshold of :math:`100`. + + +#. Loads the source image: + + .. code-block:: cpp + + /// Load an image + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + +#. Create a matrix of the same type and size of *src* (to be *dst*) + + .. code-block:: cpp + + dst.create( src.size(), src.type() ); + +#. Convert the image to grayscale (using the function :cvt_color:`cvtColor <>`: + + .. code-block:: cpp + + cvtColor( src, src_gray, CV_BGR2GRAY ); + +#. Create a window to display the results + + .. code-block:: cpp + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + +#. Create a Trackbar for the user to enter the lower threshold for our Canny detector: + + .. code-block:: cpp + + createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold ); + + Observe the following: + + a. The variable to be controlled by the Trackbar is *lowThreshold* with a limit of *max_lowThreshold* (which we set to 100 previously) + b. Each time the Trackbar registers an action, the callback function *CannyThreshold* will be invoked. + +#. Let's check the *CannyThreshold* function, step by step: + + a. First, we blur the image with a filter of kernel size 3: + + .. code-block:: cpp + + blur( src_gray, detected_edges, Size(3,3) ); + + b. Second, we apply the OpenCV function :canny:`Canny <>`: + + .. code-block:: cpp + + Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); + + where the arguments are: + + * *detected_edges*: Source image, grayscale + * *detected_edges*: Output of the detector (can be the same as the input) + * *lowThreshold*: The value entered by the user moving the Trackbar + * *highThreshold*: Set in the program as three times the lower threshold (following Canny's recommendation) + * *kernel_size*: We defined it to be 3 (the size of the Sobel kernel to be used internally) + +#. We fill a *dst* image with zeros (meaning the image is completely black). + + .. code-block:: cpp + + dst = Scalar::all(0); + +#. Finally, we will use the function :copy_to:`copyTo <>` to map only the areas of the image that are identified as edges (on a black background). + + .. code-block:: cpp + + src.copyTo( dst, detected_edges); + + :copy_to:`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. + +#. We display our result: + + .. code-block:: cpp + + imshow( window_name, dst ); + +Result +======= + +#. After compiling the code above, we can run it giving as argument the path to an image. For example, using as an input the following image: + + .. image:: images/Canny_Detector_Tutorial_Original_Image.jpg + :alt: Original test image + :width: 200pt + :align: center + + and moving the slider, trying different threshold, we obtain the following result: + + .. image:: images/Canny_Detector_Tutorial_Result.jpg + :alt: Result after running Canny + :width: 200pt + :align: center + + Notice how the image is superposed to the black background on the edge regions. + + + diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..b4545669fd Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg new file mode 100644 index 0000000000..bbddc716f6 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst new file mode 100644 index 0000000000..a475dfb0da --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst @@ -0,0 +1,222 @@ +.. _copyMakeBorder: + +Adding borders to your images +****************************** + +Goal +===== + +In this tutorial you will learn how to: + +#. Use the OpenCV function :copy_make_border:`copyMakeBorder <>` to set the borders (extra padding to your image). + +Theory +============ + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + + +#. In our previous tutorial we learned to use convolution to operate on images. One problem that naturally arises is how to handle the boundaries. How can we convolve them if the evaluated points are at the edge of the image? + +#. What most of OpenCV functions do is to copy a given image onto another slightly larger image and then automatically pads the boundary (by any of the methods explained in the sample code just below). This way, the convolution can be performed over the needed pixels without problems (the extra padding is cut after the operation is done). + +#. In this tutorial, we will briefly explore two ways of defining the extra padding (border) for an image: + + a. **BORDER_CONSTANT**: Pad the image with a constant value (i.e. black or :math:`0` + + b. **BORDER_REPLICATE**: The row or column at the very edge of the original is replicated to the extra border. + + This will be seen more clearly in the Code section. + + + +Code +====== + +#. **What does this program do?** + + * Load an image + * Let the user choose what kind of padding use in the input image. There are two options: + + #. *Constant value border*: Applies a padding of a constant value for the whole border. This value will be updated randomly each 0.5 seconds. + #. *Replicated border*: The border will be replicated from the pixel values at the edges of the original image. + + The user chooses either option by pressing 'c' (constant) or 'r' (replicate) + * The program finishes when the user presses 'ESC' + +#. The tutorial code's is shown lines below. You can also download it from `here `_ + + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + using namespace cv; + + /// Global Variables + Mat src, dst; + int top, bottom, left, right; + int borderType; + Scalar value; + char* window_name = "copyMakeBorder Demo"; + RNG rng(12345); + + /** @function main */ + int main( int argc, char** argv ) + { + + int c; + + /// Load an image + src = imread( argv[1] ); + + if( !src.data ) + { return -1; + printf(" No data entered, please enter the path to an image file \n"); + } + + /// Brief how-to for this program + printf( "\n \t copyMakeBorder Demo: \n" ); + printf( "\t -------------------- \n" ); + printf( " ** Press 'c' to set the border to a random constant value \n"); + printf( " ** Press 'r' to set the border to be replicated \n"); + printf( " ** Press 'ESC' to exit the program \n"); + + /// Create window + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + /// Initialize arguments for the filter + top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows); + left = (int) (0.05*src.cols); right = (int) (0.05*src.cols); + dst = src; + + imshow( window_name, dst ); + + 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; } + + value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) ); + copyMakeBorder( src, dst, top, bottom, left, right, borderType, value ); + + imshow( window_name, dst ); + } + + return 0; + } + + +Explanation +============= + +#. First we declare the variables we are going to use: + + .. code-block:: cpp + + Mat src, dst; + int top, bottom, left, right; + int borderType; + Scalar value; + char* window_name = "copyMakeBorder Demo"; + RNG rng(12345); + + 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-block:: cpp + + src = imread( argv[1] ); + + if( !src.data ) + { return -1; + printf(" No data entered, please enter the path to an image file \n"); + } + +#. After giving a short intro of how to use the program, we create a window: + + .. code-block:: cpp + + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + +#. 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-block:: 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); + +#. The program begins a *while* loop. If the user presses 'c' or 'r', the *borderType* variable takes the value of *BORDER_CONSTANT* or *BORDER_REPLICATE* respectively: + + .. code-block:: 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; } + +#. In each iteration (after 0.5 seconds), the variable *value* is updated... + + .. code-block:: cpp + + value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) ); + + with a random value generated by the **RNG** variable *rng*. This value is a number picked randomly in the range :math:`[0,255]` + +#. Finally, we call the function :copy_make_border:`copyMakeBorder <>` to apply the respective padding: + + .. code-block:: cpp + + copyMakeBorder( src, dst, top, bottom, left, right, borderType, value ); + + The arguments are: + + a. *src*: Source image + #. *dst*: Destination image + #. *top*, *bottom*, *left*, *right*: Length in pixels of the borders at each side of the image. We define them as being 5% of the original size of the image. + #. *borderType*: Define what type of border is applied. It can be constant or replicate for this example. + #. *value*: If *borderType* is *BORDER_CONSTANT*, this is the value used to fill the border pixels. + +#. We display our output image in the image created previously + + .. code-block:: cpp + + imshow( window_name, dst ); + + + + +Results +======== + +#. After compiling the code above, you can execute it giving as argument the path of an image. The result should be: + + * By default, it begins with the border set to BORDER_CONSTANT. Hence, a succession of random colored borders will be shown. + * If you press 'r', the border will become a replica of the edge pixels. + * If you press 'c', the random colored borders will appear again + * If you press 'ESC' the program will exit. + + Below some screenshot showing how the border changes color and how the *BORDER_REPLICATE* option looks: + + + .. image:: images/CopyMakeBorder_Tutorial_Results.jpg + :alt: Final result after copyMakeBorder application + :width: 750pt + :align: center diff --git a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg new file mode 100644 index 0000000000..1c83dcb4c7 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst new file mode 100644 index 0000000000..03e9148cf4 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst @@ -0,0 +1,198 @@ +.. _filter_2d: + +Making your own linear filters! +******************************** + +Goal +===== + +In this tutorial you will learn how to: + +* Use the OpenCV function :filter2d:`filter2D <>` to create your own linear filters. + +Theory +============ + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + + +Convolution +------------ +In a very general sense, convolution is an operation between every part of an image and an operator (kernel). + +What is a kernel? +------------------ +A kernel is essentially a fixed size array of numerical coefficeints along with an *anchor point* in that array, which is tipically located at the center. + +.. image:: images/filter_2d_tutorial_kernel_theory.png + :alt: kernel example + :align: center + +How does convolution with a kernel work? +----------------------------------------- + +Assume you want to know the resulting value of a particular location in the image. The value of the convolution is calculated in the following way: + +#. Place the kernel anchor on top of a determined pixel, with the rest of the kernel overlaying the corresponding local pixels in the image. + +#. Multiply the kernel coefficients by the corresponding image pixel values and sum the result. + +#. Place the result to the location of the *anchor* in the input image. + +#. Repeat the process for all pixels by scanning the kernel over the entire image. + +Expressing the procedure above in the form of an equation we would have: + +.. math:: + + H(x,y) = \sum_{i=0}^{M_{i} - 1} \sum_{j=0}^{M_{j}-1} I(x+i - a_{i}, y + j - a_{j})K(i,j) + +Fortunately, OpenCV provides you with the function :filter2d:`filter2D <>` so you do not have to code all these operations. + +Code +====== + +#. **What does this program do?** + + * Loads an image + * Performs a *normalized box filter*. For instance, for a kernel of size :math:`size = 3`, the kernel would be: + + .. math:: + + K = \dfrac{1}{3 \cdot 3} \begin{bmatrix} + 1 & 1 & 1 \\ + 1 & 1 & 1 \\ + 1 & 1 & 1 + \end{bmatrix} + + The program will perform the filter operation with kernels of sizes 3, 5, 7, 9 and 11. + + * The filter output (with each kernel) will be shown during 500 milliseconds + +#. The tutorial code's is shown lines below. You can also download it from `here `_ + + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + 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, CV_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; + } +Explanation +============= + +#. Load an image + + .. code-block:: cpp + + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + +#. Create a window to display the result + + .. code-block:: cpp + + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + +#. Initialize the arguments for the linear filter + + .. code-block:: cpp + + anchor = Point( -1, -1 ); + delta = 0; + ddepth = -1; + + +#. 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-block:: cpp + + kernel_size = 3 + 2*( ind%5 ); + kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size); + + The first line is to update the *kernel_size* to odd values in the range: :math:`[3,11]`. The second line actually builds the kernel by setting its value to a matrix filled with :math:`1's` and normalizing it by dividing it between the number of elements. + +#. After setting the kernel, we can generate the filter by using the function :filter2d:`filter2D <>`: + + .. code-block:: cpp + + filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT ); + + The arguments denote: + + a. *src*: Source image + #. *dst*: Destination image + #. *ddepth*: The depth of *dst*. A negative value (such as :math:`-1`) indicates that the depth is the same as the source. + #. *kernel*: The kernel to be scanned through the image + #. *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)* indicates the center by default. + #. *delta*: A value to be added to each pixel during the convolution. By default it is :math:`0` + #. *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial) + +#. Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be updated in the range indicated. + +Results +======== + +#. After compiling the code above, you can execute it giving as argument the path of an image. The result should be a window that shows an image blurred by a normalized filter. Each 0.5 seconds the kernel size should change, as can be seen in the series of snapshots below: + + .. image:: images/filter_2d_tutorial_result.png + :alt: kernel example + :align: center diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png new file mode 100644 index 0000000000..70d4e2d210 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png differ diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.png b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.png new file mode 100644 index 0000000000..416d84d98c Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.png differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst new file mode 100644 index 0000000000..43f7cd0d74 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst @@ -0,0 +1,178 @@ +.. _hough_circle: + +Hough Circle Transform +*********************** + +Goal +===== +In this tutorial you will learn how to: + +* Use the OpenCV function :hough_circles:`HoughCircles <>` to detect circles in an image. + +Theory +======= + +Hough Circle Transform +------------------------ + +* The Hough Circle Transform works in a *roughly* analogous way to the Hough Line Transform explained in the previous tutorial. +* In the line detection case, a line was defined by two parameters :math:`(r, \theta)`. In the circle case, we need three parameters to define a circle: + + .. math:: + + C : ( x_{center}, y_{center}, r ) + + where :math:`(x_{center}, y_{center})` define the center position (gree point) and :math:`r` is the radius, which allows us to completely define a circle, as it can be seen below: + + .. image:: images/Hough_Circle_Tutorial_Theory_0.jpg + :alt: Result of detecting circles with Hough Transform + :height: 200pt + :align: center + +* For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard Hough Transform: *The Hough gradient method*. For more details, please check the book *Learning OpenCV* or your favorite Computer Vision bibliography + +Code +====== + +#. **What does this program do?** + + * Loads an image and blur it to reduce the noise + * Applies the *Hough Circle Transform* to the blurred image . + * Display the detected circle in a window. + +#. The sample code that we will explain can be downloaded from `here `_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace cv; + + /** @function main */ + int main(int argc, char** argv) + { + Mat src, src_gray; + + /// Read the image + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + + /// Convert it to gray + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Reduce the noise so we avoid false circle detection + GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); + + vector circles; + + /// Apply the Hough Transform to find the circles + HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); + + /// Draw the circles detected + 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 ); + } + + /// Show your results + namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); + imshow( "Hough Circle Transform Demo", src ); + + waitKey(0); + return 0; + } + + +Explanation +============ + + +#. Load an image + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + +#. Convert it to grayscale: + + .. code-block:: cpp + + cvtColor( src, src_gray, CV_BGR2GRAY ); + +#. Apply a Gaussian blur to reduce noise and avoid false circle detection: + + .. code-block:: cpp + + GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); + +#. Proceed to apply Hough Circle Transform: + + .. code-block:: cpp + + vector circles; + + HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); + + with the arguments: + + * *src_gray*: Input image (grayscale) + * *circles*: A vector that stores sets of 3 values: :math:`x_{c}, y_{c}, r` for each detected circle. + * *CV_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 + * *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-block:: 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 ); + } + + 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-block:: cpp + + namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); + imshow( "Hough Circle Transform Demo", src ); + +#. Wait for the user to exit the program + + .. code-block:: cpp + + waitKey(0); + + +Result +======= + +The result of running the code above with a test image is shown below: + +.. image:: images/Hough_Circle_Tutorial_Result.jpg + :alt: Result of detecting circles with Hough Transform + :align: center diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg new file mode 100644 index 0000000000..2a599fc6ca Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg new file mode 100644 index 0000000000..8b729ca2fd Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst new file mode 100644 index 0000000000..9a717344f2 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst @@ -0,0 +1,289 @@ +.. _hough_lines: + +Hough Line Transform +********************* + +Goal +===== + +In this tutorial you will learn how to: + +* Use the OpenCV functions :hough_lines:`HoughLines <>` and :hough_lines_p:`HoughLinesP <>` to detect lines in an image. + +Theory +======= + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + +Hough Line Transform +--------------------- +#. The Hough Line Transform is a transform used to detect straight lines. +#. To apply the Transform, first an edge detection pre-processing is desirable. + +How does it work? +^^^^^^^^^^^^^^^^^^ + +#. As you know, a line in the image space can be expressed with two variables. For example: + + a. In the **Cartesian coordinate system:** Parameters: :math:`(m,b)`. + b. In the **Polar coordinate system:** Parameters: :math:`(r,\theta)` + + .. image:: images/Hough_Lines_Tutorial_Theory_0.jpg + :alt: Line variables + :height: 200pt + :align: center + + For Hough Transforms, we will express lines in the *Polar system*. Hence, a line equation can be written as: + + .. math:: + + y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right ) + + Arranging the terms: :math:`r = x \cos \theta + y \sin \theta` + +#. In general for each point :math:`(x_{0}, y_{0})`, we can define the family of lines that goes through that point as: + + .. math:: + + r_{\theta} = x_{0} \cdot \cos \theta + y_{0} \cdot \sin \theta + + Meaning that each pair :math:`(r_{\theta},\theta)` represents each line that passes by :math:`(x_{0}, y_{0})`. + +#. If for a given :math:`(x_{0}, y_{0})` we plot the family of lines that goes through it, we get a sinusoid. For instance, for :math:`x_{0} = 8` and :math:`y_{0} = 6` we get the following plot (in a plane :math:`\theta` - :math:`r`): + + .. image:: images/Hough_Lines_Tutorial_Theory_1.jpg + :alt: Polar plot of a the family of lines of a point + :height: 200pt + :align: center + + We consider only points such that :math:`r > 0` and :math:`0< \theta < 2 \pi`. + +#. We can do the same operation above for all the points in an image. If the curves of two different points intersect in the plane :math:`\theta` - :math:`r`, that means that both points belong to a same line. For instance, following with the example above and drawing the plot for two more points: :math:`x_{1} = 9`, :math:`y_{1} = 4` and :math:`x_{2} = 12`, :math:`y_{2} = 3`, we get: + + .. image:: images/Hough_Lines_Tutorial_Theory_2.jpg + :alt: Polar plot of the family of lines for three points + :height: 200pt + :align: center + The three plots intersect in one single point :math:`(0.925, 9.6)`, these coordinates are the parameters (:math:`\theta, r`) or the line in which :math:`(x_{0}, y_{0})`, :math:`(x_{1}, y_{1})` and :math:`(x_{2}, y_{2})` lay. + +#. What does all the stuff above mean? It means that in general, a line can be *detected* by finding the number of intersections between curves.The more curves intersecting means that the line represented by that intersection have more points. In general, we can define a *threshold* of the minimum number of intersections needed to *detect* a line. + +#. This is what the Hough Line Transform does. It keeps track of the intersection between curves of every point in the image. If the number of intersections is above some *threshold*, then it declares it as a line with the parameters :math:`(\theta, r_{\theta})` of the intersection point. + +Standard and Probabilistic Hough Line Transform +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +OpenCV implements two kind of Hough Line Transforms: + +a. **The Standard Hough Transform** + + * It consists in pretty much what we just explained in the previous section. It gives you as result a vector of couples :math:`(\theta, r_{\theta})` + + * In OpenCV it is implemented with the function :hough_lines:`HoughLines <>` + +b. **The Probabilistic Hough Line Transform** + + * A more efficient implementation of the Hough Line Transform. It gives as output the extremes of the detected lines :math:`(x_{0}, y_{0}, x_{1}, y_{1})` + + * In OpenCV it is implemented with the function :hough_lines_p:`HoughLinesP <>` + +Code +====== + +#. **What does this program do?** + + * Loads an image + * Applies either a *Standard Hough Line Transform* or a *Probabilistic Line Transform*. + * Display the original image and the detected line in two windows. + +#. The sample code that we will explain can be downloaded from `here `_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + + #include + + using namespace cv; + using namespace std; + + void help() + { + cout << "\nThis program demonstrates line finding with the Hough transform.\n" + "Usage:\n" + "./houghlines , Default is pic1.png\n" << endl; + } + + int main(int argc, char** argv) + { + const char* filename = argc >= 2 ? argv[1] : "pic1.png"; + + Mat src = imread(filename, 0); + if(src.empty()) + { + help(); + cout << "can not open " << filename << endl; + return -1; + } + + Mat dst, cdst; + Canny(src, dst, 50, 200, 3); + cvtColor(dst, cdst, CV_GRAY2BGR); + + #if 0 + vector lines; + HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); + + for( size_t i = 0; i < lines.size(); i++ ) + { + float rho = lines[i][0], theta = lines[i][1]; + Point pt1, pt2; + double a = cos(theta), b = sin(theta); + double x0 = a*rho, y0 = b*rho; + pt1.x = cvRound(x0 + 1000*(-b)); + pt1.y = cvRound(y0 + 1000*(a)); + pt2.x = cvRound(x0 - 1000*(-b)); + pt2.y = cvRound(y0 - 1000*(a)); + line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA); + } + #else + vector lines; + HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); + for( size_t i = 0; i < lines.size(); i++ ) + { + Vec4i l = lines[i]; + line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA); + } + #endif + imshow("source", src); + imshow("detected lines", cdst); + + waitKey(); + + return 0; + } + +Explanation +============= + +#. Load an image + + .. code-block:: cpp + + Mat src = imread(filename, 0); + if(src.empty()) + { + help(); + cout << "can not open " << filename << endl; + return -1; + } + +#. Detect the edges of the image by using a Canny detector + + .. code-block:: cpp + + Canny(src, dst, 50, 200, 3); + + Now we will apply the Hough Line Transform. We will explain how to use both OpenCV functions available for this purpose: + +#. **Standard Hough Line Transform** + + a. First, you apply the Transform: + + .. code-block:: cpp + + vector lines; + HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); + + with the following arguments: + + * *dst*: Output of the edge detector. It should be a grayscale image (although in fact it is a binary one) + * *lines*: A vector that will store the parameters :math:`(r,\theta)` of the detected lines + * *rho* : The resolution of the parameter :math:`r` in pixels. We use **1** pixel. + * *theta*: The resolution of the parameter :math:`\theta` in radians. We use **1 degree** (CV_PI/180) + * *threshold*: The minimum number of intersections to "*detect*" a line + * *srn* and *stn*: Default parameters to zero. Check OpenCV reference for more info. + + b. And then you display the result by drawing the lines. + + .. code-block:: cpp + + for( size_t i = 0; i < lines.size(); i++ ) + { + float rho = lines[i][0], theta = lines[i][1]; + Point pt1, pt2; + double a = cos(theta), b = sin(theta); + double x0 = a*rho, y0 = b*rho; + pt1.x = cvRound(x0 + 1000*(-b)); + pt1.y = cvRound(y0 + 1000*(a)); + pt2.x = cvRound(x0 - 1000*(-b)); + pt2.y = cvRound(y0 - 1000*(a)); + line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA); + } + +#. **Probabilistic Hough Line Transform** + + a. First you apply the transform: + + .. code-block:: cpp + + vector lines; + HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); + + with the arguments: + + * *dst*: Output of the edge detector. It should be a grayscale image (although in fact it is a binary one) + * *lines*: A vector that will store the parameters :math:`(x_{start}, y_{start}, x_{end}, y_{end})` of the detected lines + * *rho* : The resolution of the parameter :math:`r` in pixels. We use **1** pixel. + * *theta*: The resolution of the parameter :math:`\theta` in radians. We use **1 degree** (CV_PI/180) + * *threshold*: The minimum number of intersections to "*detect*" a line + * *minLinLength*: The minimum number of points that can form a line. Lines with less than this number of points are disregarded. + * *maxLineGap*: The maximum gap between two points to be considered in the same line. + + b. And then you display the result by drawing the lines. + + .. code-block:: cpp + + for( size_t i = 0; i < lines.size(); i++ ) + { + Vec4i l = lines[i]; + line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA); + } + + +#. Display the original image and the detected lines: + + .. code-block:: cpp + + imshow("source", src); + imshow("detected lines", cdst); + +#. Wait until the user exits the program + + .. code-block:: cpp + + waitKey(); + + +Result +======= + +.. note:: + + The results below are obtained using the slightly fancier version we mentioned in the *Code* section. It still implements the same stuff as above, only adding the Trackbar for the Threshold. + +Using an input image such as: + +.. image:: images/Hough_Lines_Tutorial_Original_Image.jpg + :alt: Result of detecting lines with Hough Transform + :align: center + +We get the following result by using the Probabilistic Hough Line Transform: + +.. image:: images/Hough_Lines_Tutorial_Result.jpg + :alt: Result of detecting lines with Hough Transform + :align: center + +You may observe that the number of lines detected vary while you change the *threshold*. The explanation is sort of evident: If you establish a higher threshold, fewer lines will be detected (since you will need more points to declare a line detected). + diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..2e6211dbd3 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg new file mode 100644 index 0000000000..a6107b02b5 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg new file mode 100644 index 0000000000..e8111eb42e Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg new file mode 100644 index 0000000000..0f297046c5 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg new file mode 100644 index 0000000000..ae0dc05122 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..2369ba57ce Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg new file mode 100644 index 0000000000..2354d9a5db Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg new file mode 100644 index 0000000000..1d5a29d8ba Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg new file mode 100644 index 0000000000..7bc1768b0a Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst new file mode 100644 index 0000000000..b7a8ee7519 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst @@ -0,0 +1,188 @@ +.. _laplace_operator: + +Laplace Operator +***************** + +Goal +===== + + +In this tutorial you will learn how to: + +a. Use the OpenCV function :laplacian:`Laplacian <>` to implement a discrete analog of the *Laplacian operator*. + + +Theory +======= + +#. In the previous tutorial we learned how to use the *Sobel Operator*. It was based on the fact that in the edge area, the pixel intensity shows a "jump" or a high variation of intensity. Getting the first derivative of the intensity, we observed that an edge is characterized by a maximum, as it can be seen in the figure: + + .. image:: images/Laplace_Operator_Tutorial_Theory_Previous.jpg + :alt: Previous theory + :height: 200pt + :align: center + +#. And...what happens if we take the second derivative? + + .. image:: images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg + :alt: Second derivative + :height: 200pt + :align: center + + You can observe that the second derivative is zero! So, we can also use this criterion to attempt to detect edges in an image. However, note that zeros will not only appear in edges (they can actually appear in other meaningless locations); this can be solved by applying filtering where needed. + + +Laplacian Operator +------------------- + +#. From the explanation above, we deduce that the second derivative can be used to *detect edges*. Since images are "*2D*", we would need to take the derivative in both dimensions. Here, the Laplacian operator comes handy. + +#. The *Laplacian operator* is defined by: + + .. math:: + + Laplace(f) = \dfrac{\partial^{2} f}{\partial x^{2}} + \dfrac{\partial^{2} f}{\partial y^{2}} + +#. The Laplacian operator is implemented in OpenCV by the function :laplacian:`Laplacian <>`. In fact, since the Laplacian uses the gradient of images, it calls internally the *Sobel* operator to perform its computation. + +Code +====== + +#. **What does this program do?** + + * Loads an image + * Remove noise by applying a Gaussian blur and then convert the original image to grayscale + * Applies a Laplacian operator to the grayscale image and stores the output image + * Display the result in a window + +#. The tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + using namespace cv; + + /** @function main */ + int main( int argc, char** argv ) + { + Mat src, src_gray, dst; + int kernel_size = 3; + int scale = 1; + int delta = 0; + int ddepth = CV_16S; + char* window_name = "Laplace Demo"; + + int c; + + /// Load an image + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + + /// Remove noise by blurring with a Gaussian filter + GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); + + /// Convert the image to grayscale + cvtColor( src, src_gray, CV_RGB2GRAY ); + + /// Create window + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + /// Apply Laplace function + Mat abs_dst; + + Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT ); + convertScaleAbs( dst, abs_dst ); + + /// Show what you got + imshow( window_name, abs_dst ); + + waitKey(0); + + return 0; + } + + +Explanation +============ + +#. Create some needed variables: + + .. code-block:: 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"; + +#. Loads the source image: + + .. code-block:: cpp + + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + +#. Apply a Gaussian blur to reduce noise: + + .. code-block:: cpp + + GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); + +#. Convert the image to grayscale using :cvt_color:`cvtColor <>` + + .. code-block:: cpp + + cvtColor( src, src_gray, CV_RGB2GRAY ); + +#. Apply the Laplacian operator to the grayscale image: + + .. code-block:: cpp + + Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT ); + + where the arguments are: + + * *src_gray*: The input image. + * *dst*: Destination (output) image + * *ddepth*: Depth of the destination image. Since our input is *CV_8U* we define *ddepth* = *CV_16S* to avoid overflow + * *kernel_size*: The kernel size of the Sobel operator to be applied internally. We use 3 in this example. + * *scale*, *delta* and *BORDER_DEFAULT*: We leave them as default values. + +#. Convert the output from the Laplacian operator to a *CV_8U* image: + + .. code-block:: cpp + + convertScaleAbs( dst, abs_dst ); + +#. Display the result in a window: + + .. code-block:: cpp + + imshow( window_name, abs_dst ); + + +Results +======== + +#. After compiling the code above, we can run it giving as argument the path to an image. For example, using as an input: + + .. image:: images/Laplace_Operator_Tutorial_Original_Image.jpg + :alt: Original test image + :width: 250pt + :align: center + +#. We obtain the following result. Notice how the trees and the silhouette of the cow are approximately well defined (except in areas in which the intensity are very similar, i.e. around the cow's head). Also, note that the roof of the house behind the trees (right side) is notoriously marked. This is due to the fact that the contrast is higher in that region. + + .. image:: images/Laplace_Operator_Tutorial_Result.jpg + :alt: Original test image + :width: 250pt + :align: center diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg new file mode 100644 index 0000000000..ead594e5eb Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg new file mode 100644 index 0000000000..c79d50634a Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg new file mode 100644 index 0000000000..bd77398107 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg new file mode 100644 index 0000000000..ce43af116c Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg new file mode 100644 index 0000000000..7bc1768b0a Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst new file mode 100644 index 0000000000..4b504a8c20 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst @@ -0,0 +1,276 @@ +.. _sobel_derivatives: + +Sobel Derivatives +****************** + + +Goal +===== + +In this tutorial you will learn how to: + +#. Use the OpenCV function :sobel:`Sobel <>` to calculate the derivatives from an image. +#. Use the OpenCV function :scharr:`Scharr <>` to calculate a more accurate derivative for a kernel of size :math:`3 \cdot 3` + +Theory +======== + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + + +#. In the last two tutorials we have seen applicative examples of convolutions. One of the most important convolutions is the computation of derivatives in an image (or an approximation to them). + +#. Why may be important the calculus of the derivatives in an image? Let's imagine we want to detect the *edges* present in the image. For instance: + + + .. image:: images/Sobel_Derivatives_Tutorial_Theory_0.jpg + :alt: How intensity changes in an edge + :height: 200pt + :align: center + + You can easily notice that in an *edge*, the pixel intensity *changes* in a notorious way. A good way to express *changes* is by using *derivatives*. A high change in gradient indicates a major change in the image. + +#. To be more graphical, let's assume we have a 1D-image. An edge is shown by the "jump" in intensity in the plot below: + + .. image:: images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg + :alt: Intensity Plot for an edge + :height: 200pt + :align: center + +#. The edge "jump" can be seen more easily if we take the first derivative (actually, here appears as a maximum) + + .. image:: images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg + :alt: First derivative of Intensity - Plot for an edge + :height: 200pt + :align: center + +#. So, from the explanation above, we can deduce that a method to detect edges in an image can be performed by locating pixel locations where the gradient is higher than its neighbors (or to generalize, higher than a threshold). + +#. More detailed explanation, please refer to **Learning OpenCV** by Bradski and Kaehler + +Sobel Operator +--------------- + +#. The Sobel Operator is a discrete differentiation operator. It computes an approximation of the gradient of an image intensity function. + +#. The Sobel Operator combines Gaussian smoothing and differentiation. + +Formulation +^^^^^^^^^^^^ +Assuming that the image to be operated is :math:`I`: + +#. We calculate two derivatives: + + a. **Horizontal changes**: This is computed by convolving :math:`I` with a kernel :math:`G_{x}` with odd size. For example for a kernel size of 3, :math:`G_{x}` would be computed as: + + .. math:: + + G_{x} = \begin{bmatrix} + -1 & 0 & +1 \\ + -2 & 0 & +2 \\ + -1 & 0 & +1 + \end{bmatrix} * I + + b. **Vertical changes**: This is computed by convolving :math:`I` with a kernel :math:`G_{y}` with odd size. For example for a kernel size of 3, :math:`G_{y}` would be computed as: + + .. math:: + + G_{y} = \begin{bmatrix} + -1 & -2 & -1 \\ + 0 & 0 & 0 \\ + +1 & +2 & +1 + \end{bmatrix} * I + +#. At each point of the image we calculate an approximation of the *gradient* in that point by combining both results above: + + .. math:: + + G = \sqrt{ G_{x}^{2} + G_{y}^{2} } + + Although sometimes the following simpler equation is used: + + .. math:: + + G = |G_{x}| + |G_{y}| + + +.. note:: + + When the size of the kernel is :math:`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 :scharr:`Scharr <>` function. This is as fast but more accurate than the standar Sobel function. It implements the following kernels: + + .. math:: + + G_{x} = \begin{bmatrix} + -3 & 0 & +3 \\ + -10 & 0 & +10 \\ + -3 & 0 & +3 + \end{bmatrix} + + G_{y} = \begin{bmatrix} + -3 & -10 & -3 \\ + 0 & 0 & 0 \\ + +3 & +10 & +3 + \end{bmatrix} + + You can check out more information of this function in the OpenCV reference (:scharr:`Scharr <>`). Also, in the sample code below, you will notice that above the code for :sobel:`Sobel <>` function there is also code for the :scharr:`Scharr <>` function commented. Uncommenting it (and obviously commenting the Sobel stuff) should give you an idea of how this function works. + +Code +===== + +#. **What does this program do?** + + * 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 `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + using namespace cv; + + /** @function main */ + int main( int argc, char** argv ) + { + + Mat src, src_gray; + Mat grad; + char* window_name = "Sobel Demo - Simple Edge Detector"; + int scale = 1; + int delta = 0; + int ddepth = CV_16S; + + int c; + + /// Load an image + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + + GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); + + /// Convert it to gray + cvtColor( src, src_gray, CV_RGB2GRAY ); + + /// Create window + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + /// Generate grad_x and grad_y + Mat grad_x, grad_y; + Mat abs_grad_x, abs_grad_y; + + /// Gradient X + //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT ); + Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); + convertScaleAbs( grad_x, abs_grad_x ); + + /// Gradient Y + //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT ); + Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); + convertScaleAbs( grad_y, abs_grad_y ); + + /// Total Gradient (approximate) + addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); + + imshow( window_name, grad ); + + waitKey(0); + + return 0; + } + + +Explanation +============= + +#. First we declare the variables we are going to use: + + .. code-block:: 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; + +#. As usual we load our source image *src*: + + .. code-block:: cpp + + src = imread( argv[1] ); + + if( !src.data ) + { return -1; } + +#. First, we apply a :gaussian_blur:`GaussianBlur <>` to our image to reduce the noise ( kernel size = 3 ) + + .. code-block:: cpp + + GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); + +#. Now we convert our filtered image to grayscale: + + .. code-block:: cpp + + cvtColor( src, src_gray, CV_RGB2GRAY ); + +#. Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the function :sobel:`Sobel <>` as shown below: + + .. code-block:: 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 ); + 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. + * *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. + * *scale*, *delta* and *BORDER_DEFAULT*: We use default values. + + Notice that to calculate the gradient in *x* direction we use: :math:`x_{order}= 1` and :math:`y_{order} = 0`. We do analogously for the *y* direction. + +#. We convert our partial results back to *CV_8U*: + + .. code-block:: cpp + + convertScaleAbs( grad_x, abs_grad_x ); + convertScaleAbs( grad_y, abs_grad_y ); + + +#. 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-block:: cpp + + addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); + +#. Finally, we show our result: + + .. code-block:: cpp + + imshow( window_name, grad ); + + + +Results +======== + +#. Here is the output of applying our basic detector to *lena.jpg*: + + + .. image:: images/Sobel_Derivatives_Tutorial_Result.jpg + :alt: Result of applying Sobel operator to lena.jpg + :width: 300pt + :align: center diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.png new file mode 100644 index 0000000000..5a7ba1194f Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..2f98d8359b Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png new file mode 100644 index 0000000000..ceb4e6ebc1 Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png new file mode 100644 index 0000000000..faa7859fd9 Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png new file mode 100644 index 0000000000..7de2bc386a Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png new file mode 100644 index 0000000000..d40b9bba16 Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png new file mode 100644 index 0000000000..98d0a92e9a Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst new file mode 100644 index 0000000000..896a564da8 --- /dev/null +++ b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst @@ -0,0 +1,286 @@ +.. _Morphology_2: + +More Morphology Transformations +********************************* + +Goal +===== + +In this tutorial you will learn how to: + +* Use the OpenCV function :morphology_ex:`morphologyEx <>` to apply Morphological Transformation such as: + + * Opening + * Closing + * Morphological Gradient + * Top Hat + * Black Hat + +Cool Theory +============ + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + +In the previous tutorial we covered two basic Morphology operations: + +* Erosion + +* Dilation. + +Based on these two we can effectuate more sophisticated transformations to our images. Here we discuss briefly 05 operations offered by OpenCV: + +Opening +--------- + +* It is obtained by the erosion of an image followed by a dilation. + + .. math:: + + dst = open( src, element) = dilate( erode( src, element ) ) + +* Useful for removing small objects (it is assumed that the objects are bright on a dark foreground) + +* For instance, check out the example below. The image at the left is the original and the image at the right is the result after applying the opening transformation. We can observe that the small spaces in the corners of the letter tend to dissapear. + + .. image:: images/Morphology_2_Tutorial_Theory_Opening.png + :height: 150pt + :alt: Opening + :align: center + +Closing +--------- + +* It is obtained by the dilation of an image followed by an erosion. + + .. math:: + + dst = close( src, element ) = erode( dilate( src, element ) ) + +* Useful to remove small holes (dark regions). + + .. image:: images/Morphology_2_Tutorial_Theory_Closing.png + :height: 150pt + :alt: Closing example + :align: center + + +Morphological Gradient +------------------------ + +* It is the difference between the dilation and the erosion of an image. + + .. math:: + + dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element ) + +* It is useful for finding the outline of an object as can be seen below: + + .. image:: images/Morphology_2_Tutorial_Theory_Gradient.png + :height: 150pt + :alt: Gradient + :align: center + + +Top Hat +--------- + +* It is the difference between an input image and its opening. + + .. math:: + + dst = tophat( src, element ) = src - open( src, element ) + + .. image:: images/Morphology_2_Tutorial_Theory_TopHat.png + :height: 150pt + :alt: Top Hat + :align: center + +Black Hat +---------- + +* It is the difference between the closing and its input image + + .. math:: + + dst = blackhat( src, element ) = close( src, element ) - src + + .. image:: images/Morphology_2_Tutorial_Theory_BlackHat.png + :height: 150pt + :alt: Black Hat + :align: center + +Code +====== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + 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, CV_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 ); + } + + +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 (**morph_operator**). + + .. code-block:: 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 ); + + + + * The second trackbar **"Element"** returns **morph_elem**, which indicates what kind of structure our kernel is: + + .. code-block:: cpp + + createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name, + &morph_elem, max_elem, + Morphology_Operations ); + + * The final trackbar **"Kernel Size"** returns the size of the kernel to be used (**morph_size**) + + .. code-block:: cpp + + createTrackbar( "Kernel size:\n 2n +1", window_name, + &morph_size, max_kernel_size, + Morphology_Operations ); + + + * 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-block:: 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 ); + } + + + We can observe that the key function to perform the morphology transformations is :morphology_ex:`morphologyEx <>`. In this example we use four arguments (leaving the rest as defaults): + + * **src** : Source (input) image + * **dst**: Output image + * **operation**: The kind of morphology transformation to be performed. Note that we have 5 alternatives: + + * *Opening*: MORPH_OPEN : 2 + * *Closing*: MORPH_CLOSE: 3 + * *Gradient*: MORPH_GRADIENT: 4 + * *Top Hat*: MORPH_TOPHAT: 5 + * *Black Hat*: MORPH_BLACKHAT: 6 + + As you can see the values range from <2-6>, that is why we add (+2) to the values entered by the Trackbar: + + .. code-block:: cpp + + int operation = morph_operator + 2; + + * **element**: The kernel to be used. We use the function :get_structuring_element:`getStructuringElement <>` to define our own structure. + + + +Results +======== + +* After compiling the code above we can execute it giving an image path as an argument. For this tutorial we use as input the image: **baboon.jpg**: + + .. image:: images/Morphology_2_Tutorial_Original_Image.jpg + :height: 200pt + :alt: Morphology 2: Original image + :align: center + +* And here are two snapshots of the display window. The first picture shows the output after using the operator **Opening** with a cross kernel. The second picture (right side, shows the result of using a **Blackhat** operator with an ellipse kernel. + + .. image:: images/Morphology_2_Tutorial_Cover.png + :height: 300pt + :alt: Morphology 2: Result sample + :align: center + diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Cover.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Cover.png new file mode 100644 index 0000000000..2a6058508d Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.png new file mode 100644 index 0000000000..ddf66816f5 Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.png differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.png new file mode 100644 index 0000000000..ab34b72ace Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.png differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.png new file mode 100644 index 0000000000..17f5e18cdc Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.png differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Pyramid_Theory.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Pyramid_Theory.png new file mode 100644 index 0000000000..8321c362db Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Pyramid_Theory.png differ diff --git a/doc/tutorials/imgproc/pyramids/pyramids.rst b/doc/tutorials/imgproc/pyramids/pyramids.rst new file mode 100644 index 0000000000..764463f8ba --- /dev/null +++ b/doc/tutorials/imgproc/pyramids/pyramids.rst @@ -0,0 +1,256 @@ +.. _Pyramids: + +Image Pyramids +*************** + +Goal +===== + +In this tutorial you will learn how to: + +* Use the OpenCV functions :pyr_up:`pyrUp <>` and :pyr_down:`pyrDown <>` to downsample or upsample a given image. + +Theory +======= + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + +* Usually we need to convert an image to a size different than its original. For this, there are two possible options: + + * *Upsize* the image (zoom in) or + * *Downsize* it (zoom out). + +* Although there is a *geometric transformation* function in OpenCV that -literally- resize an image (:resize:`resize <>`, which we will show in a future tutorial), in this section we analyze first the use of **Image Pyramids**, which are widely applied in a huge range of vision applications. + +Image Pyramid +-------------- + +* An image pyramid is a collection of images - all arising from a single original image - that are successively downsampled until some desired stopping point is reached. + +* There are two common kinds of image pyramids: + + * **Gaussian pyramid:** Used to downsample images + + * **Laplacian pyramid:** Used to reconstruct an upsampled image from an image lower in the pyramid (with less resolution) + +* In this tutorial we'll use the *Gaussian pyramid*. + +Gaussian Pyramid +^^^^^^^^^^^^^^^^^ + +* Imagine the pyramid as a set of layers in which the higher the layer, the smaller the size. + + .. image:: images/Pyramids_Tutorial_Pyramid_Theory.png + :alt: Pyramid figure + :align: center + +* Every layer is numbered from bottom to top, so layer :math:`(i+1)` (denoted as :math:`G_{i+1}` is smaller than layer :math:`i` (:math:`G_{i}`). + +* To produce layer :math:`(i+1)` in the Gaussian pyramid, we do the following: + + * Convolve :math:`G_{i}` with a Gaussian kernel: + + .. math:: + + \frac{1}{16} \begin{bmatrix} 1 & 4 & 6 & 4 & 1 \\ 4 & 16 & 24 & 16 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix} + + * Remove every even-numbered row and column. + +* You can easily notice that the resulting image will be exactly one-quarter the area of its predecessor. Iterating this process on the input image :math:`G_{0}` (original image) produces the entire pyramid. + +* The procedure above was useful to downsample an image. What if we want to make it bigger?: + + * First, upsize the image to twice the original in each dimension, wit the new even rows and columns filled with zeros (:math:`0`) + + * Perform a convolution with the same kernel shown above (multiplied by 4) to approximate the values of the "missing pixels" + +* These two procedures (downsampling and upsampling as explained above) are implemented by the OpenCV functions :pyr_up:`pyrUp <>` and :pyr_down:`pyrDown <>`, as we will see in an example with the code below: + +.. note:: + When we reduce the size of an image, we are actually *losing* information of the image. + +Code +====== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + #include + + using namespace cv; + + /// Global variables + Mat src, dst, tmp; + char* window_name = "Pyramids Demo"; + + + /** + * @function main + */ + int main( int argc, char** argv ) + { + /// General instructions + printf( "\n Zoom In-Out demo \n " ); + printf( "------------------ \n" ); + printf( " * [u] -> Zoom in \n" ); + printf( " * [d] -> Zoom out \n" ); + printf( " * [ESC] -> Close program \n \n" ); + + /// Test image - Make sure it s divisible by 2^{n} + src = imread( "../images/chicky_512.png" ); + if( !src.data ) + { printf(" No data! -- Exiting the program \n"); + return -1; } + + tmp = src; + dst = tmp; + + /// Create window + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + imshow( window_name, dst ); + + /// Loop + 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; + } + return 0; + } + +Explanation +============= + +#. 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-block:: cpp + + /// Test image - Make sure it s divisible by 2^{n} + src = imread( "../images/chicky_512.png" ); + if( !src.data ) + { printf(" No data! -- Exiting the program \n"); + return -1; } + + * Create a Mat object to store the result of the operations (*dst*) and one to save temporal results (*tmp*). + + .. code-block:: cpp + + Mat src, dst, tmp; + /* ... */ + tmp = src; + dst = tmp; + + + + * Create a window to display the result + + .. code-block:: cpp + + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + imshow( window_name, dst ); + + * Perform an infinite loop waiting for user input. + + .. code-block:: 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; + } + + + Our program exits if the user presses *ESC*. Besides, it has two options: + + * **Perform upsampling (after pressing 'u')** + + .. code-block:: cpp + + pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) + + We use the function :pyr_up:`pyrUp <>` with 03 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 input image) + * *Size( tmp.cols*2, tmp.rows*2 )* : The destination size. Since we are upsampling, :pyr_up:`pyrUp <>` expects a size double than the input image (in this case *tmp*). + + * **Perform downsampling (after pressing 'd')** + + .. code-block:: cpp + + pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) + + Similarly as with :pyr_up:`pyrUp <>`, we use the function :pyr_down:`pyrDown <>` with 03 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 image) + * *Size( tmp.cols/2, tmp.rows/2 )* : The destination size. Since we are upsampling, :pyr_down:`pyrDown <>` expects half the size the input image (in this case *tmp*). + + * Notice that it is important that the input image can be divided by a factor of two (in 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-block:: cpp + + tmp = dst; + + + +Results +======== + +* After compiling the code above we can test it. The program calls an image **chicky_512.png** that comes in the *tutorial_code/image* folder. Notice that this image is :math:`512 \times 512`, hence a downsample won't generate any error (:math:`512 = 2^{9}`). The original image is shown below: + + .. image:: images/Pyramids_Tutorial_Original_Image.png + :alt: Pyramids: Original image + :align: center + +* First we apply two successive :pyr_down:`pyrDown <>` operations by pressing 'd'. Our output is: + + .. image:: images/Pyramids_Tutorial_PyrDown_Result.png + :alt: Pyramids: PyrDown Result + :align: center + +* Note that we should have lost some resolution due to the fact that we are diminishing the size of the image. This is evident after we apply :pyr_up:`pyrUp <>` twice (by pressing 'u'). Our output is now: + + .. image:: images/Pyramids_Tutorial_PyrUp_Result.png + :alt: Pyramids: PyrUp Result + :align: center + + diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.png new file mode 100644 index 0000000000..2f9b038058 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.png new file mode 100644 index 0000000000..6e6aed9aa2 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.png new file mode 100644 index 0000000000..2fbee16bef Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.png new file mode 100644 index 0000000000..f05676b4bf Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.png new file mode 100644 index 0000000000..015e8c330b Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg new file mode 100644 index 0000000000..bbddc716f6 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg new file mode 100644 index 0000000000..5e91f407fa Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg new file mode 100644 index 0000000000..eb02934d38 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg new file mode 100644 index 0000000000..2a599fc6ca Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg new file mode 100644 index 0000000000..a6107b02b5 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg new file mode 100644 index 0000000000..2354d9a5db Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg new file mode 100644 index 0000000000..ead594e5eb Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst b/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst new file mode 100644 index 0000000000..ded5264c02 --- /dev/null +++ b/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst @@ -0,0 +1,234 @@ +.. _Table-Of-Content-ImgProc: + +*imgproc* module. Image Processing +----------------------------------------------------------- + +In this section you will learn about the image processing (manipulation) functions inside OpenCV. + +.. toctree:: + :hidden: + + ../gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter + ../erosion_dilatation/erosion_dilatation + ../opening_closing_hats/opening_closing_hats + ../pyramids/pyramids + ../threshold/threshold + +.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n + +* :ref:`Smoothing` + + ===================== ============================================== + |ImageProcessing_1| *Title:* **Smoothing Images** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Let's take a look at some basic linear filters! + + ===================== ============================================== + + .. |ImageProcessing_1| image:: images/Smoothing_Tutorial_Cover.png + :height: 100pt + :width: 100pt + + +* :ref:`Morphology_1` + + ===================== ============================================== + |ImageProcessing_2| *Title:* **Erosion and Dilation** + + *Compatibility:* > OpenCV 2.0 + + Author: |Author_AnaH| + + Let's *change* the shape of objects! + + ===================== ============================================== + + .. |ImageProcessing_2| image:: images/Morphology_1_Tutorial_Cover.png + :height: 100pt + :width: 100pt + +* :ref:`Morphology_2` + + ================= ================================================== + |Morphology_2| *Title:* **More advanced Morphology Transformations** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Here we investigate different morphology operators + + ================= ================================================== + + .. |Morphology_2| image:: images/Morphology_2_Tutorial_Cover.png + :height: 100pt + :width: 100pt + + +* :ref:`Pyramids` + + ===================== ============================================== + |Pyramids| *Title:* **Image Pyramids** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + What if I need a bigger/smaller image? + + ===================== ============================================== + + .. |Pyramids| image:: images/Pyramids_Tutorial_Cover.png + :height: 100pt + :width: 100pt + + +* :ref:`Basic_Threshold` + + ===================== ============================================== + |Threshold| *Title:* **Basic Thresholding Operations** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + After so much processing, it is time to decide which pixels stay! + + ===================== ============================================== + + .. |Threshold| image:: images/Threshold_Tutorial_Cover.png + :height: 100pt + :width: 100pt + +.. ************************ +.. ImgTrans +.. ************************ + +* :ref:`filter_2d` + + ===================== ============================================== + |Filter_2D| *Title:* **Making your own linear filters** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn to design our own filters by using OpenCV functions + + ===================== ============================================== + + .. |Filter_2D| image:: images/imgtrans/Filter_2D_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + + +* :ref:`copyMakeBorder` + + ===================== ============================================== + |CopyMakeBorder| *Title:* **Adding borders to your images** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to pad our images! + + ===================== ============================================== + + .. |CopyMakeBorder| image:: images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + + +* :ref:`sobel_derivatives` + + ===================== ============================================== + |SobelDerivatives| *Title:* **Sobel Derivatives** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to calculate gradients and use them to detect edges! + + ===================== ============================================== + + .. |SobelDerivatives| image:: images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + +* :ref:`laplace_operator` + + ===================== ============================================== + |LaplaceOperator| *Title:* **Laplace Operator** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn about the *Laplace* operator and how to detect edges with it. + + ===================== ============================================== + + .. |LaplaceOperator| image:: images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + + +* :ref:`canny_detector` + + ===================== ============================================== + |CannyDetector| *Title:* **Canny Edge Detector** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn a sophisticated alternative to detect edges. + + ===================== ============================================== + + .. |CannyDetector| image:: images/imgtrans/Canny_Detector_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + + +* :ref:`hough_lines` + + ===================== ============================================== + |HoughLines| *Title:* **Hough Line Transform** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to detect lines + + ===================== ============================================== + + .. |HoughLines| image:: images/imgtrans/Hough_Lines_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + + +* :ref:`hough_circle` + + ===================== ============================================== + |HoughCircle| *Title:* **Hough Circle Transform** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to detect circles + + ===================== ============================================== + + .. |HoughCircle| image:: images/imgtrans/Hough_Circle_Tutorial_Cover.jpg + :height: 100pt + :width: 100pt + diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.png new file mode 100644 index 0000000000..e0161bd119 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.png new file mode 100644 index 0000000000..ddf66816f5 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.png new file mode 100644 index 0000000000..72e36fa405 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.png new file mode 100644 index 0000000000..ce1bfeb7f1 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Base_Figure.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Base_Figure.png new file mode 100644 index 0000000000..5078bba83d Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Base_Figure.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary.png new file mode 100644 index 0000000000..a06972d250 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png new file mode 100644 index 0000000000..cfd7cc395d Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.png new file mode 100644 index 0000000000..e834992341 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Truncate.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Truncate.png new file mode 100644 index 0000000000..6e4c657ce2 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Truncate.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Zero.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Zero.png new file mode 100644 index 0000000000..6ab10a7808 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Zero.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Zero_Inverted.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Zero_Inverted.png new file mode 100644 index 0000000000..f8cb3b38fc Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Zero_Inverted.png differ diff --git a/doc/tutorials/imgproc/threshold/threshold.rst b/doc/tutorials/imgproc/threshold/threshold.rst new file mode 100644 index 0000000000..1db97811a5 --- /dev/null +++ b/doc/tutorials/imgproc/threshold/threshold.rst @@ -0,0 +1,320 @@ +.. _Basic_Threshold: + +Basic Thresholding Operations +******************************* + +Goal +===== + +In this tutorial you will learn how to: + +* Perform basic thresholding operations using OpenCV function :threshold:`threshold <>` + + +Cool Theory +============ + +.. note:: + The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. + +What is Thresholding? +----------------------- + +* The simplest segmentation method + +* Application example: Separate out regions of an image corresponding to objects which we want to analyze. This separation is based on the variation of intensity between the object pixels and the background pixels. + +* To differentiate the pixels we are interested in from the rest (which will eventually be rejected), we perform a comparison of each pixel intensity value with respect to a *threshold* (determined according to the problem to solve). + +* Once we have separated properly the important pixels, we can set them with a determined value to identify them (i.e. we can assign them a value of :math:`0` (black), :math:`255` (white) or any value that suits your needs). + + .. image:: images/Threshold_Tutorial_Theory_Example.png + :alt: Threshold simple example + :height: 150pt + :align: center + +Types of Thresholding +----------------------- + +* OpenCV offers the function :threshold:`threshold <>` to perform thresholding operations. + +* We can effectuate :math:`5` types of Thresholding operations with this function. We will explain them in the following subsections. + +* To illustrate how these thresholding processes work, let's consider that we have a source image with pixels with intensity values :math:`src(x,y)`. The plot below depicts this. The horizontal blue line represents the threshold :math:`thresh` (fixed). + + .. image:: images/Threshold_Tutorial_Theory_Base_Figure.png + :alt: Threshold Binary + :height: 100pt + :align: center + +Threshold Binary +^^^^^^^^^^^^^^^^^ + +* This thresholding operation can be expressed as: + + .. math:: + + \texttt{dst} (x,y) = \fork{\texttt{maxVal}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise} + +* So, if the intensity of the pixel :math:`src(x,y)` is higher than :math:`thresh`, then the new pixel intensity is set to a :math:`MaxVal`. Otherwise, the pixels are set to :math:`0`. + + .. image:: images/Threshold_Tutorial_Theory_Binary.png + :alt: Threshold Binary + :height: 100pt + :align: center + + +Threshold Binary, Inverted +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* This thresholding operation can be expressed as: + + .. math:: + + \texttt{dst} (x,y) = \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{maxVal}}{otherwise} + +* If the intensity of the pixel :math:`src(x,y)` is higher than :math:`thresh`, then the new pixel intensity is set to a :math:`0`. Otherwise, it is set to :math:`MaxVal`. + + .. image:: images/Threshold_Tutorial_Theory_Binary_Inverted.png + :alt: Threshold Binary Inverted + :height: 100pt + :align: center + +Truncate +^^^^^^^^^ + +* This thresholding operation can be expressed as: + + .. math:: + + \texttt{dst} (x,y) = \fork{\texttt{threshold}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise} + +* The maximum intensity value for the pixels is :math:`thresh`, if :math:`src(x,y)` is greater, then its value is *truncated*. See figure below: + + .. image:: images/Threshold_Tutorial_Theory_Truncate.png + :alt: Threshold Truncate + :height: 100pt + :align: center + + + +Threshold to Zero +^^^^^^^^^^^^^^^^^^ + +* This operation can be expressed as: + + .. math:: + + \texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise} + +* If :math:`src(x,y)` is lower than :math:`thresh`, the new pixel value will be set to :math:`0`. + + .. image:: images/Threshold_Tutorial_Theory_Zero.png + :alt: Threshold Zero + :height: 100pt + :align: center + + +Threshold to Zero, Inverted +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* This operation can be expressed as: + + .. math:: + + \texttt{dst} (x,y) = \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise} + +* If :math:`src(x,y)` is greater than :math:`thresh`, the new pixel value will be set to :math:`0`. + + .. image:: images/Threshold_Tutorial_Theory_Zero_Inverted.png + :alt: Threshold Zero Inverted + :height: 100pt + :align: center + + +Code +====== + +The tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + #include + #include + + using namespace cv; + + /// Global variables + + int threshold_value = 0; + int threshold_type = 3;; + int const max_value = 255; + int const max_type = 4; + int const max_BINARY_value = 255; + + Mat src, src_gray, dst; + char* window_name = "Threshold Demo"; + + char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; + char* trackbar_value = "Value"; + + /// Function headers + void Threshold_Demo( int, void* ); + + /** + * @function main + */ + int main( int argc, char** argv ) + { + /// Load an image + src = imread( argv[1], 1 ); + + /// Convert the image to Gray + cvtColor( src, src_gray, CV_RGB2GRAY ); + + /// Create a window to display results + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + /// Create Trackbar to choose type of Threshold + createTrackbar( trackbar_type, + window_name, &threshold_type, + max_type, Threshold_Demo ); + + createTrackbar( trackbar_value, + window_name, &threshold_value, + max_value, Threshold_Demo ); + + /// Call the function to initialize + Threshold_Demo( 0, 0 ); + + /// Wait until user finishes program + while(true) + { + int c; + c = waitKey( 20 ); + if( (char)c == 27 ) + { break; } + } + + } + + + /** + * @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 + */ + + threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type ); + + imshow( window_name, dst ); + } + + + +Explanation +============= + + +#. Let's check the general structure of the program: + + * Load an image. If it is RGB we convert it to Grayscale. For this, remember that we can use the function :cvt_color:`cvtColor <>`: + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + + /// Convert the image to Gray + cvtColor( src, src_gray, CV_RGB2GRAY ); + + + * Create a window to display the result + + .. code-block:: cpp + + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + * Create :math:`2` trackbars for the user to enter user input: + + * **Type of thresholding**: Binary, To Zero, etc... + * **Threshold value** + + .. code-block:: cpp + + createTrackbar( trackbar_type, + window_name, &threshold_type, + max_type, Threshold_Demo ); + + createTrackbar( trackbar_value, + window_name, &threshold_value, + max_value, Threshold_Demo ); + + * 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-block:: 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 + */ + + threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type ); + + imshow( window_name, dst ); + } + + As you can see, the function :threshold:`threshold <>` is invoked. We give :math:`5` parameters: + + * *src_gray*: Our input image + * *dst*: Destination (output) image + * *threshold_value*: The :math:`thresh` value with respect to which the thresholding operation is made + * *max_BINARY_value*: The value used with the Binary thresholding operations (to set the chosen pixels) + * *threshold_type*: One of the :math:`5` thresholding operations. They are listed in the comment section of the function above. + + + +Results +======== + +#. After compiling this program, run it giving a path to an image as argument. For instance, for an input image as: + + + .. image:: images/Threshold_Tutorial_Original_Image.png + :alt: Threshold Original Image + :height: 200pt + :align: center + +#. First, we try to threshold our image with a *binary threhold inverted*. We expect that the pixels brighter than the :math:`thresh` will turn dark, which is what actually happens, as we can see in the snapshot below (notice from the original image, that the doggie's tongue and eyes are particularly bright in comparison with the image, this is reflected in the output image). + + + .. image:: images/Threshold_Tutorial_Result_Binary_Inverted.png + :alt: Threshold Result Binary Inverted + :height: 200pt + :align: center + + +#. Now we try with the *threshold to zero*. With this, we expect that the darkest pixels (below the threshold) will become completely black, whereas the pixels with value greater than the threshold will keep its original value. This is verified by the following snapshot of the output image: + + .. image:: images/Threshold_Tutorial_Result_Zero.png + :alt: Threshold Result Zero + :height: 200pt + :align: center + + diff --git a/doc/tutorials/introduction/display_image/display_image.rst b/doc/tutorials/introduction/display_image/display_image.rst new file mode 100644 index 0000000000..72fe5c1767 --- /dev/null +++ b/doc/tutorials/introduction/display_image/display_image.rst @@ -0,0 +1,112 @@ +.. _Display_Image: + +Display an Image +***************** + +Goal +===== + +In this tutorial you will learn how to: + +* Load an image using :imread:`imread <>` +* Create a named window (using :named_window:`namedWindow <>`) +* Display an image in an OpenCV window (using :imshow:`imshow <>`) + +Code +===== + +Here it is: + +.. code-block:: cpp + + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + Mat image; + image = imread( argv[1], 1 ); + + if( argc != 2 || !image.data ) + { + printf( "No image data \n" ); + return -1; + } + + namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); + imshow( "Display Image", image ); + + waitKey(0); + + return 0; + } + + +Explanation +============ + +#. .. code-block:: cpp + + #include + #include + + using namespace cv; + + These are OpenCV headers: + + * *cv.h* : Main OpenCV functions + * *highgui.h* : Graphical User Interface (GUI) functions + + Now, let's analyze the *main* function: + +#. .. code-block:: cpp + + Mat image; + + We create a Mat object to store the data of the image to load. + +#. .. code-block:: cpp + + image = imread( argv[1], 1 ); + + Here, we called the function :imread:`imread <>` which basically loads the image specified by the first argument (in this case *argv[1]*). The second argument is by default. + +#. After checking that the image data was loaded correctly, we want to display our image, so we create a window: + + .. code-block:: cpp + + namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); + + + :named_window:`namedWindow <>` receives as arguments the window name ("Display Image") and an additional argument that defines windows properties. In this case **CV_WINDOW_AUTOSIZE** indicates that the window will adopt the size of the image to be displayed. + +#. Finally, it is time to show the image, for this we use :imshow:`imshow <>` + + .. code-block:: cpp + + imshow( "Display Image", image ) + +#. Finally, we want our window to be displayed until the user presses a key (otherwise the program would end far too quickly): + + .. code-block:: cpp + + waitKey(0); + + We use the :wait_key:`waitKey <>` function, which allow us to wait for a keystroke during a number of milliseconds (determined by the argument). If the argument is zero, then it will wait indefinitely. + +Result +======= + +* Compile your code and then run the executable giving a image path as argument: + + .. code-block:: bash + + ./DisplayImage HappyFish.jpg + +* You should get a nice window as the one shown below: + + .. image:: images/Display_Image_Tutorial_Result.png + :alt: Display Image Tutorial - Final Result + :align: center diff --git a/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.png b/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.png new file mode 100644 index 0000000000..62e3878e03 Binary files /dev/null and b/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-0.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-0.png new file mode 100644 index 0000000000..3ad10d4920 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-0.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-1.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-1.png new file mode 100644 index 0000000000..31c284a1a9 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-1.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-10.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-10.png new file mode 100644 index 0000000000..48bf684ab1 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-10.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-11.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-11.png new file mode 100644 index 0000000000..edca4abe13 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-11.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-12.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-12.png new file mode 100644 index 0000000000..47f1fe432d Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-12.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-13.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-13.png new file mode 100644 index 0000000000..2a2d9b3ad0 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-13.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-14.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-14.png new file mode 100644 index 0000000000..6cd7878d43 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-14.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-15.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-15.png new file mode 100644 index 0000000000..337fd00309 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-15.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-2.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-2.png new file mode 100644 index 0000000000..ddb86ea7c3 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-2.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-3.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-3.png new file mode 100644 index 0000000000..0bfad99975 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-3.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-4.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-4.png new file mode 100644 index 0000000000..8a1e2c4a3e Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-4.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-5.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-5.png new file mode 100644 index 0000000000..ba5504a925 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-5.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-6.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-6.png new file mode 100644 index 0000000000..0b16972a10 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-6.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-7.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-7.png new file mode 100644 index 0000000000..b9aa3187e4 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-7.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-8.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-8.png new file mode 100644 index 0000000000..800f67b653 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-8.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-9.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-9.png new file mode 100644 index 0000000000..e56b28c375 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-9.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/eclipse_cpp_logo.jpeg b/doc/tutorials/introduction/linux_eclipse/images/eclipse_cpp_logo.jpeg new file mode 100644 index 0000000000..f1aecfe85b Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/eclipse_cpp_logo.jpeg differ diff --git a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst new file mode 100644 index 0000000000..38cd647b23 --- /dev/null +++ b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst @@ -0,0 +1,247 @@ +.. _Linux_Eclipse_Usage: + +Using OpenCV with Eclipse (plugin CDT) +**************************************** + +.. note:: + For me at least, this works, is simple and quick. Suggestions are welcome + +Prerequisites +=============== + +#. Having installed `Eclipse `_ in your workstation (only the CDT plugin for C/C++ is needed). You can follow the following steps: + + * Go to the Eclipse site + + * Download `Eclipse IDE for C/C++ Developers `_ . Choose the link according to your workstation. + +#. Having installed OpenCV. If not yet, go :ref:`here ` + +Making a project +================= + +#. Start Eclipse. Just run the executable that comes in the folder. + +#. Go to **File -> New -> C/C++ Project** + + .. image:: images/Eclipse_Tutorial_Screenshot-0.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 0 + :align: center + +#. Choose a name for your project (i.e. DisplayImage). An **Empty Project** should be okay for this example. + + .. image:: images/Eclipse_Tutorial_Screenshot-1.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 1 + :align: center + +#. Leave everything else by default. Press **Finish**. + + .. image:: images/Eclipse_Tutorial_Screenshot-2.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 2 + :align: center + +#. Your project (in this case DisplayImage) should appear in the **Project Navigator** (usually at the left side of your window). + + .. image:: images/Eclipse_Tutorial_Screenshot-3.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 3 + :align: center + + +#. Now, let's add a source file using OpenCV: + + * Right click on **DisplayImage** (in the Navigator). **New -> Folder** . + + .. image:: images/Eclipse_Tutorial_Screenshot-4.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 4 + :align: center + + * Name your folder **src** and then hit **Finish** + + .. image:: images/Eclipse_Tutorial_Screenshot-5.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 5 + :align: center + + * Right click on your newly created **src** folder. Choose **New source file**: + + .. image:: images/Eclipse_Tutorial_Screenshot-6.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 6 + :align: center + + * Call it **DisplayImage.cpp**. Hit **Finish** + + .. image:: images/Eclipse_Tutorial_Screenshot-7.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 7 + :align: center + +#. So, now you have a project with a empty .cpp file. Let's fill it with some sample code (in other words, copy and paste the snippet below): + + .. code-block:: cpp + + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + Mat image; + image = imread( argv[1], 1 ); + + if( argc != 2 || !image.data ) + { + printf( "No image data \n" ); + return -1; + } + + namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); + imshow( "Display Image", image ); + + waitKey(0); + + return 0; + } + +#. We are only missing one final step: To tell OpenCV where the OpenCV headers and libraries are. For this, do the following: + + * + Go to **Project-->Properties** + + .. image:: images/Eclipse_Tutorial_Screenshot-8.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 8 + :align: center + + * + In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab. Here we will enter the headers and libraries info: + + a. + In **GCC C++ Compiler**, go to **Includes**. In **Include paths(-l)** you should include the path of the folder where opencv was installed. In our example, this is ``/usr/local/include/opencv``. + + .. image:: images/Eclipse_Tutorial_Screenshot-9.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 9 + :align: center + + .. note:: + If you do not know where your opencv files are, open the **Terminal** and type: + + .. code-block:: bash + + pkg-config --cflags opencv + + For instance, that command gave me this output: + + .. code-block:: bash + + -I/usr/local/include/opencv -I/usr/local/include + + + b. + Now go to **GCC C++ Linker**,there you have to fill two spaces: + + * In **Library search path (-L)** you have to write the path to where the opencv libraries reside, in my case the path is: + :: + + /usr/local/lib + + .. + + * + In **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 3 first on the list below are enough (for simple applications) . In my case, I am putting all of them since I plan to use the whole bunch: + + + * opencv_core + * opencv_imgproc + * opencv_highgui + * opencv_ml + * opencv_video + * opencv_features2d + * opencv_calib3d + * opencv_objdetect + * opencv_contrib + * opencv_legacy + * opencv_flann + + .. image:: images/Eclipse_Tutorial_Screenshot-10.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 10 + :align: center + + .. note:: + + If you don't know where your libraries are (or you are just psychotic and want to make sure the path is fine), type in **Terminal**: + + .. code-block:: bash + + pkg-config --libs opencv + + My output (in case you want to check) was: + + .. code-block:: bash + + -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann + + Now you are done. Click **OK** + + * Your project should be ready to be built. For this, go to **Project->Build all** + + .. image:: images/Eclipse_Tutorial_Screenshot-11.png + :height: 400px + :alt: Eclipse Tutorial Screenshot 11 + :align: center + + In the Console you should get something like + + .. image:: images/Eclipse_Tutorial_Screenshot-12.png + :height: 200px + :alt: Eclipse Tutorial Screenshot 12 + :align: center + + If you check in your folder, there should be an executable there. + +Running the executable +======================== + +So, now we have an executable ready to run. If we were to use the Terminal, we would probably do something like: + +.. code-block:: bash + + cd + cd src + ./DisplayImage ../images/HappyLittleFish.jpg + +Assuming that the image to use as the argument would be located in /images/HappyLittleFish.jpg. We can still do this, but let's do it from Eclipse: + + +#. Go to **Run->Run Configurations** + + .. image:: images/Eclipse_Tutorial_Screenshot-13.png + :height: 300px + :alt: Eclipse Tutorial Screenshot 13 + :align: center + +#. Under C/C++ Application you will see the name of your executable + Debug (if not, click over C/C++ Application a couple of times). Select the name (in this case **DisplayImage Debug**). + +#. Now, in the right side of the window, choose the **Arguments** Tab. Write the path of the image file we want to open (path relative to the workspace/DisplayImage folder). Let's use **HappyLittleFish.jpg**: + + .. image:: images/Eclipse_Tutorial_Screenshot-14.png + :height: 300px + :alt: Eclipse Tutorial Screenshot 14 + :align: center + +#. Click on the **Apply** button and then in Run. An OpenCV window should pop up with the fish image (or whatever you used). + + .. image:: images/Eclipse_Tutorial_Screenshot-15.png + :alt: Eclipse Tutorial Screenshot 15 + :align: center + + +#. Congratulations! You are ready to have fun with OpenCV using Eclipse. diff --git a/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.png b/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.png new file mode 100644 index 0000000000..524f7e2143 Binary files /dev/null and b/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.png differ diff --git a/doc/tutorials/introduction/linux_gcc_cmake/images/gccegg-65.png b/doc/tutorials/introduction/linux_gcc_cmake/images/gccegg-65.png new file mode 100644 index 0000000000..cd59029373 Binary files /dev/null and b/doc/tutorials/introduction/linux_gcc_cmake/images/gccegg-65.png differ diff --git a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst new file mode 100644 index 0000000000..7b9d5ed3c7 --- /dev/null +++ b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst @@ -0,0 +1,84 @@ +.. _Linux_GCC_Usage: + +Using OpenCV with gcc and CMake +********************************* + +.. note:: + We assume that you have successfully installed OpenCV in your workstation. + +The easiest way of using OpenCV in your code is to use `CMake `_. A few advantages (taken from the Wiki): + +* No need to change anything when porting between Linux and Windows +* Can easily be combined with other tools by CMake( i.e. Qt, ITK and VTK ) + +If you are not familiar with CMake, checkout the `tutorial `_ on its website. + +Steps +====== + +Create a program using OpenCV +------------------------------- + +Let's use a simple program such as DisplayImage.cpp shown below. + +.. code-block:: cpp + + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + Mat image; + image = imread( argv[1], 1 ); + + if( argc != 2 || !image.data ) + { + printf( "No image data \n" ); + return -1; + } + + namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); + imshow( "Display Image", image ); + + waitKey(0); + + return 0; + } + +Create a CMake file +--------------------- +Now you have to create your CMakeLists.txt file. It should look like this: + +.. code-block:: cmake + + project( DisplayImage ) + find_package( OpenCV REQUIRED ) + add_executable( DisplayImage DisplayImage ) + target_link_libraries( DisplayImage ${OpenCV_LIBS} ) + +Generate the executable +------------------------- +This part is easy, just proceed as with any other project using CMake: + +.. code-block:: bash + + cd + cmake . + make + +Result +-------- +By now you should have an executable (called DisplayImage in this case). You just have to run it giving an image location as an argument, i.e.: + +.. code-block:: bash + + ./DisplayImage lena.jpg + +You should get a nice window as the one shown below: + +.. image:: images/GCC_CMake_Example_Tutorial.png + :alt: Display Image - Lena + :align: center + diff --git a/doc/tutorials/introduction/linux_install/images/ubuntu_logo.jpeg b/doc/tutorials/introduction/linux_install/images/ubuntu_logo.jpeg new file mode 100644 index 0000000000..50544c119c Binary files /dev/null and b/doc/tutorials/introduction/linux_install/images/ubuntu_logo.jpeg differ diff --git a/doc/tutorials/introduction/linux_install/linux_install.rst b/doc/tutorials/introduction/linux_install/linux_install.rst new file mode 100644 index 0000000000..52f080addd --- /dev/null +++ b/doc/tutorials/introduction/linux_install/linux_install.rst @@ -0,0 +1,85 @@ +.. _Linux-Installation: + +Installation in Linux +*********************** +These steps have been tested for Ubuntu 10.04 but should work with other distros. + +Required packages +================== + + * GCC 4.x or later. This can be installed with + + .. code-block:: bash + + sudo apt-get install build-essential + + * CMake 2.6 or higher + * Subversion (SVN) client + * GTK+2.x or higher, including headers + * pkgconfig + * libpng, zlib, libjpeg, libtiff, libjasper with development files (e.g. libpjeg-dev) + * Python 2.3 or later with developer packages (e.g. python-dev) + * SWIG 1.3.30 or later + * libavcodec + * libdc1394 2.x + +All the libraries above can be installed via Terminal or by using Synaptic Manager + +Getting OpenCV source code +============================ + +You can use the latest stable OpenCV version available in *sourceforge* or you can grab the latest snapshot from the SVN repository: + +Getting the latest stable OpenCV version +------------------------------------------ + +* Go to http://sourceforge.net/projects/opencvlibrary + +* Download the source tarball and unpack it + + +Getting the cutting-edge OpenCV from SourceForge SVN repository +----------------------------------------------------------------- + +Launch SVN client and checkout either + +a. the current OpenCV snapshot from here: https://code.ros.org/svn/opencv/trunk + +#. or the latest tested OpenCV snapshot from here: http://code.ros.org/svn/opencv/tags/latest_tested_snapshot + +In Ubuntu it can be done using the following command, e.g.: + +.. code-block:: bash + + cd ~/ + svn co https://code.ros.org/svn/opencv/trunk + + +Building OpenCV from source using CMake, using the command line +================================================================ + +#. Create a temporary directory, which we denote as , where you want to put the generated Makefiles, project files as well the object filees and output binaries + +#. Enter the and type + + .. code-block:: bash + + cmake [] + + For example + + .. code-block:: bash + + cd ~/opencv + mkdir release + cd release + cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX= /usr/local + +#. Enter the created temporary directory () and proceed with: + + .. code-block:: bash + + make + sudo make install + + diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.png new file mode 100644 index 0000000000..91c9eb6b76 Binary files /dev/null and b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.png differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.png new file mode 100644 index 0000000000..ccf4f493fc Binary files /dev/null and b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.png differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_a.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_a.png new file mode 100644 index 0000000000..c4b76850c3 Binary files /dev/null and b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_a.png differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_b.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_b.png new file mode 100644 index 0000000000..cc31604c61 Binary files /dev/null and b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_b.png differ diff --git a/doc/tutorials/introduction/load_save_image/load_save_image.rst b/doc/tutorials/introduction/load_save_image/load_save_image.rst new file mode 100644 index 0000000000..8afdf0c2d4 --- /dev/null +++ b/doc/tutorials/introduction/load_save_image/load_save_image.rst @@ -0,0 +1,122 @@ +.. _Load_Save_Image: + +Load and Save an Image +*********************** + +.. note:: + + We assume that by now you know: + + * Load an image using :imread:`imread <>` + * Display an image in an OpenCV window (using :imshow:`imshow <>`) + +Goals +====== + +In this tutorial you will learn how to: + +* Transform an image from RGB to Grayscale format by using :cvt_color:`cvtColor <>` +* Save your transformed image in a file on disk (using :imwrite:`imwrite <>`) + +Code +====== + +Here it is: + +.. code-block:: cpp + :linenos: + + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + char* imageName = argv[1]; + + Mat image; + image = imread( imageName, 1 ); + + if( argc != 2 || !image.data ) + { + printf( " No image data \n " ); + return -1; + } + + Mat gray_image; + cvtColor( image, gray_image, CV_RGB2GRAY ); + + imwrite( "../../images/Gray_Image.png", gray_image ); + + namedWindow( imageName, CV_WINDOW_AUTOSIZE ); + namedWindow( "Gray image", CV_WINDOW_AUTOSIZE ); + + imshow( imageName, image ); + imshow( "Gray image", gray_image ); + + waitKey(0); + + return 0; + } + +Explanation +============ + +#. We begin by: + + * Creating a Mat object to store the image information + * Load an image using :imread:`imread <>`, located in the path given by *imageName*. Fort this example, assume you are loading a RGB image. + +#. Now we are going to convert our image from RGB to Grayscale format. OpenCV has a really nice function to do this kind of transformations: + + .. code-block:: cpp + + cvtColor( image, gray_image, CV_RGB2GRAY ); + + As you can see, :cvt_color:`cvtColor <>` takes as arguments: + + * a source image (*image*) + * a destination image (*gray_image*), in which we will save the converted image. + + And an additional parameter that indicates what kind of transformation will be performed. In this case we use **CV_RGB2GRAY** (self-explanatory). + +#. So now we have our new *gray_image* and want to save it on disk (otherwise it will get lost after the program ends). To save it, we will use a function analagous to :imread:`imread <>`: :imwrite:`imwrite <>` + + .. code-block:: cpp + + imwrite( "../../images/Gray_Image.png", gray_image ); + + Which will save our *gray_image* as *Gray_Image.png* in the folder *images* located two levels up of my current location. + +#. Finally, let's check out the images. We create 02 windows and use them to show the original image as well as the new one: + + .. code-block:: cpp + + namedWindow( imageName, CV_WINDOW_AUTOSIZE ); + namedWindow( "Gray image", CV_WINDOW_AUTOSIZE ); + + imshow( imageName, image ); + imshow( "Gray image", gray_image ); + +#. Add the usual *waitKey(0)* for the program to wait forever until the user presses a key. + + +Result +======= + +When you run your program you should get something like this: + + .. image:: images/Load_Save_Image_Result_1.png + :alt: Load Save Image Result 1 + :height: 400px + :align: center + +And if you check in your folder (in my case *images*), you should have a newly .png file named *Gray_Image.png*: + + .. image:: images/Load_Save_Image_Result_2.png + :alt: Load Save Image Result 2 + :height: 250px + :align: center + +Congratulations, you are done with this tutorial! diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.png b/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.png new file mode 100644 index 0000000000..0c2e67c1dc Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.png differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.png b/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.png new file mode 100644 index 0000000000..97fef256d9 Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.png differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg b/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg new file mode 100644 index 0000000000..95d4b7938d Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.png b/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.png new file mode 100644 index 0000000000..cd59029373 Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.png differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu_logo.jpeg b/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu_logo.jpeg new file mode 100644 index 0000000000..0efc4f73d7 Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu_logo.jpeg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg new file mode 100644 index 0000000000..9727ee4e90 Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst b/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst new file mode 100644 index 0000000000..2b8884fd1c --- /dev/null +++ b/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst @@ -0,0 +1,131 @@ +.. _Table-Of-Content-Introduction: + +Introduction to OpenCV +----------------------------------------------------------- + +Here you can read tutorials about how to set up your computer to work with the OpenCV library. Additionaly you can find a few very basic sample source code that will let introduce you to the world of the OpenCV. + +.. We use a custom table of content format and as the table of content only imforms Sphinx about the hierarchy of the files, no need to show it. +.. toctree:: + :hidden: + + ../linux_install/linux_install + ../linux_gcc_cmake/linux_gcc_cmake + ../linux_eclipse/linux_eclipse + ../windows_install/windows_install + ../display_image/display_image + ../load_save_image/load_save_image + +.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n +.. |Author_BernatG| unicode:: Bern U+00E1 t U+0020 G U+00E1 bor + +* **Linux** + + * :ref:`Linux-Installation` + + =========== ====================================================== + |Install_1| *Title:* **Installation steps in Linux** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to setup OpenCV in your computer! + + =========== ====================================================== + + .. |Install_1| image:: images/ubuntu_logo.jpeg + :height: 100pt + :width: 100pt + + + * :ref:`Linux_GCC_Usage` + + =========== ====================================================== + |Usage_1| *Title:* **Using OpenCV with gcc (and CMake)** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to compile your first project using gcc and CMake + + =========== ====================================================== + + .. |Usage_1| image:: images/gccegg-65.png + :height: 100pt + :width: 100pt + + + * :ref:`Linux_Eclipse_Usage` + + =========== ====================================================== + |Usage_2| *Title:* **Using OpenCV with Eclipse (CDT plugin)** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to compile your first project using the Eclipse environment + + =========== ====================================================== + + .. |Usage_2| image:: images/eclipse_cpp_logo.jpeg + :height: 100pt + :width: 100pt + +* **Windows** + + * :ref:`Windows_Installation` + + =========== ====================================================== + |Install_2| *Title:* **Installation steps in Windows** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will learn how to setup OpenCV in your Windows Operating System! + + =========== ====================================================== + + .. |Install_2| image:: images/windows_logo.jpg + :height: 100pt + :width: 100pt + +* **From where to start?** + + * :ref:`Display_Image` + + =============== ====================================================== + |Beginners_1| *Title:* **Display an Image** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to display an image using OpenCV + + =============== ====================================================== + + .. |Beginners_1| image:: images/Display_Image_Tutorial_Result.png + :height: 100pt + :width: 100pt + + + * :ref:`Load_Save_Image` + + =============== ====================================================== + |Beginners_2| *Title:* **Load and save an Image** + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to save an Image in OpenCV...plus a small conversion to grayscale + + =============== ====================================================== + + .. |Beginners_2| image:: images/Load_Save_Image_Result_1.png + :height: 100pt + :width: 100pt diff --git a/doc/tutorials/introduction/windows_install/images/windows_logo.jpg b/doc/tutorials/introduction/windows_install/images/windows_logo.jpg new file mode 100644 index 0000000000..37e130dee6 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/windows_logo.jpg differ diff --git a/doc/tutorials/introduction/windows_install/windows_install.rst b/doc/tutorials/introduction/windows_install/windows_install.rst new file mode 100644 index 0000000000..7fff23c7aa --- /dev/null +++ b/doc/tutorials/introduction/windows_install/windows_install.rst @@ -0,0 +1,5 @@ +.. _Windows_Installation: + +Installation in Windows +*********************** +For now this is just a stub article. It will be updated with valuable content as soon as possible. Make sure to check back for it! diff --git a/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst b/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst new file mode 100644 index 0000000000..33134ff3ae --- /dev/null +++ b/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-Ml: + +*ml* module. Machine Learning +----------------------------------------------------------- + +Use the powerfull machine learning classes for statistical classification, regression and clustering of data. + +.. include:: ../../definitions/noContent.rst diff --git a/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.rst b/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.rst new file mode 100644 index 0000000000..e9b37f5eb2 --- /dev/null +++ b/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-ObjDetect: + +*objdetect* module. Object Detection +----------------------------------------------------------- + +Ever wondered how your digital camera detects peoples and faces? Look here to find out! + +.. include:: ../../definitions/noContent.rst \ No newline at end of file diff --git a/doc/tutorials/video/table_of_content_video/table_of_content_video.rst b/doc/tutorials/video/table_of_content_video/table_of_content_video.rst new file mode 100644 index 0000000000..aabe62d361 --- /dev/null +++ b/doc/tutorials/video/table_of_content_video/table_of_content_video.rst @@ -0,0 +1,8 @@ +.. _Table-Of-Content-Video: + +*video* module. Video analysis +----------------------------------------------------------- + +Look here in order to find use on your video stream algoritms like: motion extraction, feature tracking and foreground extractions. + +.. include:: ../../definitions/noContent.rst