* Add two images using :add_weighted:`addWeighted <>`
Cool Theory
=================
.. note::
The explanation below belongs to the book `Computer Vision: Algorithms and Applications <http://szeliski.org/Book/>`_ 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 <cv.h>
#include <highgui.h>
#include <iostream>
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 "<<std::endl;
std::cout<<"-----------------------"<<std::endl;
std::cout<<"* Enter alpha [0-1]: ";
std::cin>>input;
/// We use the alpha provided by the user iff it is between 0 and 1
* 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**
* 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:
* 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 <http://szeliski.org/Book/>`_ 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 <cv.h>
#include <highgui.h>
#include <iostream>
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 "<<std::endl;
#. 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:
* To access each pixel in the images we are using this syntax: *image.at<Vec3b>(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`
* *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:
: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:
* 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 <https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Basic/Drawing_1.cpp>`_
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*:
* 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 <https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Basic/Drawing_2.cpp>`_
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 )
* 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:
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),
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):
For me at least, this works, is simple and quick. Suggestions are welcome
Prerequisites
===============
#. Having installed `Eclipse <http://www.eclipse.org/>`_ 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 <http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/heliossr2>`_ . Choose the link according to your workstation.
#. Having installed OpenCV. If not yet, go :ref:`here <Linux_Installation>`
Making a project
=================
#. Start Eclipse. Just run the executable that comes in the folder.
In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab. Here we will enter the headers and libraries info:
*
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: ::
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
*
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:
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 <DisplayImage_directory>
cd src
./DisplayImage ../images/HappyLittleFish.jpg
Assuming that the image to use as the argument would be located in <DisplayImage_directory>/images/HappyLittleFish.jpg. We can still do this, but let's do it from Eclipse:
#. 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**:
#. Create a temporary directory, which we denote as <cmake_binary_dir>, where you want to put the generated Makefiles, project files as well the object filees and output binaries
#. Enter the <cmake_binary_dir> and type
.. code-block:: bash
cmake [<some optional parameters>] <path to the OpenCV source directory>
* 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 <>`
* 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:
* 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:
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.
This tutorial code's is shown lines below. You can also download it from `here <https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Image_Processing/Morphology_1.cpp>`_
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.
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.
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.
* 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 <http://szeliski.org/Book/>`_ 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?
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 :
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 <http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html>`_
Code
======
This tutorial code's is shown lines below. You can also download it from `here <https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Image_Processing/Smoothing.cpp>`_
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 )
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 )
The goal of this tutorial is to learn how to calibrate a camera given a set of chessboard images.
*Test data*: use images in your data/chess folder.
#.
Compile opencv with samples by setting ``BUILD_EXAMPLES`` to ``ON`` in cmake configuration.
#.
Go to ``bin`` folder and use ``imagelist_creator`` to create an ``XML/YAML`` list of your images.
#.
Then, run ``calibration`` sample to get camera parameters. Use square size equal to 3cm.
Pose estimation
===============
Now, let us write a code that detects a chessboard in a new image and finds its distance from the camera. You can apply the same method to any object with known 3D geometry that you can detect in an image.
*Test data*: use chess_test*.jpg images from your data folder.
#.
Create an empty console project. Load a test image: ::
Mat img = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
#.
Detect a chessboard in this image using findChessboard function. ::
bool found = findChessboardCorners( img, boardSize, ptvec, CV_CALIB_CB_ADAPTIVE_THRESH );
#.
Now, write a function that generates a ``vector<Point3f>`` array of 3d coordinates of a chessboard in any coordinate system. For simplicity, let us choose a system such that one of the chessboard corners is in the origin and the board is in the plane *z = 0*.
#.
Read camera parameters from XML/YAML file: ::
FileStorage fs(filename, FileStorage::READ);
Mat intrinsics, distortion;
fs["camera_matrix"] >> intrinsics;
fs["distortion_coefficients"] >> distortion;
#.
Now we are ready to find chessboard pose by running ``solvePnP``: ::
Calculate reprojection error like it is done in ``calibration`` sample (see ``opencv/samples/cpp/calibration.cpp``, function ``computeReprojectionErrors``).
Question: how to calculate the distance from the camera origin to any of the corners?
Download the latest release of opencv from \url{http://sourceforge.net/projects/opencvlibrary/}. You will need cmake and your favorite compiler environment in order to build opencv from sources. Please refer to the installation guide \url{http://opencv.willowgarage.com/wiki/InstallGuide} for detailed instructions.