Commit c5536534 authored by Maksim Shabunin's avatar Maksim Shabunin

Doxygen tutorials: warnings cleared

parent 8375182e
...@@ -199,7 +199,7 @@ if(BUILD_DOCS AND HAVE_DOXYGEN) ...@@ -199,7 +199,7 @@ if(BUILD_DOCS AND HAVE_DOXYGEN)
set(tutorial_path "${CMAKE_CURRENT_SOURCE_DIR}/tutorials") set(tutorial_path "${CMAKE_CURRENT_SOURCE_DIR}/tutorials")
string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_INPUT_LIST "${rootfile} ; ${paths_include} ; ${paths_doc} ; ${tutorial_path}") string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_INPUT_LIST "${rootfile} ; ${paths_include} ; ${paths_doc} ; ${tutorial_path}")
string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_IMAGE_PATH "${paths_doc} ; ${tutorial_path}") string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_IMAGE_PATH "${paths_doc} ; ${tutorial_path}")
string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_EXAMPLE_PATH "${CMAKE_SOURCE_DIR}/samples/cpp ; ${paths_doc}") string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_EXAMPLE_PATH "${CMAKE_SOURCE_DIR}/samples ; ${paths_doc}")
set(CMAKE_DOXYGEN_LAYOUT "${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml") set(CMAKE_DOXYGEN_LAYOUT "${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml")
set(CMAKE_DOXYGEN_OUTPUT_PATH "doxygen") set(CMAKE_DOXYGEN_OUTPUT_PATH "doxygen")
set(CMAKE_EXTRA_BIB_FILES "${bibfile} ${paths_bib}") set(CMAKE_EXTRA_BIB_FILES "${bibfile} ${paths_bib}")
......
...@@ -91,7 +91,7 @@ directory mentioned above. ...@@ -91,7 +91,7 @@ directory mentioned above.
The application starts up with reading the settings from the configuration file. Although, this is The application starts up with reading the settings from the configuration file. Although, this is
an important part of it, it has nothing to do with the subject of this tutorial: *camera an important part of it, it has nothing to do with the subject of this tutorial: *camera
calibration*. Therefore, I've chosen not to post the code for that part here. Technical background calibration*. Therefore, I've chosen not to post the code for that part here. Technical background
on how to do this you can find in the @ref fileInputOutputXMLYAML tutorial. on how to do this you can find in the @ref tutorial_file_input_output_with_xml_yml tutorial.
Explanation Explanation
----------- -----------
...@@ -486,4 +486,3 @@ here](https://www.youtube.com/watch?v=ViPN810E0SU). ...@@ -486,4 +486,3 @@ here](https://www.youtube.com/watch?v=ViPN810E0SU).
<iframe title=" Camera calibration With OpenCV - Chessboard or asymmetrical circle pattern." width="560" height="349" src="http://www.youtube.com/embed/ViPN810E0SU?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe> <iframe title=" Camera calibration With OpenCV - Chessboard or asymmetrical circle pattern." width="560" height="349" src="http://www.youtube.com/embed/ViPN810E0SU?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
</div> </div>
\endhtmlonly \endhtmlonly
...@@ -51,8 +51,7 @@ plane: ...@@ -51,8 +51,7 @@ plane:
\f[s\ \left [ \begin{matrix} u \\ v \\ 1 \end{matrix} \right ] = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ] \left [ \begin{matrix} r_{11} & r_{12} & r_{13} & t_1 \\ r_{21} & r_{22} & r_{23} & t_2 \\ r_{31} & r_{32} & r_{33} & t_3 \end{matrix} \right ] \left [ \begin{matrix} X \\ Y \\ Z\\ 1 \end{matrix} \right ]\f] \f[s\ \left [ \begin{matrix} u \\ v \\ 1 \end{matrix} \right ] = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ] \left [ \begin{matrix} r_{11} & r_{12} & r_{13} & t_1 \\ r_{21} & r_{22} & r_{23} & t_2 \\ r_{31} & r_{32} & r_{33} & t_3 \end{matrix} \right ] \left [ \begin{matrix} X \\ Y \\ Z\\ 1 \end{matrix} \right ]\f]
The complete documentation of how to manage with this equations is in @ref cv::Camera Calibration The complete documentation of how to manage with this equations is in @ref calib3d .
and 3D Reconstruction .
Source code Source code
----------- -----------
...@@ -80,7 +79,7 @@ then uses the mesh along with the [Möller–Trumbore intersection ...@@ -80,7 +79,7 @@ then uses the mesh along with the [Möller–Trumbore intersection
algorithm](http://http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm/) algorithm](http://http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm/)
to compute the 3D coordinates of the found features. Finally, the 3D points and the descriptors to compute the 3D coordinates of the found features. Finally, the 3D points and the descriptors
are stored in different lists in a file with YAML format which each row is a different point. The are stored in different lists in a file with YAML format which each row is a different point. The
technical background on how to store the files can be found in the @ref fileInputOutputXMLYAML technical background on how to store the files can be found in the @ref tutorial_file_input_output_with_xml_yml
tutorial. tutorial.
![image](images/registration.png) ![image](images/registration.png)
...@@ -91,9 +90,9 @@ The aim of this application is estimate in real time the object pose given its 3 ...@@ -91,9 +90,9 @@ The aim of this application is estimate in real time the object pose given its 3
The application starts up loading the 3D textured model in YAML file format with the same The application starts up loading the 3D textured model in YAML file format with the same
structure explained in the model registration program. From the scene, the ORB features and structure explained in the model registration program. From the scene, the ORB features and
descriptors are detected and extracted. Then, is used @ref cv::FlannBasedMatcher with @ref descriptors are detected and extracted. Then, is used @ref cv::FlannBasedMatcher with
cv::LshIndexParams to do the matching between the scene descriptors and the model descriptors. @ref cv::flann::GenericIndex to do the matching between the scene descriptors and the model descriptors.
Using the found matches along with @ref cv::solvePnPRansac function the @ref cv::R\` and \f$t\f$ of Using the found matches along with @ref cv::solvePnPRansac function the `R` and `t` of
the camera are computed. Finally, a KalmanFilter is applied in order to reject bad poses. the camera are computed. Finally, a KalmanFilter is applied in order to reject bad poses.
In the case that you compiled OpenCV with the samples, you can find it in opencv/build/bin/cpp-tutorial-pnp_detection\`. In the case that you compiled OpenCV with the samples, you can find it in opencv/build/bin/cpp-tutorial-pnp_detection\`.
...@@ -242,7 +241,7 @@ implemented a *class* **RobustMatcher** which has a function for keypoints detec ...@@ -242,7 +241,7 @@ implemented a *class* **RobustMatcher** which has a function for keypoints detec
extraction. You can find it in extraction. You can find it in
`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/RobusMatcher.cpp`. In your `samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/RobusMatcher.cpp`. In your
*RobusMatch* object you can use any of the 2D features detectors of OpenCV. In this case I used *RobusMatch* object you can use any of the 2D features detectors of OpenCV. In this case I used
@ref cv::ORB features because is based on @ref cv::FAST to detect the keypoints and @ref cv::BRIEF @ref cv::ORB features because is based on @ref cv::FAST to detect the keypoints and @ref cv::xfeatures2d::BriefDescriptorExtractor
to extract the descriptors which means that is fast and robust to rotations. You can find more to extract the descriptors which means that is fast and robust to rotations. You can find more
detailed information about *ORB* in the documentation. detailed information about *ORB* in the documentation.
...@@ -265,9 +264,9 @@ It is the first step in our detection algorithm. The main idea is to match the s ...@@ -265,9 +264,9 @@ It is the first step in our detection algorithm. The main idea is to match the s
with our model descriptors in order to know the 3D coordinates of the found features into the with our model descriptors in order to know the 3D coordinates of the found features into the
current scene. current scene.
Firstly, we have to set which matcher we want to use. In this case is used @ref Firstly, we have to set which matcher we want to use. In this case is used
cv::FlannBasedMatcher matcher which in terms of computational cost is faster than the @ref @ref cv::FlannBasedMatcher matcher which in terms of computational cost is faster than the
cv::BruteForceMatcher matcher as we increase the trained collectction of features. Then, for @ref cv::BFMatcher matcher as we increase the trained collectction of features. Then, for
FlannBased matcher the index created is *Multi-Probe LSH: Efficient Indexing for High-Dimensional FlannBased matcher the index created is *Multi-Probe LSH: Efficient Indexing for High-Dimensional
Similarity Search* due to *ORB* descriptors are binary. Similarity Search* due to *ORB* descriptors are binary.
...@@ -349,8 +348,8 @@ void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector<cv::DMatch>& ...@@ -349,8 +348,8 @@ void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector<cv::DMatch>&
} }
@endcode @endcode
After the matches filtering we have to subtract the 2D and 3D correspondences from the found scene After the matches filtering we have to subtract the 2D and 3D correspondences from the found scene
keypoints and our 3D model using the obtained *DMatches* vector. For more information about @ref keypoints and our 3D model using the obtained *DMatches* vector. For more information about
cv::DMatch check the documentation. @ref cv::DMatch check the documentation.
@code{.cpp} @code{.cpp}
// -- Step 2: Find out the 2D/3D correspondences // -- Step 2: Find out the 2D/3D correspondences
...@@ -385,8 +384,8 @@ solution. ...@@ -385,8 +384,8 @@ solution.
For the camera pose estimation I have implemented a *class* **PnPProblem**. This *class* has 4 For the camera pose estimation I have implemented a *class* **PnPProblem**. This *class* has 4
atributes: a given calibration matrix, the rotation matrix, the translation matrix and the atributes: a given calibration matrix, the rotation matrix, the translation matrix and the
rotation-translation matrix. The intrinsic calibration parameters of the camera which you are rotation-translation matrix. The intrinsic calibration parameters of the camera which you are
using to estimate the pose are necessary. In order to obtain the parameters you can check @ref using to estimate the pose are necessary. In order to obtain the parameters you can check
CameraCalibrationSquareChessBoardTutorial and @ref cameraCalibrationOpenCV tutorials. @ref tutorial_camera_calibration_square_chess and @ref tutorial_camera_calibration tutorials.
The following code is how to declare the *PnPProblem class* in the main program: The following code is how to declare the *PnPProblem class* in the main program:
@code{.cpp} @code{.cpp}
...@@ -543,9 +542,9 @@ Filter will be applied after detected a given number of inliers. ...@@ -543,9 +542,9 @@ Filter will be applied after detected a given number of inliers.
You can find more information about what [Kalman You can find more information about what [Kalman
Filter](http://en.wikipedia.org/wiki/Kalman_filter) is. In this tutorial it's used the OpenCV Filter](http://en.wikipedia.org/wiki/Kalman_filter) is. In this tutorial it's used the OpenCV
implementation of the @ref cv::Kalman Filter based on [Linear Kalman Filter for position and implementation of the @ref cv::KalmanFilter based on
orientation tracking](http://campar.in.tum.de/Chair/KalmanFilter) to set the dynamics and [Linear Kalman Filter for position and orientation tracking](http://campar.in.tum.de/Chair/KalmanFilter)
measurement models. to set the dynamics and measurement models.
Firstly, we have to define our state vector which will have 18 states: the positional data (x,y,z) Firstly, we have to define our state vector which will have 18 states: the positional data (x,y,z)
with its first and second derivatives (velocity and acceleration), then rotation is added in form with its first and second derivatives (velocity and acceleration), then rotation is added in form
...@@ -796,4 +795,3 @@ here](http://www.youtube.com/user/opencvdev/videos). ...@@ -796,4 +795,3 @@ here](http://www.youtube.com/user/opencvdev/videos).
<iframe title="Pose estimation of textured object using OpenCV in cluttered background" width="560" height="349" src="http://www.youtube.com/embed/YLS9bWek78k?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe> <iframe title="Pose estimation of textured object using OpenCV in cluttered background" width="560" height="349" src="http://www.youtube.com/embed/YLS9bWek78k?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
</div> </div>
\endhtmlonly \endhtmlonly
...@@ -83,29 +83,22 @@ Explanation ...@@ -83,29 +83,22 @@ Explanation
src2 = imread("../../images/WindowsLogo.jpg"); src2 = imread("../../images/WindowsLogo.jpg");
@endcode @endcode
**warning** **warning**
Since we are *adding* *src1* and *src2*, they both have to be of the same size (width and Since we are *adding* *src1* and *src2*, they both have to be of the same size (width and
height) and type. height) and type.
2. Now we need to generate the @ref cv::g(x)\` image. For this, the function 2. Now we need to generate the `g(x)` image. For this, the function add_weighted:addWeighted comes quite handy:
add_weighted:addWeighted comes quite handy: @code{.cpp}
beta = ( 1.0 - alpha );
.. code-block:: cpp addWeighted( src1, alpha, src2, beta, 0.0, dst);
@endcode
beta = ( 1.0 - alpha );
addWeighted( src1, alpha, src2, beta, 0.0, dst);
since @ref cv::addWeighted produces: since @ref cv::addWeighted produces:
\f[dst = \alpha \cdot src1 + \beta \cdot src2 + \gamma\f]
In this case, `gamma` is the argument \f$0.0\f$ in the code above.
.. math::
dst = \\alpha \\cdot src1 + \\beta \\cdot src2 + \\gamma
In this case, :math:gamma\` is the argument \f$0.0\f$ in the code above.
3. Create windows, show the images and wait for the user to end the program. 3. Create windows, show the images and wait for the user to end the program.
Result Result
------ ------
![image](images/Adding_Images_Tutorial_Result_0.jpg) ![image](images/Adding_Images_Tutorial_Result_Big.jpg)
...@@ -115,6 +115,6 @@ Explanation ...@@ -115,6 +115,6 @@ Explanation
Result Result
======= =======
.. image:: images/Adding_Images_Tutorial_Result_0.jpg .. image:: images/Adding_Images_Tutorial_Result_Big.jpg
:alt: Blending Images Tutorial - Final Result :alt: Blending Images Tutorial - Final Result
:align: center :align: center
...@@ -97,6 +97,7 @@ int main( int argc, char** argv ) ...@@ -97,6 +97,7 @@ int main( int argc, char** argv )
return 0; return 0;
} }
@endcode @endcode
Explanation Explanation
----------- -----------
...@@ -134,11 +135,10 @@ Explanation ...@@ -134,11 +135,10 @@ Explanation
} }
@endcode @endcode
Notice the following: Notice the following:
- To access each pixel in the images we are using this syntax: *image.at\<Vec3b\>(y,x)[c]* - 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). where *y* is the row, *x* is the column and *c* is R, G or B (0, 1 or 2).
- Since the operation @ref cv::alpha cdot p(i,j) + beta\` can give values out of range or not - Since the operation \f$\alpha \cdot p(i,j) + \beta\f$ can give values out of range or not
integers (if \f$\alpha\f$ is float), we use :saturate_cast:\`saturate_cast to make sure the integers (if \f$\alpha\f$ is float), we use cv::saturate_cast to make sure the
values are valid. values are valid.
5. Finally, we create windows and show the images, the usual way. 5. Finally, we create windows and show the images, the usual way.
...@@ -151,12 +151,13 @@ Explanation ...@@ -151,12 +151,13 @@ Explanation
waitKey(0); waitKey(0);
@endcode @endcode
@note @note
Instead of using the **for** loops to access each pixel, we could have simply used this command: Instead of using the **for** loops to access each pixel, we could have simply used this command:
@code{.cpp} @code{.cpp}
image.convertTo(new_image, -1, alpha, beta); image.convertTo(new_image, -1, alpha, beta);
@endcode @endcode
where @ref cv::convertTo would effectively perform *new_image = a*image + beta\*. However, we where @ref cv::Mat::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 but wanted to show you how to access each pixel. In any case, both methods give the same result but
convertTo is more optimized and works a lot faster. convertTo is more optimized and works a lot faster.
...@@ -171,8 +172,7 @@ Result ...@@ -171,8 +172,7 @@ Result
* Enter the alpha value [1.0-3.0]: 2.2 * Enter the alpha value [1.0-3.0]: 2.2
* Enter the beta value [0-100]: 50 * Enter the beta value [0-100]: 50
@endcode @endcode
- We get this:
![image](images/Basic_Linear_Transform_Tutorial_Result_0.jpg)
- We get this:
![image](images/Basic_Linear_Transform_Tutorial_Result_big.jpg)
...@@ -204,6 +204,6 @@ Result ...@@ -204,6 +204,6 @@ Result
* We get this: * We get this:
.. image:: images/Basic_Linear_Transform_Tutorial_Result_0.jpg .. image:: images/Basic_Linear_Transform_Tutorial_Result_big.jpg
:alt: Basic Linear Transform - Final Result :alt: Basic Linear Transform - Final Result
:align: center :align: center
...@@ -79,10 +79,12 @@ double t = (double)getTickCount(); ...@@ -79,10 +79,12 @@ double t = (double)getTickCount();
t = ((double)getTickCount() - t)/getTickFrequency(); t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Times passed in seconds: " << t << endl; cout << "Times passed in seconds: " << t << endl;
@endcode @endcode
@anchor tutorial_how_to_scan_images_storing
How the image matrix is stored in the memory? How the image matrix is stored in the memory?
--------------------------------------------- ---------------------------------------------
As you could already read in my @ref matTheBasicImageContainer tutorial the size of the matrix As you could already read in my @ref tutorial_mat_the_basic_image_container tutorial the size of the matrix
depends of the color system used. More accurately, it depends from the number of channels used. In depends of the color system used. More accurately, it depends from the number of channels used. In
case of a gray scale image we have something like: case of a gray scale image we have something like:
...@@ -110,7 +112,7 @@ Row n & \tabIt{n,0} & \tabIt{n,1} & \tabIt{n,...} & \tabIt{n, m} \\ ...@@ -110,7 +112,7 @@ Row n & \tabIt{n,0} & \tabIt{n,1} & \tabIt{n,...} & \tabIt{n, m} \\
Note that the order of the channels is inverse: BGR instead of RGB. Because in many cases the memory Note that the order of the channels is inverse: BGR instead of RGB. Because in many cases the memory
is large enough to store the rows in a successive fashion the rows may follow one after another, is large enough to store the rows in a successive fashion the rows may follow one after another,
creating a single long row. Because everything is in a single place following one after another this creating a single long row. Because everything is in a single place following one after another this
may help to speed up the scanning process. We can use the @ref cv::isContinuous() function to *ask* may help to speed up the scanning process. We can use the @ref cv::Mat::isContinuous() function to *ask*
the matrix if this is the case. Continue on to the next section to find an example. the matrix if this is the case. Continue on to the next section to find an example.
The efficient way The efficient way
...@@ -227,12 +229,12 @@ differences I've used a quite large (2560 X 1600) image. The performance present ...@@ -227,12 +229,12 @@ differences I've used a quite large (2560 X 1600) image. The performance present
color images. For a more accurate value I've averaged the value I got from the call of the function color images. For a more accurate value I've averaged the value I got from the call of the function
for hundred times. for hundred times.
--------------- ---------------------- Method | Time
Efficient Way 79.4717 milliseconds --------------- | ----------------------
Iterator 83.7201 milliseconds Efficient Way | 79.4717 milliseconds
On-The-Fly RA 93.7878 milliseconds Iterator | 83.7201 milliseconds
LUT function 32.5759 milliseconds On-The-Fly RA | 93.7878 milliseconds
--------------- ---------------------- LUT function | 32.5759 milliseconds
We can conclude a couple of things. If possible, use the already made functions of OpenCV (instead We can conclude a couple of things. If possible, use the already made functions of OpenCV (instead
reinventing these). The fastest method turns out to be the LUT function. This is because the OpenCV reinventing these). The fastest method turns out to be the LUT function. This is because the OpenCV
...@@ -242,12 +244,10 @@ Using the on-the-fly reference access method for full image scan is the most cos ...@@ -242,12 +244,10 @@ Using the on-the-fly reference access method for full image scan is the most cos
In the release mode it may beat the iterator approach or not, however it surely sacrifices for this In the release mode it may beat the iterator approach or not, however it surely sacrifices for this
the safety trait of iterators. the safety trait of iterators.
Finally, you may watch a sample run of the program on the [video Finally, you may watch a sample run of the program on the [video posted](https://www.youtube.com/watch?v=fB3AN5fjgwc) on our YouTube channel.
posted](https://www.youtube.com/watch?v=fB3AN5fjgwc) on our YouTube channel.
\htmlonly \htmlonly
<div align="center"> <div align="center">
<iframe title="How to scan images in OpenCV?" width="560" height="349" src="http://www.youtube.com/embed/fB3AN5fjgwc?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe> <iframe title="How to scan images in OpenCV?" width="560" height="349" src="http://www.youtube.com/embed/fB3AN5fjgwc?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
</div> </div>
\endhtmlonly \endhtmlonly
...@@ -16,8 +16,7 @@ Code ...@@ -16,8 +16,7 @@ Code
You may also find the source code in the You may also find the source code in the
`samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp` file of the OpenCV source library or `samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp` file of the OpenCV source library or
download it from here download it from [here](samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp).
\<../../../../samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp\>.
@includelineno cpp/tutorial_code/core/ippasync/ippasync_sample.cpp @includelineno cpp/tutorial_code/core/ippasync/ippasync_sample.cpp
...@@ -37,8 +36,8 @@ Explanation ...@@ -37,8 +36,8 @@ Explanation
hppStatus sts; hppStatus sts;
hppiVirtualMatrix * virtMatrix; hppiVirtualMatrix * virtMatrix;
@endcode @endcode
2. Load input image or video. How to open and read video stream you can see in the @ref 2. Load input image or video. How to open and read video stream you can see in the
videoInputPSNRMSSIM tutorial. @ref tutorial_video_input_psnr_ssim tutorial.
@code{.cpp} @code{.cpp}
if( useCamera ) if( useCamera )
{ {
...@@ -83,7 +82,7 @@ Explanation ...@@ -83,7 +82,7 @@ Explanation
result.create( image.rows, image.cols, CV_8U); result.create( image.rows, image.cols, CV_8U);
@endcode @endcode
6. Convert Mat to [hppiMatrix](http://software.intel.com/en-us/node/501660) using @ref cv::getHpp 6. Convert Mat to [hppiMatrix](http://software.intel.com/en-us/node/501660) using @ref cv::hpp::getHpp
and call [hppiSobel](http://software.intel.com/en-us/node/474701) function. and call [hppiSobel](http://software.intel.com/en-us/node/474701) function.
@code{.cpp} @code{.cpp}
//convert Mat to hppiMatrix //convert Mat to hppiMatrix
...@@ -134,6 +133,7 @@ Explanation ...@@ -134,6 +133,7 @@ Explanation
CHECK_DEL_STATUS(sts, "hppDeleteInstance"); CHECK_DEL_STATUS(sts, "hppDeleteInstance");
} }
@endcode @endcode
Result Result
------ ------
...@@ -141,4 +141,3 @@ After compiling the code above we can execute it giving an image or video path a ...@@ -141,4 +141,3 @@ After compiling the code above we can execute it giving an image or video path a
as an argument. For this tutorial we use baboon.png image as input. The result is below. as an argument. For this tutorial we use baboon.png image as input. The result is below.
![image](images/How_To_Use_IPPA_Result.jpg) ![image](images/How_To_Use_IPPA_Result.jpg)
...@@ -19,8 +19,8 @@ this. In the following you'll learn: ...@@ -19,8 +19,8 @@ this. In the following you'll learn:
General General
------- -------
When making the switch you first need to learn some about the new data structure for images: @ref When making the switch you first need to learn some about the new data structure for images:
matTheBasicImageContainer, this replaces the old *CvMat* and *IplImage* ones. Switching to the new @ref tutorial_mat_the_basic_image_container, this replaces the old *CvMat* and *IplImage* ones. Switching to the new
functions is easier. You just need to remember a couple of new things. functions is easier. You just need to remember a couple of new things.
OpenCV 2 received reorganization. No longer are all the functions crammed into a single library. We OpenCV 2 received reorganization. No longer are all the functions crammed into a single library. We
...@@ -46,8 +46,8 @@ and the subsequent words start with a capital letter (like *copyMakeBorder*). ...@@ -46,8 +46,8 @@ and the subsequent words start with a capital letter (like *copyMakeBorder*).
Now, remember that you need to link to your application all the modules you use, and in case you are Now, remember that you need to link to your application all the modules you use, and in case you are
on Windows using the *DLL* system you will need to add, again, to the path all the binaries. For on Windows using the *DLL* system you will need to add, again, to the path all the binaries. For
more in-depth information if you're on Windows read @ref Windows_Visual_Studio_How_To and for more in-depth information if you're on Windows read @ref tutorial_windows_visual_studio_Opencv and for
Linux an example usage is explained in @ref Linux_Eclipse_Usage. Linux an example usage is explained in @ref tutorial_linux_eclipse.
Now for converting the *Mat* object you can use either the *IplImage* or the *CvMat* operators. Now for converting the *Mat* object you can use either the *IplImage* or the *CvMat* operators.
While in the C interface you used to work with pointers here it's no longer the case. In the C++ While in the C interface you used to work with pointers here it's no longer the case. In the C++
...@@ -81,11 +81,11 @@ For example: ...@@ -81,11 +81,11 @@ For example:
Mat K(piL), L; Mat K(piL), L;
L = Mat(pI); L = Mat(pI);
@endcode @endcode
A case study A case study
------------ ------------
Now that you have the basics done [here's Now that you have the basics done [here's](samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp)
](samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp)
an example that mixes the usage of the C interface with the C++ one. You will also find it in the an example that mixes the usage of the C interface with the C++ one. You will also find it in the
sample directory of the OpenCV source code library at the sample directory of the OpenCV source code library at the
`samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` . `samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` .
...@@ -124,7 +124,7 @@ lines ...@@ -124,7 +124,7 @@ lines
Here you can observe that we may go through all the pixels of an image in three fashions: an Here you can observe that we may go through all the pixels of an image in three fashions: an
iterator, a C pointer and an individual element access style. You can read a more in-depth iterator, a C pointer and an individual element access style. You can read a more in-depth
description of these in the @ref howToScanImagesOpenCV tutorial. Converting from the old function description of these in the @ref tutorial_how_to_scan_images tutorial. Converting from the old function
names is easy. Just remove the cv prefix and use the new *Mat* data structure. Here's an example of names is easy. Just remove the cv prefix and use the new *Mat* data structure. Here's an example of
this by using the weighted addition function: this by using the weighted addition function:
...@@ -161,4 +161,3 @@ of the OpenCV source code library. ...@@ -161,4 +161,3 @@ of the OpenCV source code library.
<iframe title="Interoperability with OpenCV 1" width="560" height="349" src="http://www.youtube.com/embed/qckm-zvo31w?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe> <iframe title="Interoperability with OpenCV 1" width="560" height="349" src="http://www.youtube.com/embed/qckm-zvo31w?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
</div> </div>
\endhtmlonly \endhtmlonly
...@@ -67,7 +67,7 @@ At first we make sure that the input images data is in unsigned char format. For ...@@ -67,7 +67,7 @@ At first we make sure that the input images data is in unsigned char format. For
CV_Assert(myImage.depth() == CV_8U); // accept only uchar images CV_Assert(myImage.depth() == CV_8U); // accept only uchar images
@endcode @endcode
We create an output image with the same size and the same type as our input. As you can see in the We create an output image with the same size and the same type as our input. As you can see in the
@ref How_Image_Stored_Memory section, depending on the number of channels we may have one or more @ref tutorial_how_to_scan_images_storing "storing" section, depending on the number of channels we may have one or more
subcolumns. We will iterate through them via pointers so the total number of elements depends from subcolumns. We will iterate through them via pointers so the total number of elements depends from
this number. this number.
@code{.cpp} @code{.cpp}
...@@ -104,6 +104,7 @@ Result.row(Result.rows - 1).setTo(Scalar(0)); // The bottom row ...@@ -104,6 +104,7 @@ Result.row(Result.rows - 1).setTo(Scalar(0)); // The bottom row
Result.col(0).setTo(Scalar(0)); // The left column Result.col(0).setTo(Scalar(0)); // The left column
Result.col(Result.cols - 1).setTo(Scalar(0)); // The right column Result.col(Result.cols - 1).setTo(Scalar(0)); // The right column
@endcode @endcode
The filter2D function The filter2D function
--------------------- ---------------------
......
...@@ -13,15 +13,14 @@ In this tutorial you will learn how to: ...@@ -13,15 +13,14 @@ In this tutorial you will learn how to:
Code Code
---- ----
- In the previous tutorial (@ref Drawing_1) we drew diverse geometric figures, giving as input - In the previous tutorial (@ref tutorial_basic_geometric_drawing) we drew diverse geometric figures, giving as input
parameters such as coordinates (in the form of @ref cv::Points ), color, thickness, etc. You parameters such as coordinates (in the form of @ref cv::Point), color, thickness, etc. You
might have noticed that we gave specific values for these arguments. 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 - 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 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* . 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 - This code is in your OpenCV sample folder. Otherwise you can grab it from
[here](http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/core/Matrix/Drawing_2.cpp) [here](http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/core/Matrix/Drawing_2.cpp)
.
Explanation Explanation
----------- -----------
...@@ -213,9 +212,9 @@ Explanation ...@@ -213,9 +212,9 @@ Explanation
**image** minus the value of **i** (remember that for each pixel we are considering three values **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) such as R, G and B, so each of them will be affected)
Also remember that the substraction operation *always* performs internally a **saturate** 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 operation, which means that the result obtained will always be inside the allowed range (no
negative and between 0 and 255 for our example). negative and between 0 and 255 for our example).
Result Result
------ ------
...@@ -247,6 +246,4 @@ functions, which will produce: ...@@ -247,6 +246,4 @@ functions, which will produce:
colors and positions. colors and positions.
8. And the big end (which by the way expresses a big truth too): 8. And the big end (which by the way expresses a big truth too):
![image](images/Drawing_2_Tutorial_Result_7.jpg) ![image](images/Drawing_2_Tutorial_Result_big.jpg)
...@@ -262,6 +262,6 @@ As you just saw in the Code section, the program will sequentially execute diver ...@@ -262,6 +262,6 @@ As you just saw in the Code section, the program will sequentially execute diver
#. And the big end (which by the way expresses a big truth too): #. And the big end (which by the way expresses a big truth too):
.. image:: images/Drawing_2_Tutorial_Result_7.jpg .. image:: images/Drawing_2_Tutorial_Result_big.jpg
:alt: Drawing Tutorial 2 - Final Result 7 :alt: Drawing Tutorial 2 - Final Result 7
:align: center :align: center
...@@ -8,7 +8,7 @@ In this tutorial you will learn how to: ...@@ -8,7 +8,7 @@ In this tutorial you will learn how to:
- Use the @ref cv::DescriptorExtractor interface in order to find the feature vector correspondent - Use the @ref cv::DescriptorExtractor interface in order to find the feature vector correspondent
to the keypoints. Specifically: to the keypoints. Specifically:
- Use @ref cv::SurfDescriptorExtractor and its function @ref cv::compute to perform the - Use @ref cv::xfeatures2d::SURF and its function @ref cv::xfeatures2d::SURF::compute to perform the
required calculations. required calculations.
- Use a @ref cv::BFMatcher to match the features vector - Use a @ref cv::BFMatcher to match the features vector
- Use the function @ref cv::drawMatches to draw the detected matches. - Use the function @ref cv::drawMatches to draw the detected matches.
...@@ -78,14 +78,13 @@ int main( int argc, char** argv ) ...@@ -78,14 +78,13 @@ int main( int argc, char** argv )
void readme() void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; } { std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
@endcode @endcode
Explanation Explanation
----------- -----------
Result Result
------ ------
1. Here is the result after applying the BruteForce matcher between the two original images: Here is the result after applying the BruteForce matcher between the two original images:
![image](images/Feature_Description_BruteForce_Result.jpg)
![image](images/Feature_Description_BruteForce_Result.jpg)
...@@ -7,7 +7,7 @@ Goal ...@@ -7,7 +7,7 @@ Goal
In this tutorial you will learn how to: In this tutorial you will learn how to:
- Use the @ref cv::FeatureDetector interface in order to find interest points. Specifically: - Use the @ref cv::FeatureDetector interface in order to find interest points. Specifically:
- Use the @ref cv::SurfFeatureDetector and its function @ref cv::detect to perform the - Use the @ref cv::xfeatures2d::SURF and its function @ref cv::xfeatures2d::SURF::detect to perform the
detection process detection process
- Use the function @ref cv::drawKeypoints to draw the detected keypoints - Use the function @ref cv::drawKeypoints to draw the detected keypoints
...@@ -72,6 +72,7 @@ int main( int argc, char** argv ) ...@@ -72,6 +72,7 @@ int main( int argc, char** argv )
void readme() void readme()
{ std::cout << " Usage: ./SURF_detector <img1> <img2>" << std::endl; } { std::cout << " Usage: ./SURF_detector <img1> <img2>" << std::endl; }
@endcode @endcode
Explanation Explanation
----------- -----------
...@@ -85,5 +86,3 @@ Result ...@@ -85,5 +86,3 @@ Result
2. And here is the result for the second image: 2. And here is the result for the second image:
![image](images/Feature_Detection_Result_b.jpg) ![image](images/Feature_Detection_Result_b.jpg)
...@@ -7,7 +7,7 @@ Goal ...@@ -7,7 +7,7 @@ Goal
In this tutorial you will learn how to: In this tutorial you will learn how to:
- Use the @ref cv::FlannBasedMatcher interface in order to perform a quick and efficient matching - Use the @ref cv::FlannBasedMatcher interface in order to perform a quick and efficient matching
by using the @ref cv::FLANN ( *Fast Approximate Nearest Neighbor Search Library* ) by using the @ref flann module
Theory Theory
------ ------
...@@ -123,6 +123,7 @@ int main( int argc, char** argv ) ...@@ -123,6 +123,7 @@ int main( int argc, char** argv )
void readme() void readme()
{ std::cout << " Usage: ./SURF_FlannMatcher <img1> <img2>" << std::endl; } { std::cout << " Usage: ./SURF_FlannMatcher <img1> <img2>" << std::endl; }
@endcode @endcode
Explanation Explanation
----------- -----------
...@@ -136,5 +137,3 @@ Result ...@@ -136,5 +137,3 @@ Result
2. Additionally, we get as console output the keypoints filtered: 2. Additionally, we get as console output the keypoints filtered:
![image](images/Feature_FlannMatcher_Keypoints_Result.jpg) ![image](images/Feature_FlannMatcher_Keypoints_Result.jpg)
Similarity check (PNSR and SSIM) on the GPU {#tutorial_gpu_basics_similarity} Similarity check (PNSR and SSIM) on the GPU {#tutorial_gpu_basics_similarity}
=========================================== ===========================================
@todo update this tutorial
Goal Goal
---- ----
In the @ref videoInputPSNRMSSIM tutorial I already presented the PSNR and SSIM methods for checking In the @ref tutorial_video_input_psnr_ssim tutorial I already presented the PSNR and SSIM methods for checking
the similarity between the two images. And as you could see there performing these takes quite some the similarity between the two images. And as you could see there performing these takes quite some
time, especially in the case of the SSIM. However, if the performance numbers of an OpenCV time, especially in the case of the SSIM. However, if the performance numbers of an OpenCV
implementation for the CPU do not satisfy you and you happen to have an NVidia CUDA GPU device in implementation for the CPU do not satisfy you and you happen to have an NVidia CUDA GPU device in
...@@ -32,7 +33,7 @@ you'll find here only the functions itself. ...@@ -32,7 +33,7 @@ you'll find here only the functions itself.
The PSNR returns a float number, that if the two inputs are similar between 30 and 50 (higher is The PSNR returns a float number, that if the two inputs are similar between 30 and 50 (higher is
better). better).
@includelineno cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp @includelineno samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp
lines lines
165-210, 18-23, 210-235 165-210, 18-23, 210-235
...@@ -41,7 +42,7 @@ The SSIM returns the MSSIM of the images. This is too a float number between zer ...@@ -41,7 +42,7 @@ The SSIM returns the MSSIM of the images. This is too a float number between zer
better), however we have one for each channel. Therefore, we return a *Scalar* OpenCV data better), however we have one for each channel. Therefore, we return a *Scalar* OpenCV data
structure: structure:
@includelineno cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp @includelineno samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp
lines lines
235-355, 26-42, 357- 235-355, 26-42, 357-
...@@ -63,7 +64,8 @@ the cv:: to avoid confusion. I'll do the later. ...@@ -63,7 +64,8 @@ the cv:: to avoid confusion. I'll do the later.
@code{.cpp} @code{.cpp}
#include <opencv2/gpu.hpp> // GPU structures and methods #include <opencv2/gpu.hpp> // GPU structures and methods
@endcode @endcode
GPU stands for **g**raphics **p**rocessing **u**nit. It was originally build to render graphical
GPU stands for "graphics processing unit". It was originally build to render graphical
scenes. These scenes somehow build on a lot of data. Nevertheless, these aren't all dependent one scenes. These scenes somehow build on a lot of data. Nevertheless, these aren't all dependent one
from another in a sequential way and as it is possible a parallel processing of them. Due to this a from another in a sequential way and as it is possible a parallel processing of them. Due to this a
GPU will contain multiple smaller processing units. These aren't the state of the art processors and GPU will contain multiple smaller processing units. These aren't the state of the art processors and
...@@ -81,7 +83,7 @@ small functions to GPU is not recommended as the upload/download time will be la ...@@ -81,7 +83,7 @@ small functions to GPU is not recommended as the upload/download time will be la
you gain by a parallel execution. you gain by a parallel execution.
Mat objects are stored only in the system memory (or the CPU cache). For getting an OpenCV matrix to Mat objects are stored only in the system memory (or the CPU cache). For getting an OpenCV matrix to
the GPU you'll need to use its GPU counterpart @ref cv::GpuMat . It works similar to the Mat with a the GPU you'll need to use its GPU counterpart @ref cv::cuda::GpuMat . It works similar to the Mat with a
2D only limitation and no reference returning for its functions (cannot mix GPU references with CPU 2D only limitation and no reference returning for its functions (cannot mix GPU references with CPU
ones). To upload a Mat object to the GPU you need to call the upload function after creating an ones). To upload a Mat object to the GPU you need to call the upload function after creating an
instance of the class. To download you may use simple assignment to a Mat object or use the download instance of the class. To download you may use simple assignment to a Mat object or use the download
...@@ -120,7 +122,7 @@ Optimization ...@@ -120,7 +122,7 @@ Optimization
The reason for this is that you're throwing out on the window the price for memory allocation and The reason for this is that you're throwing out on the window the price for memory allocation and
data transfer. And on the GPU this is damn high. Another possibility for optimization is to data transfer. And on the GPU this is damn high. Another possibility for optimization is to
introduce asynchronous OpenCV GPU calls too with the help of the @ref cv::gpu::Stream. introduce asynchronous OpenCV GPU calls too with the help of the @ref cv::cuda::Stream.
1. Memory allocation on the GPU is considerable. Therefore, if it’s possible allocate new memory as 1. Memory allocation on the GPU is considerable. Therefore, if it’s possible allocate new memory as
few times as possible. If you create a function what you intend to call multiple times it is a few times as possible. If you create a function what you intend to call multiple times it is a
...@@ -162,7 +164,7 @@ introduce asynchronous OpenCV GPU calls too with the help of the @ref cv::gpu::S ...@@ -162,7 +164,7 @@ introduce asynchronous OpenCV GPU calls too with the help of the @ref cv::gpu::S
gpu::multiply(b.mu1_mu2, 2, b.t1); //b.t1 = 2 * b.mu1_mu2 + C1; gpu::multiply(b.mu1_mu2, 2, b.t1); //b.t1 = 2 * b.mu1_mu2 + C1;
gpu::add(b.t1, C1, b.t1); gpu::add(b.t1, C1, b.t1);
@endcode @endcode
3. Use asynchronous calls (the @ref cv::gpu::Stream ). By default whenever you call a gpu function 3. Use asynchronous calls (the @ref cv::cuda::Stream ). By default whenever you call a gpu function
it will wait for the call to finish and return with the result afterwards. However, it is it will wait for the call to finish and return with the result afterwards. However, it is
possible to make asynchronous calls, meaning it will call for the operation execution, make the possible to make asynchronous calls, meaning it will call for the operation execution, make the
costly data allocations for the algorithm and return back right away. Now you can call another costly data allocations for the algorithm and return back right away. Now you can call another
...@@ -182,6 +184,7 @@ introduce asynchronous OpenCV GPU calls too with the help of the @ref cv::gpu::S ...@@ -182,6 +184,7 @@ introduce asynchronous OpenCV GPU calls too with the help of the @ref cv::gpu::S
gpu::split(b.t1, b.vI1, stream); // Methods (pass the stream as final parameter). gpu::split(b.t1, b.vI1, stream); // Methods (pass the stream as final parameter).
gpu::multiply(b.vI1[i], b.vI1[i], b.I1_2, stream); // I1^2 gpu::multiply(b.vI1[i], b.vI1[i], b.I1_2, stream); // I1^2
@endcode @endcode
Result and conclusion Result and conclusion
--------------------- ---------------------
......
...@@ -22,7 +22,7 @@ In this tutorial you will learn how to: ...@@ -22,7 +22,7 @@ In this tutorial you will learn how to:
Code Code
---- ----
Let's modify the program made in the tutorial @ref Adding_Images. We will let the user enter the Let's modify the program made in the tutorial @ref tutorial_adding_images. We will let the user enter the
\f$\alpha\f$ value by using the Trackbar. \f$\alpha\f$ value by using the Trackbar.
@code{.cpp} @code{.cpp}
#include <opencv2/opencv.hpp> #include <opencv2/opencv.hpp>
...@@ -82,6 +82,7 @@ int main( int argc, char** argv ) ...@@ -82,6 +82,7 @@ int main( int argc, char** argv )
return 0; return 0;
} }
@endcode @endcode
Explanation Explanation
----------- -----------
...@@ -122,7 +123,6 @@ We only analyze the code that is related to Trackbar: ...@@ -122,7 +123,6 @@ We only analyze the code that is related to Trackbar:
} }
@endcode @endcode
Note that: Note that:
- We use the value of **alpha_slider** (integer) to get a double value for **alpha**. - 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. - **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, - We define *src1*, *src2*, *dist*, *alpha*, *alpha_slider* and *beta* as global variables,
...@@ -135,10 +135,8 @@ Result ...@@ -135,10 +135,8 @@ Result
![image](images/Adding_Trackbars_Tutorial_Result_0.jpg) ![image](images/Adding_Trackbars_Tutorial_Result_0.jpg)
- As a manner of practice, you can also add 02 trackbars for the program made in @ref - As a manner of practice, you can also add 02 trackbars for the program made in
Basic_Linear_Transform. One trackbar to set \f$\alpha\f$ and another for \f$\beta\f$. The output might @ref tutorial_basic_linear_transform. One trackbar to set \f$\alpha\f$ and another for \f$\beta\f$. The output might
look like: look like:
![image](images/Adding_Trackbars_Tutorial_Result_1.jpg) ![image](images/Adding_Trackbars_Tutorial_Result_1.jpg)
...@@ -33,8 +33,8 @@ lines ...@@ -33,8 +33,8 @@ lines
How to read a video stream (online-camera or offline-file)? How to read a video stream (online-camera or offline-file)?
----------------------------------------------------------- -----------------------------------------------------------
Essentially, all the functionalities required for video manipulation is integrated in the @ref Essentially, all the functionalities required for video manipulation is integrated in the @ref cv::VideoCapture
cv::VideoCapture C++ class. This on itself builds on the FFmpeg open source library. This is a basic C++ class. This on itself builds on the FFmpeg open source library. This is a basic
dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession
of images, we refer to these in the literature as frames. In case of a video file there is a *frame of images, we refer to these in the literature as frames. In case of a video file there is a *frame
rate* specifying just how long is between two frames. While for the video cameras usually there is a rate* specifying just how long is between two frames. While for the video cameras usually there is a
...@@ -42,7 +42,7 @@ limit of just how many frames they can digitalize per second, this property is l ...@@ -42,7 +42,7 @@ limit of just how many frames they can digitalize per second, this property is l
any time the camera sees the current snapshot of the world. any time the camera sees the current snapshot of the world.
The first task you need to do is to assign to a @ref cv::VideoCapture class its source. You can do The first task you need to do is to assign to a @ref cv::VideoCapture class its source. You can do
this either via the @ref cv::constructor or its @ref cv::open function. If this argument is an this either via the @ref cv::VideoCapture::VideoCapture or its @ref cv::VideoCapture::open function. If this argument is an
integer then you will bind the class to a camera, a device. The number passed here is the ID of the integer then you will bind the class to a camera, a device. The number passed here is the ID of the
device, assigned by the operating system. If you have a single camera attached to your system its ID device, assigned by the operating system. If you have a single camera attached to your system its ID
will probably be zero and further ones increasing from there. If the parameter passed to these is a will probably be zero and further ones increasing from there. If the parameter passed to these is a
...@@ -63,8 +63,8 @@ VideoCapture captRefrnc(sourceReference); ...@@ -63,8 +63,8 @@ VideoCapture captRefrnc(sourceReference);
VideoCapture captUndTst; VideoCapture captUndTst;
captUndTst.open(sourceCompareWith); captUndTst.open(sourceCompareWith);
@endcode @endcode
To check if the binding of the class to a video source was successful or not use the @ref To check if the binding of the class to a video source was successful or not use the @ref cv::VideoCapture::isOpened
cv::isOpened function: function:
@code{.cpp} @code{.cpp}
if ( !captRefrnc.isOpened()) if ( !captRefrnc.isOpened())
{ {
...@@ -73,10 +73,10 @@ if ( !captRefrnc.isOpened()) ...@@ -73,10 +73,10 @@ if ( !captRefrnc.isOpened())
} }
@endcode @endcode
Closing the video is automatic when the objects destructor is called. However, if you want to close Closing the video is automatic when the objects destructor is called. However, if you want to close
it before this you need to call its @ref cv::release function. The frames of the video are just it before this you need to call its @ref cv::VideoCapture::release function. The frames of the video are just
simple images. Therefore, we just need to extract them from the @ref cv::VideoCapture object and put simple images. Therefore, we just need to extract them from the @ref cv::VideoCapture object and put
them inside a *Mat* one. The video streams are sequential. You may get the frames one after another them inside a *Mat* one. The video streams are sequential. You may get the frames one after another
by the @ref cv::read or the overloaded \>\> operator: by the @ref cv::VideoCapture::read or the overloaded \>\> operator:
@code{.cpp} @code{.cpp}
Mat frameReference, frameUnderTest; Mat frameReference, frameUnderTest;
captRefrnc >> frameReference; captRefrnc >> frameReference;
...@@ -92,11 +92,11 @@ if( frameReference.empty() || frameUnderTest.empty()) ...@@ -92,11 +92,11 @@ if( frameReference.empty() || frameUnderTest.empty())
} }
@endcode @endcode
A read method is made of a frame grab and a decoding applied on that. You may call explicitly these A read method is made of a frame grab and a decoding applied on that. You may call explicitly these
two by using the @ref cv::grab and then the @ref cv::retrieve functions. two by using the @ref cv::VideoCapture::grab and then the @ref cv::VideoCapture::retrieve functions.
Videos have many-many information attached to them besides the content of the frames. These are Videos have many-many information attached to them besides the content of the frames. These are
usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to
this to acquire these information there is a general function named @ref cv::get that returns double this to acquire these information there is a general function named @ref cv::VideoCapture::get that returns double
values containing these properties. Use bitwise operations to decode the characters from a double values containing these properties. Use bitwise operations to decode the characters from a double
type and conversions where valid values are only integers. Its single argument is the ID of the type and conversions where valid values are only integers. Its single argument is the ID of the
queried property. For example, here we get the size of the frames in the reference and test case queried property. For example, here we get the size of the frames in the reference and test case
...@@ -109,7 +109,7 @@ cout << "Reference frame resolution: Width=" << refS.width << " Height=" << ref ...@@ -109,7 +109,7 @@ cout << "Reference frame resolution: Width=" << refS.width << " Height=" << ref
<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl; << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
@endcode @endcode
When you are working with videos you may often want to control these values yourself. To do this When you are working with videos you may often want to control these values yourself. To do this
there is a @ref cv::set function. Its first argument remains the name of the property you want to there is a @ref cv::VideoCapture::set function. Its first argument remains the name of the property you want to
change and there is a second of double type containing the value to be set. It will return true if change and there is a second of double type containing the value to be set. It will return true if
it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time
or frame: or frame:
...@@ -118,8 +118,8 @@ captRefrnc.set(CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video ...@@ -118,8 +118,8 @@ captRefrnc.set(CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video
captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
// now a read operation would read the frame at the set position // now a read operation would read the frame at the set position
@endcode @endcode
For properties you can read and change look into the documentation of the @ref cv::get and @ref For properties you can read and change look into the documentation of the @ref cv::VideoCapture::get and
cv::set functions. @ref cv::VideoCapture::set functions.
Image similarity - PSNR and SSIM Image similarity - PSNR and SSIM
-------------------------------- --------------------------------
...@@ -175,9 +175,10 @@ the article introducing it. Nevertheless, you can get a good image of it by look ...@@ -175,9 +175,10 @@ the article introducing it. Nevertheless, you can get a good image of it by look
implementation below. implementation below.
@sa @sa
SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P.
Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE
Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article. Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article.
@code{.cpp} @code{.cpp}
Scalar getMSSIM( const Mat& i1, const Mat& i2) Scalar getMSSIM( const Mat& i1, const Mat& i2)
{ {
......
...@@ -5,8 +5,8 @@ Goal ...@@ -5,8 +5,8 @@ Goal
---- ----
Whenever you work with video feeds you may eventually want to save your image processing result in a Whenever you work with video feeds you may eventually want to save your image processing result in a
form of a new video file. For simple video outputs you can use the OpenCV built-in @ref form of a new video file. For simple video outputs you can use the OpenCV built-in @ref cv::VideoWriter
cv::VideoWriter class, designed for this. class, designed for this.
- How to create a video file with OpenCV - How to create a video file with OpenCV
- What type of video files you can create with OpenCV - What type of video files you can create with OpenCV
...@@ -58,11 +58,15 @@ container. No audio or other track editing support here. Nevertheless, any video ...@@ -58,11 +58,15 @@ container. No audio or other track editing support here. Nevertheless, any video
your system might work. If you encounter some of these limitations you will need to look into more your system might work. If you encounter some of these limitations you will need to look into more
specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As
an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to
other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*. The other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*.
*VideoWriter* class ======================= The content written here builds on the assumption you
already read the @ref videoInputPSNRMSSIM tutorial and you know how to read video files. To create a The *VideoWriter* class
-----------------------
The content written here builds on the assumption you
already read the @ref tutorial_video_input_psnr_ssim tutorial and you know how to read video files. To create a
video file you just need to create an instance of the @ref cv::VideoWriter class. You can specify video file you just need to create an instance of the @ref cv::VideoWriter class. You can specify
its properties either via parameters in the constructor or later on via the @ref cv::open function. its properties either via parameters in the constructor or later on via the @ref cv::VideoWriter::open function.
Either way, the parameters are the same: 1. The name of the output that contains the container type Either way, the parameters are the same: 1. The name of the output that contains the container type
in its extension. At the moment only *avi* is supported. We construct this from the input file, add in its extension. At the moment only *avi* is supported. We construct this from the input file, add
to this the name of the channel to use, and finish it off with the container extension. to this the name of the channel to use, and finish it off with the container extension.
...@@ -122,10 +126,10 @@ Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), //Acquire input siz ...@@ -122,10 +126,10 @@ Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), //Acquire input siz
(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT)); (int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true); outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true);
@endcode @endcode
Afterwards, you use the @ref cv::isOpened() function to find out if the open operation succeeded or Afterwards, you use the @ref cv::VideoWriter::isOpened() function to find out if the open operation succeeded or
not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open
the object with success you can send the frames of the video in a sequential order by using the @ref the object with success you can send the frames of the video in a sequential order by using the
cv::write function of the class. Alternatively, you can use its overloaded operator \<\< : @ref cv::VideoWriter::write function of the class. Alternatively, you can use its overloaded operator \<\< :
@code{.cpp} @code{.cpp}
outputVideo.write(res); //or outputVideo.write(res); //or
outputVideo << res; outputVideo << res;
......
...@@ -15,7 +15,9 @@ Cool Theory ...@@ -15,7 +15,9 @@ Cool Theory
----------- -----------
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. @note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
Morphological Operations --------------------------
Morphological Operations
------------------------
- In short: A set of operations that process images based on shapes. 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. apply a *structuring element* to an input image and generate an output image.
...@@ -59,102 +61,8 @@ Code ...@@ -59,102 +61,8 @@ Code
This tutorial code's is shown lines below. You can also download it from This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp)
@code{.cpp} @includelineno samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
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", WINDOW_AUTOSIZE );
namedWindow( "Dilation Demo", 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 );
}
@endcode
Explanation Explanation
----------- -----------
...@@ -195,9 +103,8 @@ Explanation ...@@ -195,9 +103,8 @@ Explanation
- *src*: The source image - *src*: The source image
- *erosion_dst*: The output image - *erosion_dst*: The output image
- *element*: This is the kernel we will use to perform the operation. If we do not - *element*: This is the kernel we will use to perform the operation. If we do not
specify, the default is a simple @ref cv::3x3\` matrix. Otherwise, we can specify its specify, the default is a simple `3x3` matrix. Otherwise, we can specify its
shape. For this, we need to use the function shape. For this, we need to use the function cv::getStructuringElement :
get_structuring_element:\`getStructuringElement :
@code{.cpp} @code{.cpp}
Mat element = getStructuringElement( erosion_type, Mat element = getStructuringElement( erosion_type,
Size( 2*erosion_size + 1, 2*erosion_size+1 ), Size( 2*erosion_size + 1, 2*erosion_size+1 ),
...@@ -213,44 +120,42 @@ get_structuring_element:\`getStructuringElement : ...@@ -213,44 +120,42 @@ get_structuring_element:\`getStructuringElement :
specified, it is assumed to be in the center. specified, it is assumed to be in the center.
- That is all. We are ready to perform the erosion of our image. - 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 @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 (iterations) at once. We are not using it in this simple tutorial, though. You can check out the
Reference for more details. Reference for more details.
1. **dilation:** 3. **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{.cpp}
/* @function Dilation */
void Dilation( int, void* )
{
int dilation_type;
if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement( dilation_type,
Size( 2*dilation_size + 1, 2*dilation_size+1 ),
Point( dilation_size, dilation_size ) );
/// Apply the dilation operation
dilate( src, dilation_dst, element );
imshow( "Dilation Demo", dilation_dst );
}
@endcode
Results
-------
- Compile the code above and execute it with an image as argument. For instance, using this image: The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
Here we also have the option of defining our kernel, its anchor point and the size of the operator
to be used.
@code{.cpp}
/* @function Dilation */
void Dilation( int, void* )
{
int dilation_type;
if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement( dilation_type,
Size( 2*dilation_size + 1, 2*dilation_size+1 ),
Point( dilation_size, dilation_size ) );
/// Apply the dilation operation
dilate( src, dilation_dst, element );
imshow( "Dilation Demo", dilation_dst );
}
@endcode
![image](images/Morphology_1_Tutorial_Original_Image.jpg) Results
-------
We get the results below. Varying the indices in the Trackbars give different output images, Compile the code above and execute it with an image as argument. For instance, using this image:
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.jpg) ![image](images/Morphology_1_Tutorial_Original_Image.jpg)
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_Result.jpg)
...@@ -271,6 +271,6 @@ Results ...@@ -271,6 +271,6 @@ Results
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. 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.jpg .. image:: images/Morphology_1_Result.jpg
:alt: Dilation and Erosion application :alt: Dilation and Erosion application
:align: center :align: center
...@@ -42,17 +42,17 @@ Theory ...@@ -42,17 +42,17 @@ Theory
- What we want to do is to use our *model histogram* (that we know represents a skin tonality) to - What we want to do is to use our *model histogram* (that we know represents a skin tonality) to
detect skin areas in our Test Image. Here are the steps detect skin areas in our Test Image. Here are the steps
a. In each pixel of our Test Image (i.e. \f$p(i,j)\f$ ), collect the data and find the -# In each pixel of our Test Image (i.e. \f$p(i,j)\f$ ), collect the data and find the
correspondent bin location for that pixel (i.e. \f$( h_{i,j}, s_{i,j} )\f$ ). correspondent bin location for that pixel (i.e. \f$( h_{i,j}, s_{i,j} )\f$ ).
b. Lookup the *model histogram* in the correspondent bin - \f$( h_{i,j}, s_{i,j} )\f$ - and read -# Lookup the *model histogram* in the correspondent bin - \f$( h_{i,j}, s_{i,j} )\f$ - and read
the bin value. the bin value.
c. Store this bin value in a new image (*BackProjection*). Also, you may consider to normalize -# Store this bin value in a new image (*BackProjection*). Also, you may consider to normalize
the *model histogram* first, so the output for the Test Image can be visible for you. the *model histogram* first, so the output for the Test Image can be visible for you.
d. Applying the steps above, we get the following BackProjection image for our Test Image: -# Applying the steps above, we get the following BackProjection image for our Test Image:
![image](images/Back_Projection_Theory4.jpg) ![image](images/Back_Projection_Theory4.jpg)
e. In terms of statistics, the values stored in *BackProjection* represent the *probability* -# In terms of statistics, the values stored in *BackProjection* represent the *probability*
that a pixel in *Test Image* belongs to a skin area, based on the *model histogram* that we that a pixel in *Test Image* belongs to a skin area, based on the *model histogram* that we
use. For instance in our Test image, the brighter areas are more probable to be skin area use. For instance in our Test image, the brighter areas are more probable to be skin area
(as they actually are), whereas the darker areas have less probability (notice that these (as they actually are), whereas the darker areas have less probability (notice that these
...@@ -72,13 +72,13 @@ Code ...@@ -72,13 +72,13 @@ Code
- Display the backprojection and the histogram in windows. - Display the backprojection and the histogram in windows.
- **Downloadable code**: - **Downloadable code**:
a. Click -# Click
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp)
for the basic version (explained in this tutorial). for the basic version (explained in this tutorial).
b. For stuff slightly fancier (using H-S histograms and floodFill to define a mask for the -# For stuff slightly fancier (using H-S histograms and floodFill to define a mask for the
skin area) you can check the [improved skin area) you can check the [improved
demo](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp) demo](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp)
c. ...or you can always check out the classical -# ...or you can always check out the classical
[camshiftdemo](https://github.com/Itseez/opencv/tree/master/samples/cpp/camshiftdemo.cpp) [camshiftdemo](https://github.com/Itseez/opencv/tree/master/samples/cpp/camshiftdemo.cpp)
in samples. in samples.
...@@ -255,5 +255,3 @@ Results ...@@ -255,5 +255,3 @@ Results
------ ------ ------ ------ ------ ------
|R0| |R1| |R2| |R0| |R1| |R2|
------ ------ ------ ------ ------ ------
...@@ -10,7 +10,7 @@ In this tutorial you will learn how to: ...@@ -10,7 +10,7 @@ In this tutorial you will learn how to:
- To calculate histograms of arrays of images by using the OpenCV function @ref cv::calcHist - To calculate histograms of arrays of images by using the OpenCV function @ref cv::calcHist
- To normalize an array by using the function @ref cv::normalize - To normalize an array by using the function @ref cv::normalize
@note In the last tutorial (@ref histogram_equalization) we talked about a particular kind of @note In the last tutorial (@ref tutorial_histogram_equalization) we talked about a particular kind of
histogram called *Image histogram*. Now we will considerate it in its more general concept. Read on! histogram called *Image histogram*. Now we will considerate it in its more general concept. Read on!
### What are histograms? ### What are histograms?
...@@ -42,10 +42,10 @@ histogram called *Image histogram*. Now we will considerate it in its more gener ...@@ -42,10 +42,10 @@ histogram called *Image histogram*. Now we will considerate it in its more gener
keep count not only of color intensities, but of whatever image features that we want to measure keep count not only of color intensities, but of whatever image features that we want to measure
(i.e. gradients, directions, etc). (i.e. gradients, directions, etc).
- Let's identify some parts of the histogram: - Let's identify some parts of the histogram:
a. **dims**: The number of parameters you want to collect data of. In our example, **dims = 1** -# **dims**: The number of parameters you want to collect data of. In our example, **dims = 1**
because we are only counting the intensity values of each pixel (in a greyscale image). because we are only counting the intensity values of each pixel (in a greyscale image).
b. **bins**: It is the number of **subdivisions** in each dim. In our example, **bins = 16** -# **bins**: It is the number of **subdivisions** in each dim. In our example, **bins = 16**
c. **range**: The limits for the values to be measured. In this case: **range = [0,255]** -# **range**: The limits for the values to be measured. In this case: **range = [0,255]**
- What if you want to count two features? In this case your resulting histogram would be a 3D plot - What if you want to count two features? In this case your resulting histogram would be a 3D plot
(in which x and y would be \f$bin_{x}\f$ and \f$bin_{y}\f$ for each feature and z would be the number of (in which x and y would be \f$bin_{x}\f$ and \f$bin_{y}\f$ for each feature and z would be the number of
counts for each combination of \f$(bin_{x}, bin_{y})\f$. The same would apply for more features (of counts for each combination of \f$(bin_{x}, bin_{y})\f$. The same would apply for more features (of
...@@ -68,82 +68,8 @@ Code ...@@ -68,82 +68,8 @@ Code
- **Downloadable code**: Click - **Downloadable code**: Click
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp)
- **Code at glance:** - **Code at glance:**
@code{.cpp} @includelineno samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/*
* @function main
*/
int main( int argc, char** argv )
{
Mat src, dst;
/// Load image
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
/// Separate the image in 3 places ( B, G and R )
vector<Mat> bgr_planes;
split( src, bgr_planes );
/// Establish the number of bins
int histSize = 256;
/// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat b_hist, g_hist, r_hist;
/// Compute the histograms:
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
// Draw the histograms for B, G and R
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
/// Normalize the result to [ 0, histImage.rows ]
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// Draw for each channel
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
}
/// Display
namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
imshow("calcHist Demo", histImage );
waitKey(0);
return 0;
}
@endcode
Explanation Explanation
----------- -----------
...@@ -169,26 +95,26 @@ Explanation ...@@ -169,26 +95,26 @@ Explanation
4. Now we are ready to start configuring the **histograms** for each plane. Since we are working 4. Now we are ready to start configuring the **histograms** for each plane. Since we are working
with the B, G and R planes, we know that our values will range in the interval \f$[0,255]\f$ with the B, G and R planes, we know that our values will range in the interval \f$[0,255]\f$
a. Establish number of bins (5, 10...): -# Establish number of bins (5, 10...):
@code{.cpp} @code{.cpp}
int histSize = 256; //from 0 to 255 int histSize = 256; //from 0 to 255
@endcode @endcode
b. Set the range of values (as we said, between 0 and 255 ) -# Set the range of values (as we said, between 0 and 255 )
@code{.cpp} @code{.cpp}
/// Set the ranges ( for B,G,R) ) /// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ; //the upper boundary is exclusive float range[] = { 0, 256 } ; //the upper boundary is exclusive
const float* histRange = { range }; const float* histRange = { range };
@endcode @endcode
c. We want our bins to have the same size (uniform) and to clear the histograms in the -# We want our bins to have the same size (uniform) and to clear the histograms in the
beginning, so: beginning, so:
@code{.cpp} @code{.cpp}
bool uniform = true; bool accumulate = false; bool uniform = true; bool accumulate = false;
@endcode @endcode
d. Finally, we create the Mat objects to save our histograms. Creating 3 (one for each plane): -# Finally, we create the Mat objects to save our histograms. Creating 3 (one for each plane):
@code{.cpp} @code{.cpp}
Mat b_hist, g_hist, r_hist; Mat b_hist, g_hist, r_hist;
@endcode @endcode
e. We proceed to calculate the histograms by using the OpenCV function @ref cv::calcHist : -# We proceed to calculate the histograms by using the OpenCV function @ref cv::calcHist :
@code{.cpp} @code{.cpp}
/// Compute the histograms: /// Compute the histograms:
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate ); calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
...@@ -254,18 +180,15 @@ Explanation ...@@ -254,18 +180,15 @@ Explanation
Scalar( 0, 0, 255), 2, 8, 0 ); Scalar( 0, 0, 255), 2, 8, 0 );
} }
@endcode @endcode
we use the expression: we use the expression:
@code{.cpp} @code{.cpp}
b_hist.at<float>(i) b_hist.at<float>(i)
@endcode @endcode
where \f$i\f$ indicates the dimension. If it were a 2D-histogram we would use something like: where \f$i\f$ indicates the dimension. If it were a 2D-histogram we would use something like:
@code{.cpp} @code{.cpp}
b_hist.at<float>( i, j ) b_hist.at<float>( i, j )
@endcode @endcode
8. Finally we display our histograms and wait for the user to exit: 8. Finally we display our histograms and wait for the user to exit:
@code{.cpp} @code{.cpp}
namedWindow("calcHist Demo", WINDOW_AUTOSIZE ); namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
...@@ -275,6 +198,7 @@ Explanation ...@@ -275,6 +198,7 @@ Explanation
return 0; return 0;
@endcode @endcode
Result Result
------ ------
...@@ -285,5 +209,3 @@ Result ...@@ -285,5 +209,3 @@ Result
2. Produces the following histogram: 2. Produces the following histogram:
![image](images/Histogram_Calculation_Result.jpg) ![image](images/Histogram_Calculation_Result.jpg)
...@@ -17,7 +17,7 @@ Theory ...@@ -17,7 +17,7 @@ Theory
(\f$d(H_{1}, H_{2})\f$) to express how well both histograms match. (\f$d(H_{1}, H_{2})\f$) to express how well both histograms match.
- OpenCV implements the function @ref cv::compareHist to perform a comparison. It also offers 4 - OpenCV implements the function @ref cv::compareHist to perform a comparison. It also offers 4
different metrics to compute the matching: different metrics to compute the matching:
a. **Correlation ( CV_COMP_CORREL )** -# **Correlation ( CV_COMP_CORREL )**
\f[d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}}\f] \f[d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}}\f]
...@@ -27,15 +27,15 @@ Theory ...@@ -27,15 +27,15 @@ Theory
and \f$N\f$ is the total number of histogram bins. and \f$N\f$ is the total number of histogram bins.
b. **Chi-Square ( CV_COMP_CHISQR )** -# **Chi-Square ( CV_COMP_CHISQR )**
\f[d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}\f] \f[d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}\f]
c. **Intersection ( method=CV_COMP_INTERSECT )** -# **Intersection ( method=CV_COMP_INTERSECT )**
\f[d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))\f] \f[d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))\f]
d. **Bhattacharyya distance ( CV_COMP_BHATTACHARYYA )** -# **Bhattacharyya distance ( CV_COMP_BHATTACHARYYA )**
\f[d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}}\f] \f[d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}}\f]
...@@ -165,4 +165,3 @@ match. As we can see, the match *base-base* is the highest of all as expected. A ...@@ -165,4 +165,3 @@ match. As we can see, the match *base-base* is the highest of all as expected. A
that the match *base-half* is the second best match (as we predicted). For the other two metrics, that the match *base-half* is the second best match (as we predicted). For the other two metrics,
the less the result, the better the match. We can observe that the matches between the test 1 and the less the result, the better the match. We can observe that the matches between the test 1 and
test 2 with respect to the base are worse, which again, was expected. test 2 with respect to the base are worse, which again, was expected.
...@@ -7,7 +7,7 @@ Goal ...@@ -7,7 +7,7 @@ Goal
In this tutorial you will learn: In this tutorial you will learn:
- What an image histogram is and why it is useful - What an image histogram is and why it is useful
- To equalize histograms of images by using the OpenCV <function@ref> cv::equalizeHist - To equalize histograms of images by using the OpenCV function @ref cv::equalizeHist
Theory Theory
------ ------
...@@ -59,54 +59,13 @@ Code ...@@ -59,54 +59,13 @@ Code
- **What does this program do?** - **What does this program do?**
- Loads an image - Loads an image
- Convert the original image to grayscale - Convert the original image to grayscale
- Equalize the Histogram by using the OpenCV function @ref cv::EqualizeHist - Equalize the Histogram by using the OpenCV function @ref cv::equalizeHist
- Display the source and equalized images in a window. - Display the source and equalized images in a window.
- **Downloadable code**: Click - **Downloadable code**: Click
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp)
- **Code at glance:** - **Code at glance:**
@code{.cpp} @includelineno samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
/* @function main */
int main( int argc, char** argv )
{
Mat src, dst;
char* source_window = "Source image";
char* equalized_window = "Equalized Image";
/// Load image
src = imread( argv[1], 1 );
if( !src.data )
{ cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
return -1;}
/// Convert to grayscale
cvtColor( src, src, COLOR_BGR2GRAY );
/// Apply Histogram Equalization
equalizeHist( src, dst );
/// Display results
namedWindow( source_window, WINDOW_AUTOSIZE );
namedWindow( equalized_window, WINDOW_AUTOSIZE );
imshow( source_window, src );
imshow( equalized_window, dst );
/// Wait until user exits the program
waitKey(0);
return 0;
}
@endcode
Explanation Explanation
----------- -----------
...@@ -149,6 +108,7 @@ Explanation ...@@ -149,6 +108,7 @@ Explanation
waitKey(0); waitKey(0);
return 0; return 0;
@endcode @endcode
Results Results
------- -------
...@@ -173,8 +133,6 @@ Results ...@@ -173,8 +133,6 @@ Results
Notice how the number of pixels is more distributed through the intensity range. Notice how the number of pixels is more distributed through the intensity range.
**note** @note
Are you wondering how did we draw the Histogram figures shown above? Check out the following Are you wondering how did we draw the Histogram figures shown above? Check out the following
tutorial! tutorial!
...@@ -23,8 +23,8 @@ template image (patch). ...@@ -23,8 +23,8 @@ template image (patch).
- We need two primary components: - We need two primary components:
a. **Source image (I):** The image in which we expect to find a match to the template image -# **Source image (I):** The image in which we expect to find a match to the template image
b. **Template image (T):** The patch image which will be compared to the template image -# **Template image (T):** The patch image which will be compared to the template image
our goal is to detect the highest matching area: our goal is to detect the highest matching area:
...@@ -300,5 +300,3 @@ Results ...@@ -300,5 +300,3 @@ Results
other possible high matches. other possible high matches.
![image](images/Template_Matching_Image_Result.jpg) ![image](images/Template_Matching_Image_Result.jpg)
...@@ -11,12 +11,12 @@ In this tutorial you will learn how to: ...@@ -11,12 +11,12 @@ In this tutorial you will learn how to:
Theory Theory
------ ------
1. The *Canny Edge detector* was developed by John F. Canny in 1986. Also known to many as the 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: *optimal detector*, Canny algorithm aims to satisfy three main criteria:
- **Low error rate:** Meaning a good detection of only existent edges. - **Low error rate:** Meaning a good detection of only existent edges.
- **Good localization:** The distance between edge pixels detected and real edge pixels have - **Good localization:** The distance between edge pixels detected and real edge pixels have
to be minimized. to be minimized.
- **Minimal response:** Only one detector response per edge. - **Minimal response:** Only one detector response per edge.
### Steps ### Steps
...@@ -32,8 +32,7 @@ Theory ...@@ -32,8 +32,7 @@ Theory
\end{bmatrix}\f] \end{bmatrix}\f]
2. Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel: 2. Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel:
a. Apply a pair of convolution masks (in \f$x\f$ and \f$y\f$ directions: 1. Apply a pair of convolution masks (in \f$x\f$ and \f$y\f$ directions:
\f[G_{x} = \begin{bmatrix} \f[G_{x} = \begin{bmatrix}
-1 & 0 & +1 \\ -1 & 0 & +1 \\
-2 & 0 & +2 \\ -2 & 0 & +2 \\
...@@ -44,22 +43,20 @@ Theory ...@@ -44,22 +43,20 @@ Theory
+1 & +2 & +1 +1 & +2 & +1
\end{bmatrix}\f] \end{bmatrix}\f]
b. Find the gradient strength and direction with: 2. Find the gradient strength and direction with:
\f[\begin{array}{l} \f[\begin{array}{l}
G = \sqrt{ G_{x}^{2} + G_{y}^{2} } \\ G = \sqrt{ G_{x}^{2} + G_{y}^{2} } \\
\theta = \arctan(\dfrac{ G_{y} }{ G_{x} }) \theta = \arctan(\dfrac{ G_{y} }{ G_{x} })
\end{array}\f] \end{array}\f]
The direction is rounded to one of four possible angles (namely 0, 45, 90 or 135) The direction is rounded to one of four possible angles (namely 0, 45, 90 or 135)
3. *Non-maximum* suppression is applied. This removes pixels that are not considered to be part of 3. *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. an edge. Hence, only thin lines (candidate edges) will remain.
4. *Hysteresis*: The final step. Canny does use two thresholds (upper and lower): 4. *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 1. 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. 2. 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 3. 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. connected to a pixel that is above the *upper* threshold.
Canny recommended a *upper*:*lower* ratio between 2:1 and 3:1. Canny recommended a *upper*:*lower* ratio between 2:1 and 3:1.
...@@ -78,76 +75,8 @@ Code ...@@ -78,76 +75,8 @@ Code
2. The tutorial code's is shown lines below. You can also download it from 2. The tutorial code's is shown lines below. You can also download it from
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp)
@code{.cpp} @includelineno samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
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, COLOR_BGR2GRAY );
/// Create a window
namedWindow( window_name, 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;
}
@endcode
Explanation Explanation
----------- -----------
...@@ -164,11 +93,11 @@ Explanation ...@@ -164,11 +93,11 @@ Explanation
char* window_name = "Edge Map"; char* window_name = "Edge Map";
@endcode @endcode
Note the following: Note the following:
a. We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*) 1. We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*)
b. We set the kernel size of \f$3\f$ (for the Sobel operations to be performed internally by the 2. We set the kernel size of \f$3\f$ (for the Sobel operations to be performed internally by the
Canny function) Canny function)
c. We set a maximum value for the lower Threshold of \f$100\f$. 3. We set a maximum value for the lower Threshold of \f$100\f$.
2. Loads the source image: 2. Loads the source image:
@code{.cpp} @code{.cpp}
...@@ -196,17 +125,17 @@ Explanation ...@@ -196,17 +125,17 @@ Explanation
@endcode @endcode
Observe the following: Observe the following:
a. The variable to be controlled by the Trackbar is *lowThreshold* with a limit of 1. The variable to be controlled by the Trackbar is *lowThreshold* with a limit of
*max_lowThreshold* (which we set to 100 previously) *max_lowThreshold* (which we set to 100 previously)
b. Each time the Trackbar registers an action, the callback function *CannyThreshold* will be 2. Each time the Trackbar registers an action, the callback function *CannyThreshold* will be
invoked. invoked.
7. Let's check the *CannyThreshold* function, step by step: 7. Let's check the *CannyThreshold* function, step by step:
a. First, we blur the image with a filter of kernel size 3: 1. First, we blur the image with a filter of kernel size 3:
@code{.cpp} @code{.cpp}
blur( src_gray, detected_edges, Size(3,3) ); blur( src_gray, detected_edges, Size(3,3) );
@endcode @endcode
b. Second, we apply the OpenCV function @ref cv::Canny : 2. Second, we apply the OpenCV function @ref cv::Canny :
@code{.cpp} @code{.cpp}
Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
@endcode @endcode
...@@ -224,12 +153,12 @@ Explanation ...@@ -224,12 +153,12 @@ Explanation
@code{.cpp} @code{.cpp}
dst = Scalar::all(0); dst = Scalar::all(0);
@endcode @endcode
9. Finally, we will use the function @ref cv::copyTo to map only the areas of the image that are 9. Finally, we will use the function @ref cv::Mat::copyTo to map only the areas of the image that are
identified as edges (on a black background). identified as edges (on a black background).
@code{.cpp} @code{.cpp}
src.copyTo( dst, detected_edges); src.copyTo( dst, detected_edges);
@endcode @endcode
@ref cv::copyTo copy the *src* image onto *dst*. However, it will only copy the pixels in the @ref cv::Mat::copyTo copy the *src* image onto *dst*. However, it will only copy the pixels in the
locations where they have non-zero values. Since the output of the Canny detector is the edge 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 contours on a black background, the resulting *dst* will be black in all the area but the
detected edges. detected edges.
...@@ -251,4 +180,3 @@ Result ...@@ -251,4 +180,3 @@ Result
![image](images/Canny_Detector_Tutorial_Result.jpg) ![image](images/Canny_Detector_Tutorial_Result.jpg)
- Notice how the image is superposed to the black background on the edge regions. - Notice how the image is superposed to the black background on the edge regions.
...@@ -24,8 +24,8 @@ Theory ...@@ -24,8 +24,8 @@ Theory
3. In this tutorial, we will briefly explore two ways of defining the extra padding (border) for an 3. In this tutorial, we will briefly explore two ways of defining the extra padding (border) for an
image: image:
a. **BORDER_CONSTANT**: Pad the image with a constant value (i.e. black or \f$0\f$ -# **BORDER_CONSTANT**: Pad the image with a constant value (i.e. black or \f$0\f$
b. **BORDER_REPLICATE**: The row or column at the very edge of the original is replicated to -# **BORDER_REPLICATE**: The row or column at the very edge of the original is replicated to
the extra border. the extra border.
This will be seen more clearly in the Code section. This will be seen more clearly in the Code section.
...@@ -175,13 +175,13 @@ Explanation ...@@ -175,13 +175,13 @@ Explanation
@endcode @endcode
The arguments are: The arguments are:
a. *src*: Source image -# *src*: Source image
b. *dst*: Destination image -# *dst*: Destination image
c. *top*, *bottom*, *left*, *right*: Length in pixels of the borders at each side of the 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. We define them as being 5% of the original size of the image.
d. *borderType*: Define what type of border is applied. It can be constant or replicate for -# *borderType*: Define what type of border is applied. It can be constant or replicate for
this example. this example.
e. *value*: If *borderType* is *BORDER_CONSTANT*, this is the value used to fill the border -# *value*: If *borderType* is *BORDER_CONSTANT*, this is the value used to fill the border
pixels. pixels.
8. We display our output image in the image created previously 8. We display our output image in the image created previously
...@@ -204,5 +204,3 @@ Results ...@@ -204,5 +204,3 @@ Results
option looks: option looks:
![image](images/CopyMakeBorder_Tutorial_Results.jpg) ![image](images/CopyMakeBorder_Tutorial_Results.jpg)
...@@ -159,15 +159,15 @@ Explanation ...@@ -159,15 +159,15 @@ Explanation
@endcode @endcode
The arguments denote: The arguments denote:
a. *src*: Source image -# *src*: Source image
b. *dst*: Destination image -# *dst*: Destination image
c. *ddepth*: The depth of *dst*. A negative value (such as \f$-1\f$) indicates that the depth is -# *ddepth*: The depth of *dst*. A negative value (such as \f$-1\f$) indicates that the depth is
the same as the source. the same as the source.
d. *kernel*: The kernel to be scanned through the image -# *kernel*: The kernel to be scanned through the image
e. *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)* -# *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)*
indicates the center by default. indicates the center by default.
f. *delta*: A value to be added to each pixel during the convolution. By default it is \f$0\f$ -# *delta*: A value to be added to each pixel during the convolution. By default it is \f$0\f$
g. *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial) -# *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial)
7. Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be 7. Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be
updated in the range indicated. updated in the range indicated.
...@@ -180,5 +180,3 @@ Results ...@@ -180,5 +180,3 @@ Results
the kernel size should change, as can be seen in the series of snapshots below: the kernel size should change, as can be seen in the series of snapshots below:
![image](images/filter_2d_tutorial_result.jpg) ![image](images/filter_2d_tutorial_result.jpg)
...@@ -20,8 +20,8 @@ straight lines. \#. To apply the Transform, first an edge detection pre-processi ...@@ -20,8 +20,8 @@ straight lines. \#. To apply the Transform, first an edge detection pre-processi
1. As you know, a line in the image space can be expressed with two variables. For example: 1. As you know, a line in the image space can be expressed with two variables. For example:
a. In the **Cartesian coordinate system:** Parameters: \f$(m,b)\f$. -# In the **Cartesian coordinate system:** Parameters: \f$(m,b)\f$.
b. In the **Polar coordinate system:** Parameters: \f$(r,\theta)\f$ -# In the **Polar coordinate system:** Parameters: \f$(r,\theta)\f$
![image](images/Hough_Lines_Tutorial_Theory_0.jpg) ![image](images/Hough_Lines_Tutorial_Theory_0.jpg)
...@@ -180,7 +180,7 @@ Explanation ...@@ -180,7 +180,7 @@ Explanation
available for this purpose: available for this purpose:
3. **Standard Hough Line Transform** 3. **Standard Hough Line Transform**
a. First, you apply the Transform: -# First, you apply the Transform:
@code{.cpp} @code{.cpp}
vector<Vec2f> lines; vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
...@@ -196,7 +196,7 @@ Explanation ...@@ -196,7 +196,7 @@ Explanation
- *threshold*: The minimum number of intersections to "*detect*" a line - *threshold*: The minimum number of intersections to "*detect*" a line
- *srn* and *stn*: Default parameters to zero. Check OpenCV reference for more info. - *srn* and *stn*: Default parameters to zero. Check OpenCV reference for more info.
b. And then you display the result by drawing the lines. -# And then you display the result by drawing the lines.
@code{.cpp} @code{.cpp}
for( size_t i = 0; i < lines.size(); i++ ) for( size_t i = 0; i < lines.size(); i++ )
{ {
...@@ -212,7 +212,7 @@ Explanation ...@@ -212,7 +212,7 @@ Explanation
} }
@endcode @endcode
4. **Probabilistic Hough Line Transform** 4. **Probabilistic Hough Line Transform**
a. First you apply the transform: -# First you apply the transform:
@code{.cpp} @code{.cpp}
vector<Vec4i> lines; vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
...@@ -231,7 +231,7 @@ Explanation ...@@ -231,7 +231,7 @@ Explanation
this number of points are disregarded. this number of points are disregarded.
- *maxLineGap*: The maximum gap between two points to be considered in the same line. - *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. -# And then you display the result by drawing the lines.
@code{.cpp} @code{.cpp}
for( size_t i = 0; i < lines.size(); i++ ) for( size_t i = 0; i < lines.size(); i++ )
{ {
...@@ -267,4 +267,3 @@ We get the following result by using the Probabilistic Hough Line Transform: ...@@ -267,4 +267,3 @@ We get the following result by using the Probabilistic Hough Line Transform:
You may observe that the number of lines detected vary while you change the *threshold*. The 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 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). (since you will need more points to declare a line detected).
...@@ -206,16 +206,16 @@ Explanation ...@@ -206,16 +206,16 @@ Explanation
How do we update our mapping matrices *mat_x* and *mat_y*? Go on reading: How do we update our mapping matrices *mat_x* and *mat_y*? Go on reading:
6. **Updating the mapping matrices:** We are going to perform 4 different mappings: 6. **Updating the mapping matrices:** We are going to perform 4 different mappings:
a. Reduce the picture to half its size and will display it in the middle: -# Reduce the picture to half its size and will display it in the middle:
\f[h(i,j) = ( 2*i - src.cols/2 + 0.5, 2*j - src.rows/2 + 0.5)\f] \f[h(i,j) = ( 2*i - src.cols/2 + 0.5, 2*j - src.rows/2 + 0.5)\f]
for all pairs \f$(i,j)\f$ such that: \f$\dfrac{src.cols}{4}<i<\dfrac{3 \cdot src.cols}{4}\f$ and for all pairs \f$(i,j)\f$ such that: \f$\dfrac{src.cols}{4}<i<\dfrac{3 \cdot src.cols}{4}\f$ and
\f$\dfrac{src.rows}{4}<j<\dfrac{3 \cdot src.rows}{4}\f$ \f$\dfrac{src.rows}{4}<j<\dfrac{3 \cdot src.rows}{4}\f$
b. Turn the image upside down: \f$h( i, j ) = (i, src.rows - j)\f$ -# Turn the image upside down: \f$h( i, j ) = (i, src.rows - j)\f$
c. Reflect the image from left to right: \f$h(i,j) = ( src.cols - i, j )\f$ -# Reflect the image from left to right: \f$h(i,j) = ( src.cols - i, j )\f$
d. Combination of b and c: \f$h(i,j) = ( src.cols - i, src.rows - j )\f$ -# Combination of b and c: \f$h(i,j) = ( src.cols - i, src.rows - j )\f$
This is expressed in the following snippet. Here, *map_x* represents the first coordinate of This is expressed in the following snippet. Here, *map_x* represents the first coordinate of
*h(i,j)* and *map_y* the second coordinate. *h(i,j)* and *map_y* the second coordinate.
...@@ -277,4 +277,3 @@ Result ...@@ -277,4 +277,3 @@ Result
5. Reflecting it in both directions: 5. Reflecting it in both directions:
![image](images/Remap_Tutorial_Result_3.jpg) ![image](images/Remap_Tutorial_Result_3.jpg)
...@@ -53,7 +53,7 @@ Theory ...@@ -53,7 +53,7 @@ Theory
Assuming that the image to be operated is \f$I\f$: Assuming that the image to be operated is \f$I\f$:
1. We calculate two derivatives: 1. We calculate two derivatives:
a. **Horizontal changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{x}\f$ with odd 1. **Horizontal changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{x}\f$ with odd
size. For example for a kernel size of 3, \f$G_{x}\f$ would be computed as: size. For example for a kernel size of 3, \f$G_{x}\f$ would be computed as:
\f[G_{x} = \begin{bmatrix} \f[G_{x} = \begin{bmatrix}
...@@ -62,7 +62,7 @@ Assuming that the image to be operated is \f$I\f$: ...@@ -62,7 +62,7 @@ Assuming that the image to be operated is \f$I\f$:
-1 & 0 & +1 -1 & 0 & +1
\end{bmatrix} * I\f] \end{bmatrix} * I\f]
b. **Vertical changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{y}\f$ with odd 2. **Vertical changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{y}\f$ with odd
size. For example for a kernel size of 3, \f$G_{y}\f$ would be computed as: size. For example for a kernel size of 3, \f$G_{y}\f$ would be computed as:
\f[G_{y} = \begin{bmatrix} \f[G_{y} = \begin{bmatrix}
...@@ -81,11 +81,10 @@ Assuming that the image to be operated is \f$I\f$: ...@@ -81,11 +81,10 @@ Assuming that the image to be operated is \f$I\f$:
\f[G = |G_{x}| + |G_{y}|\f] \f[G = |G_{x}| + |G_{y}|\f]
@note @note
When the size of the kernel is @ref cv::3\`, the Sobel kernel shown above may produce noticeable When the size of the kernel is `3`, the Sobel kernel shown above may produce noticeable
inaccuracies (after all, Sobel is only an approximation of the derivative). OpenCV addresses inaccuracies (after all, Sobel is only an approximation of the derivative). OpenCV addresses
this inaccuracy for kernels of size 3 by using the :scharr:\`Scharr function. This is as fast 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: but more accurate than the standar Sobel function. It implements the following kernels:
\f[G_{x} = \begin{bmatrix} \f[G_{x} = \begin{bmatrix}
-3 & 0 & +3 \\ -3 & 0 & +3 \\
-10 & 0 & +10 \\ -10 & 0 & +10 \\
...@@ -95,11 +94,11 @@ Assuming that the image to be operated is \f$I\f$: ...@@ -95,11 +94,11 @@ Assuming that the image to be operated is \f$I\f$:
0 & 0 & 0 \\ 0 & 0 & 0 \\
+3 & +10 & +3 +3 & +10 & +3
\end{bmatrix}\f] \end{bmatrix}\f]
@note
You can check out more information of this function in the OpenCV reference (@ref cv::Scharr ). You can check out more information of this function in the OpenCV reference (@ref cv::Scharr ).
Also, in the sample code below, you will notice that above the code for @ref cv::Sobel function Also, in the sample code below, you will notice that above the code for @ref cv::Sobel function
there is also code for the @ref cv::Scharr function commented. Uncommenting it (and obviously there is also code for the @ref cv::Scharr function commented. Uncommenting it (and obviously
commenting the Sobel stuff) should give you an idea of how this function works. commenting the Sobel stuff) should give you an idea of how this function works.
Code Code
---- ----
...@@ -110,65 +109,8 @@ Code ...@@ -110,65 +109,8 @@ Code
2. The tutorial code's is shown lines below. You can also download it from 2. The tutorial code's is shown lines below. You can also download it from
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
@code{.cpp} @includelineno samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
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, COLOR_RGB2GRAY );
/// Create window
namedWindow( window_name, 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;
}
@endcode
Explanation Explanation
----------- -----------
...@@ -239,5 +181,3 @@ Results ...@@ -239,5 +181,3 @@ Results
1. Here is the output of applying our basic detector to *lena.jpg*: 1. Here is the output of applying our basic detector to *lena.jpg*:
![image](images/Sobel_Derivatives_Tutorial_Result.jpg) ![image](images/Sobel_Derivatives_Tutorial_Result.jpg)
...@@ -18,9 +18,9 @@ Theory ...@@ -18,9 +18,9 @@ Theory
transformation) followed by a *vector addition* (translation). transformation) followed by a *vector addition* (translation).
2. From the above, We can use an Affine Transformation to express: 2. From the above, We can use an Affine Transformation to express:
a. Rotations (linear transformation) -# Rotations (linear transformation)
b. Translations (vector addition) -# Translations (vector addition)
c. Scale operations (linear transformation) -# Scale operations (linear transformation)
you can see that, in essence, an Affine Transformation represents a **relation** between two you can see that, in essence, an Affine Transformation represents a **relation** between two
images. images.
...@@ -41,7 +41,7 @@ Theory ...@@ -41,7 +41,7 @@ Theory
begin{bmatrix} begin{bmatrix}
a_{00} & a_{01} & b_{00} \\ a_{10} & a_{11} & b_{10} a_{00} & a_{01} & b_{00} \\ a_{10} & a_{11} & b_{10}
end{bmatrix}_{2 times 3} end{bmatrix}_{2 times 3}
Considering that we want to transform a 2D vector \f$X = \begin{bmatrix}x \\ y\end{bmatrix}\f$ by Considering that we want to transform a 2D vector \f$X = \begin{bmatrix}x \\ y\end{bmatrix}\f$ by
...@@ -58,8 +58,8 @@ Theory ...@@ -58,8 +58,8 @@ Theory
1. Excellent question. We mentioned that an Affine Transformation is basically a **relation** 1. Excellent question. We mentioned that an Affine Transformation is basically a **relation**
between two images. The information about this relation can come, roughly, in two ways: between two images. The information about this relation can come, roughly, in two ways:
a. We know both \f$X\f$ and T and we also know that they are related. Then our job is to find \f$M\f$ -# We know both \f$X\f$ and T and we also know that they are related. Then our job is to find \f$M\f$
b. We know \f$M\f$ and \f$X\f$. To obtain \f$T\f$ we only need to apply \f$T = M \cdot X\f$. Our information -# We know \f$M\f$ and \f$X\f$. To obtain \f$T\f$ we only need to apply \f$T = M \cdot X\f$. Our information
for \f$M\f$ may be explicit (i.e. have the 2-by-3 matrix) or it can come as a geometric relation for \f$M\f$ may be explicit (i.e. have the 2-by-3 matrix) or it can come as a geometric relation
between points. between points.
...@@ -219,9 +219,9 @@ Explanation ...@@ -219,9 +219,9 @@ Explanation
7. **Rotate:** To rotate an image, we need to know two things: 7. **Rotate:** To rotate an image, we need to know two things:
a. The center with respect to which the image will rotate -# The center with respect to which the image will rotate
b. The angle to be rotated. In OpenCV a positive angle is counter-clockwise -# The angle to be rotated. In OpenCV a positive angle is counter-clockwise
c. *Optional:* A scale factor -# *Optional:* A scale factor
We define these parameters with the following snippet: We define these parameters with the following snippet:
@code{.cpp} @code{.cpp}
...@@ -269,5 +269,3 @@ Result ...@@ -269,5 +269,3 @@ Result
factor, we get: factor, we get:
![image](images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg) ![image](images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg)
...@@ -12,8 +12,7 @@ In this tutorial you will learn how to: ...@@ -12,8 +12,7 @@ In this tutorial you will learn how to:
Theory Theory
------ ------
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. .. @note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
container:: enumeratevisibleitemswithsquare
- Usually we need to convert an image to a size different than its original. For this, there are - Usually we need to convert an image to a size different than its original. For this, there are
two possible options: two possible options:
...@@ -53,161 +52,109 @@ container:: enumeratevisibleitemswithsquare ...@@ -53,161 +52,109 @@ container:: enumeratevisibleitemswithsquare
predecessor. Iterating this process on the input image \f$G_{0}\f$ (original image) produces the predecessor. Iterating this process on the input image \f$G_{0}\f$ (original image) produces the
entire pyramid. entire pyramid.
- The procedure above was useful to downsample an image. What if we want to make it bigger?: - The procedure above was useful to downsample an image. What if we want to make it bigger?:
columns filled with zeros (\f$0\f$)
- First, upsize the image to twice the original in each dimension, wit the new even rows and - First, upsize the image to twice the original in each dimension, wit the new even rows and
columns filled with zeros (\f$0\f$)
- Perform a convolution with the same kernel shown above (multiplied by 4) to approximate the - Perform a convolution with the same kernel shown above (multiplied by 4) to approximate the
values of the "missing pixels" values of the "missing pixels"
- These two procedures (downsampling and upsampling as explained above) are implemented by the - These two procedures (downsampling and upsampling as explained above) are implemented by the
OpenCV functions @ref cv::pyrUp and @ref cv::pyrDown , as we will see in an example with the OpenCV functions @ref cv::pyrUp and @ref cv::pyrDown , as we will see in an example with the
code below: code below:
@note When we reduce the size of an image, we are actually *losing* information of the image. Code @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 This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp)
@code{.cpp}
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
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.jpg" );
if( !src.data )
{ printf(" No data! -- Exiting the program \n");
return -1; }
tmp = src;
dst = tmp;
/// Create window
namedWindow( window_name, 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 ); @includelineno samples/cpp/tutorial_code/ImgProc/Pyramids.cpp
tmp = dst;
}
return 0;
}
@endcode
Explanation Explanation
----------- -----------
1. Let's check the general structure of the program: 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) - Load an image (in this case it is defined in the program, the user does not have to enter it
@code{.cpp} as an argument)
/// Test image - Make sure it s divisible by 2^{n} @code{.cpp}
src = imread( "../images/chicky_512.jpg" ); /// Test image - Make sure it s divisible by 2^{n}
if( !src.data ) src = imread( "../images/chicky_512.jpg" );
{ printf(" No data! -- Exiting the program \n"); if( !src.data )
return -1; } { printf(" No data! -- Exiting the program \n");
@endcode return -1; }
- Create a Mat object to store the result of the operations (*dst*) and one to save temporal @endcode
results (*tmp*).
- Create a Mat object to store the result of the operations (*dst*) and one to save temporal
results (*tmp*).
@code{.cpp}
Mat src, dst, tmp;
/* ... */
tmp = src;
dst = tmp;
@endcode
- Create a window to display the result
@code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE );
imshow( window_name, dst );
@endcode
- Perform an infinite loop waiting for user input.
@code{.cpp}
while( true )
{
int c;
c = waitKey(10);
if( (char)c == 27 )
{ break; }
if( (char)c == 'u' )
{ pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
printf( "** Zoom In: Image x 2 \n" );
}
else if( (char)c == 'd' )
{ pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
printf( "** Zoom Out: Image / 2 \n" );
}
imshow( window_name, dst );
tmp = dst;
}
@endcode
Our program exits if the user presses *ESC*. Besides, it has two options:
- **Perform upsampling (after pressing 'u')**
@code{.cpp} @code{.cpp}
Mat src, dst, tmp; pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 )
/* ... */
tmp = src;
dst = tmp;
@endcode @endcode
- Create a window to display the result We use the function @ref cv::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,
@ref cv::pyrUp expects a size double than the input image (in this case *tmp*).
- **Perform downsampling (after pressing 'd')**
@code{.cpp} @code{.cpp}
namedWindow( window_name, WINDOW_AUTOSIZE ); pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 )
imshow( window_name, dst );
@endcode @endcode
- Perform an infinite loop waiting for user input. Similarly as with @ref cv::pyrUp , we use the function @ref cv::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,
@ref cv::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{.cpp} @code{.cpp}
while( true ) tmp = dst;
{
int c;
c = waitKey(10);
if( (char)c == 27 )
{ break; }
if( (char)c == 'u' )
{ pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
printf( "** Zoom In: Image x 2 \n" );
}
else if( (char)c == 'd' )
{ pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
printf( "** Zoom Out: Image / 2 \n" );
}
imshow( window_name, dst );
tmp = dst;
}
@endcode @endcode
Our program exits if the user presses *ESC*. Besides, it has two options:
- **Perform upsampling (after pressing 'u')**
@code{.cpp}
pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 )
@endcode
We use the function @ref cv::pyrUp with 03 arguments:
- *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,
@ref cv::pyrUp expects a size double than the input image (in this case *tmp*).
- **Perform downsampling (after pressing 'd')**
@code{.cpp}
pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 )
@endcode
Similarly as with @ref cv::pyrUp , we use the function @ref cv::pyrDown with 03
arguments:
- *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,
@ref cv::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{.cpp}
tmp = dst;
@endcode
Results Results
------- -------
...@@ -226,5 +173,3 @@ Results ...@@ -226,5 +173,3 @@ Results
is now: is now:
![image](images/Pyramids_Tutorial_PyrUp_Result.jpg) ![image](images/Pyramids_Tutorial_PyrUp_Result.jpg)
...@@ -16,67 +16,8 @@ Code ...@@ -16,67 +16,8 @@ Code
This tutorial code's is shown lines below. You can also download it from This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp) [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp)
@code{.cpp}
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv; @includelineno samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
void thresh_callback(int, void* );
@endcode
/\* @function main */ int main( int argc, char*\* argv )
{
/// Load source image and convert it to gray src = imread( argv[1], 1 );
/// Convert image to gray and blur it cvtColor( src, src_gray, COLOR_BGR2GRAY ); blur(
src_gray, src_gray, Size(3,3) );
/// Create Window char\* source_window = "Source"; namedWindow( source_window,
WINDOW_AUTOSIZE ); imshow( source_window, src );
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0); return(0);
}
/\* @function thresh_callback */ void thresh_callback(int, void* ) { Mat src_copy =
src.clone(); Mat threshold_output; vector\<vector\<Point\> \> contours; vector\<Vec4i\>
hierarchy;
/// Detect edges using Threshold threshold( src_gray, threshold_output, thresh, 255,
THRESH_BINARY );
/// Find contours findContours( threshold_output, contours, hierarchy, RETR_TREE,
CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the convex hull object for each contour vector\<vector\<Point\> \>hull(
contours.size() ); for( int i = 0; i \< contours.size(); i++ ) { convexHull(
Mat(contours[i]), hull[i], false ); }
/// Draw contours + hull results Mat drawing = Mat::zeros( threshold_output.size(),
CV_8UC3 ); for( int i = 0; i\< contours.size(); i++ ) { Scalar color = Scalar(
rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours( drawing,
contours, i, color, 1, 8, vector\<Vec4i\>(), 0, Point() ); drawContours( drawing, hull, i,
color, 1, 8, vector\<Vec4i\>(), 0, Point() ); }
/// Show in a window namedWindow( "Hull demo", WINDOW_AUTOSIZE ); imshow( "Hull demo",
drawing );
}
Explanation Explanation
----------- -----------
...@@ -84,10 +25,7 @@ Explanation ...@@ -84,10 +25,7 @@ Explanation
Result Result
------ ------
1. Here it is: Here it is:
----------- -----------
|Hull_0| |Hull_1|
----------- -----------
![Original](images/Hull_Original_Image.jpg)
![Result](images/Hull_Result.jpg)
...@@ -247,6 +247,7 @@ APP_ABI := all ...@@ -247,6 +247,7 @@ APP_ABI := all
@note We recommend setting APP_ABI := all for all targets. If you want to specify the target @note We recommend setting APP_ABI := all for all targets. If you want to specify the target
explicitly, use armeabi for ARMv5/ARMv6, armeabi-v7a for ARMv7, x86 for Intel Atom or mips for MIPS. explicitly, use armeabi for ARMv5/ARMv6, armeabi-v7a for ARMv7, x86 for Intel Atom or mips for MIPS.
@anchor tutorial_android_dev_intro_ndk
Building application native part from command line Building application native part from command line
-------------------------------------------------- --------------------------------------------------
...@@ -284,6 +285,8 @@ build tool). ...@@ -284,6 +285,8 @@ build tool).
@code{.bash} @code{.bash}
<path_where_NDK_is_placed>/ndk-build -B <path_where_NDK_is_placed>/ndk-build -B
@endcode @endcode
@anchor tutorial_android_dev_intro_eclipse
Building application native part from *Eclipse* (CDT Builder) Building application native part from *Eclipse* (CDT Builder)
------------------------------------------------------------- -------------------------------------------------------------
...@@ -331,9 +334,9 @@ to apply the changes. ...@@ -331,9 +334,9 @@ to apply the changes.
4. Open Project Properties -\> C/C++ Build, uncheck Use default build command, replace "Build 4. Open Project Properties -\> C/C++ Build, uncheck Use default build command, replace "Build
command" text from "make" to command" text from "make" to
"\\f${NDKROOT}/ndk-build.cmd" on Windows, "${NDKROOT}/ndk-build.cmd" on Windows,
"\\f${NDKROOT}/ndk-build" on Linux and MacOS. "${NDKROOT}/ndk-build" on Linux and MacOS.
![image](images/eclipse_cdt_cfg4.png) ![image](images/eclipse_cdt_cfg4.png)
...@@ -438,7 +441,7 @@ instructions](http://developer.android.com/tools/device.html) for more informati ...@@ -438,7 +441,7 @@ instructions](http://developer.android.com/tools/device.html) for more informati
![image](images/usb_device_connect_08.png) ![image](images/usb_device_connect_08.png)
\` \` \` \`
![image](images/usb_device_connect_09.png) ![image](images/usb_device_connect_09.png)
...@@ -514,5 +517,4 @@ What's next ...@@ -514,5 +517,4 @@ What's next
----------- -----------
Now, when you have your development environment set up and configured, you may want to proceed to Now, when you have your development environment set up and configured, you may want to proceed to
installing OpenCV4Android SDK. You can learn how to do that in a separate @ref O4A_SDK tutorial. installing OpenCV4Android SDK. You can learn how to do that in a separate @ref tutorial_O4A_SDK tutorial.
...@@ -13,11 +13,11 @@ This tutorial assumes you have the following installed and configured: ...@@ -13,11 +13,11 @@ This tutorial assumes you have the following installed and configured:
- Eclipse IDE - Eclipse IDE
- ADT and CDT plugins for Eclipse - ADT and CDT plugins for Eclipse
If you need help with anything of the above, you may refer to our @ref android_dev_intro guide. If you need help with anything of the above, you may refer to our @ref tutorial_android_dev_intro guide.
This tutorial also assumes you have OpenCV4Android SDK already installed on your development machine This tutorial also assumes you have OpenCV4Android SDK already installed on your development machine
and OpenCV Manager on your testing device correspondingly. If you need help with any of these, you and OpenCV Manager on your testing device correspondingly. If you need help with any of these, you
may consult our @ref O4A_SDK tutorial. may consult our @ref tutorial_O4A_SDK tutorial.
If you encounter any error after thoroughly following these steps, feel free to contact us via If you encounter any error after thoroughly following these steps, feel free to contact us via
[OpenCV4Android](https://groups.google.com/group/android-opencv/) discussion group or OpenCV [Q&A [OpenCV4Android](https://groups.google.com/group/android-opencv/) discussion group or OpenCV [Q&A
...@@ -28,7 +28,7 @@ Using OpenCV Library Within Your Android Project ...@@ -28,7 +28,7 @@ Using OpenCV Library Within Your Android Project
In this section we will explain how to make some existing project to use OpenCV. Starting with 2.4.2 In this section we will explain how to make some existing project to use OpenCV. Starting with 2.4.2
release for Android, *OpenCV Manager* is used to provide apps with the best available version of release for Android, *OpenCV Manager* is used to provide apps with the best available version of
OpenCV. You can get more information here: @ref Android_OpenCV_Manager and in these OpenCV. You can get more information here: `Android OpenCV Manager` and in these
[slides](https://docs.google.com/a/itseez.com/presentation/d/1EO_1kijgBg_BsjNp2ymk-aarg-0K279_1VZRcPplSuk/present#slide=id.p). [slides](https://docs.google.com/a/itseez.com/presentation/d/1EO_1kijgBg_BsjNp2ymk-aarg-0K279_1VZRcPplSuk/present#slide=id.p).
### Java ### Java
...@@ -52,7 +52,7 @@ Manager to access OpenCV libraries externally installed in the target system. ...@@ -52,7 +52,7 @@ Manager to access OpenCV libraries externally installed in the target system.
In most cases OpenCV Manager may be installed automatically from Google Play. For the case, when In most cases OpenCV Manager may be installed automatically from Google Play. For the case, when
Google Play is not available, i.e. emulator, developer board, etc, you can install it manually using Google Play is not available, i.e. emulator, developer board, etc, you can install it manually using
adb tool. See @ref manager_selection for details. adb tool. See `Manager Selection` for details.
There is a very base code snippet implementing the async initialization. It shows basic principles. There is a very base code snippet implementing the async initialization. It shows basic principles.
See the "15-puzzle" OpenCV sample for details. See the "15-puzzle" OpenCV sample for details.
...@@ -118,7 +118,7 @@ described above. ...@@ -118,7 +118,7 @@ described above.
In case of the application project **with a JNI part**, instead of manual libraries copying you In case of the application project **with a JNI part**, instead of manual libraries copying you
need to modify your Android.mk file: add the following two code lines after the need to modify your Android.mk file: add the following two code lines after the
"include \\f$(CLEAR_VARS)" and before "include $(CLEAR_VARS)" and before
"include path_to_OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk" "include path_to_OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk"
@code{.make} @code{.make}
OPENCV_CAMERA_MODULES:=on OPENCV_CAMERA_MODULES:=on
...@@ -160,6 +160,7 @@ described above. ...@@ -160,6 +160,7 @@ described above.
} }
} }
@endcode @endcode
### Native/C++ ### Native/C++
To build your own Android application, using OpenCV as native part, the following steps should be To build your own Android application, using OpenCV as native part, the following steps should be
...@@ -184,12 +185,13 @@ taken: ...@@ -184,12 +185,13 @@ taken:
4. Several variables can be used to customize OpenCV stuff, but you **don't need** to use them when 4. Several variables can be used to customize OpenCV stuff, but you **don't need** to use them when
your application uses the async initialization via the OpenCV Manager API. your application uses the async initialization via the OpenCV Manager API.
@note These variables should be set **before** the "include .../OpenCV.mk" line: @note These variables should be set **before** the "include .../OpenCV.mk" line:
@code{.make} @code{.make}
OPENCV_INSTALL_MODULES:=on OPENCV_INSTALL_MODULES:=on
@endcode @endcode
Copies necessary OpenCV dynamic libs to the project libs folder in order to include them
into the APK. Copies necessary OpenCV dynamic libs to the project libs folder in order to include them
into the APK.
@code{.make} @code{.make}
OPENCV_CAMERA_MODULES:=off OPENCV_CAMERA_MODULES:=off
@endcode @endcode
...@@ -200,7 +202,7 @@ Copies necessary OpenCV dynamic libs to the project libs folder in order to incl ...@@ -200,7 +202,7 @@ Copies necessary OpenCV dynamic libs to the project libs folder in order to incl
Perform static linking with OpenCV. By default dynamic link is used and the project JNI lib Perform static linking with OpenCV. By default dynamic link is used and the project JNI lib
depends on libopencv_java.so. depends on libopencv_java.so.
1. The file `Application.mk` should exist and should contain lines: 5. The file `Application.mk` should exist and should contain lines:
@code{.make} @code{.make}
APP_STL := gnustl_static APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions APP_CPPFLAGS := -frtti -fexceptions
...@@ -218,8 +220,10 @@ Copies necessary OpenCV dynamic libs to the project libs folder in order to incl ...@@ -218,8 +220,10 @@ Copies necessary OpenCV dynamic libs to the project libs folder in order to incl
@code{.make} @code{.make}
APP_PLATFORM := android-9 APP_PLATFORM := android-9
@endcode @endcode
2. Either use @ref manual \<NDK_build_cli\> ndk-build invocation or @ref setup Eclipse CDT
Builder \<CDT_Builder\> to build native JNI lib before (re)building the Java part and creating 6. Either use @ref tutorial_android_dev_intro_ndk "manual" ndk-build invocation or
@ref tutorial_android_dev_intro_eclipse "setup Eclipse CDT Builder" to build native JNI lib
before (re)building the Java part and creating
an APK. an APK.
Hello OpenCV Sample Hello OpenCV Sample
...@@ -246,7 +250,7 @@ application. It will be capable of accessing camera output, processing it and di ...@@ -246,7 +250,7 @@ application. It will be capable of accessing camera output, processing it and di
xmlns:opencv="http://schemas.android.com/apk/res-auto" xmlns:opencv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" > android:layout_height="match_parent" >
<org.opencv.android.JavaCameraView <org.opencv.android.JavaCameraView
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
...@@ -254,7 +258,7 @@ application. It will be capable of accessing camera output, processing it and di ...@@ -254,7 +258,7 @@ application. It will be capable of accessing camera output, processing it and di
android:id="@+id/HelloOpenCvView" android:id="@+id/HelloOpenCvView"
opencv:show_fps="true" opencv:show_fps="true"
opencv:camera_id="any" /> opencv:camera_id="any" />
</LinearLayout> </LinearLayout>
@endcode @endcode
8. Add the following permissions to the `AndroidManifest.xml` file: 8. Add the following permissions to the `AndroidManifest.xml` file:
...@@ -293,7 +297,7 @@ application. It will be capable of accessing camera output, processing it and di ...@@ -293,7 +297,7 @@ application. It will be capable of accessing camera output, processing it and di
} }
} }
}; };
@Override @Override
public void onResume() public void onResume()
{ {
...@@ -365,7 +369,8 @@ function and it is called on retrieving frame from camera. The callback input is ...@@ -365,7 +369,8 @@ function and it is called on retrieving frame from camera. The callback input is
CvCameraViewFrame class that represents frame from camera. CvCameraViewFrame class that represents frame from camera.
@note Do not save or use CvCameraViewFrame object out of onCameraFrame callback. This object does @note Do not save or use CvCameraViewFrame object out of onCameraFrame callback. This object does
not have its own state and its behavior out of callback is unpredictable! It has rgba() and gray() not have its own state and its behavior out of callback is unpredictable!
It has rgba() and gray()
methods that allows to get frame as RGBA and one channel gray scale Mat respectively. It expects methods that allows to get frame as RGBA and one channel gray scale Mat respectively. It expects
that onCameraFrame function returns RGBA frame that will be drawn on the screen. that onCameraFrame function returns RGBA frame that will be drawn on the screen.
...@@ -61,7 +61,7 @@ The available [installation guide](https://github.com/technomancy/leiningen#inst ...@@ -61,7 +61,7 @@ The available [installation guide](https://github.com/technomancy/leiningen#inst
easy to be followed: easy to be followed:
1. [Download the script](https://raw.github.com/technomancy/leiningen/stable/bin/lein) 1. [Download the script](https://raw.github.com/technomancy/leiningen/stable/bin/lein)
2. Place it on your \\f$PATH (cf. \~/bin is a good choice if it is on your path.) 2. Place it on your $PATH (cf. \~/bin is a good choice if it is on your path.)
3. Set the script to be executable. (i.e. chmod 755 \~/bin/lein). 3. Set the script to be executable. (i.e. chmod 755 \~/bin/lein).
If you work on Windows, follow [this instruction](https://github.com/technomancy/leiningen#windows) If you work on Windows, follow [this instruction](https://github.com/technomancy/leiningen#windows)
......
...@@ -6,8 +6,8 @@ Android development. This guide will help you to create your first Java (or Scal ...@@ -6,8 +6,8 @@ Android development. This guide will help you to create your first Java (or Scal
OpenCV. We will use either [Apache Ant](http://ant.apache.org/) or [Simple Build Tool OpenCV. We will use either [Apache Ant](http://ant.apache.org/) or [Simple Build Tool
(SBT)](http://www.scala-sbt.org/) to build the application. (SBT)](http://www.scala-sbt.org/) to build the application.
If you want to use Eclipse head to @ref Java_Eclipse. For further reading after this guide, look at If you want to use Eclipse head to @ref tutorial_java_eclipse. For further reading after this guide, look at
the @ref Android_Dev_Intro tutorials. the @ref tutorial_android_dev_intro tutorials.
What we'll do in this guide What we'll do in this guide
--------------------------- ---------------------------
...@@ -58,19 +58,23 @@ or ...@@ -58,19 +58,23 @@ or
@code{.bat} @code{.bat}
cmake -DBUILD_SHARED_LIBS=OFF -G "Visual Studio 10" .. cmake -DBUILD_SHARED_LIBS=OFF -G "Visual Studio 10" ..
@endcode @endcode
@note When OpenCV is built as a set of **static** libraries (-DBUILD_SHARED_LIBS=OFF option) the @note When OpenCV is built as a set of **static** libraries (-DBUILD_SHARED_LIBS=OFF option) the
Java bindings dynamic library is all-sufficient, i.e. doesn't depend on other OpenCV libs, but Java bindings dynamic library is all-sufficient, i.e. doesn't depend on other OpenCV libs, but
includes all the OpenCV code inside. Examine the output of CMake and ensure java is one of the includes all the OpenCV code inside.
Examine the output of CMake and ensure java is one of the
modules "To be built". If not, it's likely you're missing a dependency. You should troubleshoot by modules "To be built". If not, it's likely you're missing a dependency. You should troubleshoot by
looking through the CMake output for any Java-related tools that aren't found and installing them. looking through the CMake output for any Java-related tools that aren't found and installing them.
![image](images/cmake_output.png) ![image](images/cmake_output.png)
@note If CMake can't find Java in your system set the JAVA_HOME environment variable with the path to installed JDK before running it. E.g.: @note If CMake can't find Java in your system set the JAVA_HOME environment variable with the path to installed JDK before running it. E.g.:
@code{.bash} @code{.bash}
export JAVA_HOME=/usr/lib/jvm/java-6-oracle export JAVA_HOME=/usr/lib/jvm/java-6-oracle
cmake -DBUILD_SHARED_LIBS=OFF .. cmake -DBUILD_SHARED_LIBS=OFF ..
@endcode @endcode
Now start the build: Now start the build:
@code{.bash} @code{.bash}
make -j8 make -j8
...@@ -87,72 +91,23 @@ Java sample with Ant ...@@ -87,72 +91,23 @@ Java sample with Ant
-------------------- --------------------
@note The described sample is provided with OpenCV library in the `opencv/samples/java/ant` @note The described sample is provided with OpenCV library in the `opencv/samples/java/ant`
folder. \* Create a folder where you'll develop this sample application. folder.
- In this folder create the `build.xml` file with the following content using any text editor:
@code{.xml}
<project name="SimpleSample" basedir="." default="rebuild-run">
<property name="src.dir" value="src"/>
<property name="lib.dir" value="\f${ocvJarDir}"/>
<path id="classpath">
<fileset dir="\f${lib.dir}" includes="**/*.jar"/>
</path>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="\f${build.dir}/classes"/>
<property name="jar.dir" value="\f${build.dir}/jar"/>
<property name="main-class" value="\f${ant.project.name}"/>
<target name="clean"> - Create a folder where you'll develop this sample application.
<delete dir="\f${build.dir}"/>
</target>
<target name="compile"> - In this folder create the `build.xml` file with the following content using any text editor:
<mkdir dir="\f${classes.dir}"/> @include samples/java/ant/build.xml
<javac includeantruntime="false" srcdir="\f${src.dir}" destdir="\f${classes.dir}" classpathref="classpath"/> @note This XML file can be reused for building other Java applications. It describes a common folder structure in the lines 3 - 12 and common targets for compiling and running the application.
</target> When reusing this XML don't forget to modify the project name in the line 1, that is also the
<target name="jar" depends="compile">
<mkdir dir="\f${jar.dir}"/>
<jar destfile="\f${jar.dir}/\f${ant.project.name}.jar" basedir="\f${classes.dir}">
<manifest>
<attribute name="Main-Class" value="\f${main-class}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java fork="true" classname="\f${main-class}">
<sysproperty key="java.library.path" path="\f${ocvLibDir}"/>
<classpath>
<path refid="classpath"/>
<path location="\f${jar.dir}/\f${ant.project.name}.jar"/>
</classpath>
</java>
</target>
<target name="rebuild" depends="clean,jar"/>
<target name="rebuild-run" depends="clean,run"/>
</project>
@endcode
@note This XML file can be reused for building other Java applications. It describes a common folder structure in the lines 3 - 12 and common targets for compiling and running the application.
When reusing this XML don't forget to modify the project name in the line 1, that is also the
name of the main class (line 14). The paths to OpenCV jar and jni lib are expected as parameters name of the main class (line 14). The paths to OpenCV jar and jni lib are expected as parameters
("\\f${ocvJarDir}" in line 5 and "\\f${ocvLibDir}" in line 37), but you can hardcode these paths for ("${ocvJarDir}" in line 5 and "${ocvLibDir}" in line 37), but you can hardcode these paths for
your convenience. See [Ant documentation](http://ant.apache.org/manual/) for detailed your convenience. See [Ant documentation](http://ant.apache.org/manual/) for detailed
description of its build file format. description of its build file format.
- Create an `src` folder next to the `build.xml` file and a `SimpleSample.java` file in it. - Create an `src` folder next to the `build.xml` file and a `SimpleSample.java` file in it.
-
Put the following Java code into the `SimpleSample.java` file: - Put the following Java code into the `SimpleSample.java` file:
@code{.java} @code{.java}
import org.opencv.core.Core; import org.opencv.core.Core;
import org.opencv.core.Mat; import org.opencv.core.Mat;
import org.opencv.core.CvType; import org.opencv.core.CvType;
...@@ -175,20 +130,18 @@ folder. \* Create a folder where you'll develop this sample application. ...@@ -175,20 +130,18 @@ folder. \* Create a folder where you'll develop this sample application.
} }
@endcode @endcode
- - Run the following command in console in the folder containing `build.xml`:
@code{.bash}
Run the following command in console in the folder containing `build.xml`: ant -DocvJarDir=path/to/dir/containing/opencv-244.jar -DocvLibDir=path/to/dir/containing/opencv_java244/native/library
@code{.bash} @endcode
ant -DocvJarDir=path/to/dir/containing/opencv-244.jar -DocvLibDir=path/to/dir/containing/opencv_java244/native/library For example:
@endcode @code{.bat}
For example: ant -DocvJarDir=X:\opencv-2.4.4\bin -DocvLibDir=X:\opencv-2.4.4\bin\Release
@code{.bat} @endcode
ant -DocvJarDir=X:\opencv-2.4.4\bin -DocvLibDir=X:\opencv-2.4.4\bin\Release The command should initiate [re]building and running the sample. You should see on the
@endcode screen something like this:
The command should initiate [re]building and running the sample. You should see on the
screen something like this:
![image](images/ant_output.png) ![image](images/ant_output.png)
SBT project for Java and Scala SBT project for Java and Scala
------------------------------ ------------------------------
...@@ -370,4 +323,3 @@ It should also write the following image to `faceDetection.png`: ...@@ -370,4 +323,3 @@ It should also write the following image to `faceDetection.png`:
You're done! Now you have a sample Java application working with OpenCV, so you can start the work You're done! Now you have a sample Java application working with OpenCV, so you can start the work
on your own. We wish you good luck and many years of joyful life! on your own. We wish you good luck and many years of joyful life!
...@@ -12,10 +12,12 @@ Required Packages ...@@ -12,10 +12,12 @@ Required Packages
Launch GIT client and clone OpenCV repository from [here](http://github.com/itseez/opencv) Launch GIT client and clone OpenCV repository from [here](http://github.com/itseez/opencv)
In MacOS it can be done using the following command in Terminal: In MacOS it can be done using the following command in Terminal:
@code{.bash} @code{.bash}
cd ~/<my_working _directory> cd ~/<my_working _directory>
git clone https://github.com/Itseez/opencv.git git clone https://github.com/Itseez/opencv.git
@endcode @endcode
Building OpenCV from Source, using CMake and Command Line Building OpenCV from Source, using CMake and Command Line
--------------------------------------------------------- ---------------------------------------------------------
...@@ -24,11 +26,13 @@ Building OpenCV from Source, using CMake and Command Line ...@@ -24,11 +26,13 @@ Building OpenCV from Source, using CMake and Command Line
cd / cd /
sudo ln -s /Applications/Xcode.app/Contents/Developer Developer sudo ln -s /Applications/Xcode.app/Contents/Developer Developer
@endcode @endcode
2. Build OpenCV framework: 2. Build OpenCV framework:
@code{.bash} @code{.bash}
cd ~/<my_working_directory> cd ~/<my_working_directory>
python opencv/platforms/ios/build_framework.py ios python opencv/platforms/ios/build_framework.py ios
@endcode @endcode
If everything's fine, a few minutes later you will get If everything's fine, a few minutes later you will get
\~/\<my_working_directory\>/ios/opencv2.framework. You can add this framework to your Xcode \~/\<my_working_directory\>/ios/opencv2.framework. You can add this framework to your Xcode
projects. projects.
...@@ -36,5 +40,4 @@ projects. ...@@ -36,5 +40,4 @@ projects.
Further Reading Further Reading
--------------- ---------------
You can find several OpenCV+iOS tutorials here @ref Table-Of-Content-iOS. You can find several OpenCV+iOS tutorials here @ref tutorial_table_of_content_ios.
...@@ -11,7 +11,7 @@ Configuring Eclipse ...@@ -11,7 +11,7 @@ Configuring Eclipse
------------------- -------------------
First, obtain a fresh release of OpenCV [from download page](http://opencv.org/downloads.html) and First, obtain a fresh release of OpenCV [from download page](http://opencv.org/downloads.html) and
extract it under a simple location like C:\\OpenCV-2.4.6\\. I am using version 2.4.6, but the steps extract it under a simple location like `C:\OpenCV-2.4.6\`. I am using version 2.4.6, but the steps
are more or less the same for other versions. are more or less the same for other versions.
Now, we will define OpenCV as a user library in Eclipse, so we can reuse the configuration for any Now, we will define OpenCV as a user library in Eclipse, so we can reuse the configuration for any
...@@ -31,12 +31,12 @@ Now select your new user library and click Add External JARs.... ...@@ -31,12 +31,12 @@ Now select your new user library and click Add External JARs....
![image](images/4-add-external-jars.png) ![image](images/4-add-external-jars.png)
Browse through C:\\OpenCV-2.4.6\\build\\java\\ and select opencv-246.jar. After adding the jar, Browse through `C:\OpenCV-2.4.6\build\java\` and select opencv-246.jar. After adding the jar,
extend the opencv-246.jar and select Native library location and press Edit.... extend the opencv-246.jar and select Native library location and press Edit....
![image](images/5-native-library.png) ![image](images/5-native-library.png)
Select External Folder... and browse to select the folder C:\\OpenCV-2.4.6\\build\\java\\x64. If you Select External Folder... and browse to select the folder `C:\OpenCV-2.4.6\build\java\x64`. If you
have a 32-bit system you need to select the x86 folder instead of x64. have a 32-bit system you need to select the x86 folder instead of x64.
![image](images/6-external-folder.png) ![image](images/6-external-folder.png)
...@@ -86,4 +86,3 @@ When you run the code you should see 3x3 identity matrix as output. ...@@ -86,4 +86,3 @@ When you run the code you should see 3x3 identity matrix as output.
That is it, whenever you start a new project just add the OpenCV user library that you have defined That is it, whenever you start a new project just add the OpenCV user library that you have defined
to your project and you are good to go. Enjoy your powerful, less painful development environment :) to your project and you are good to go. Enjoy your powerful, less painful development environment :)
Using OpenCV with Eclipse (plugin CDT) {#tutorial_linux_eclipse} Using OpenCV with Eclipse (plugin CDT) {#tutorial_linux_eclipse}
====================================== ======================================
@note Two ways, one by forming a project directly, and another by CMake Prerequisites Prerequisites
=============== -------------
Two ways, one by forming a project directly, and another by CMake Prerequisites
1. Having installed [Eclipse](http://www.eclipse.org/) in your workstation (only the CDT plugin for 1. 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: C/C++ is needed). You can follow the following steps:
- Go to the Eclipse site - Go to the Eclipse site
- Download [Eclipse IDE for C/C++ - Download [Eclipse IDE for C/C++
Developers](http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/heliossr2) . Developers](http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/heliossr2) .
Choose the link according to your workstation. Choose the link according to your workstation.
2. Having installed OpenCV. If not yet, go @ref tutorial_linux_install "here".
2. Having installed OpenCV. If not yet, go @ref here \<Linux-Installation\>.
Making a project Making a project
---------------- ----------------
...@@ -75,46 +74,47 @@ Making a project ...@@ -75,46 +74,47 @@ Making a project
- Go to **Project--\>Properties** - Go to **Project--\>Properties**
- In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab. - In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab.
Here we will enter the headers and libraries info: Here we will enter the headers and libraries info:
a. In **GCC C++ Compiler**, go to **Includes**. In **Include paths(-l)** you should -# 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 include the path of the folder where opencv was installed. In our example, this is
/usr/local/include/opencv. /usr/local/include/opencv.
![image](images/a9.png) ![image](images/a9.png)
@note If you do not know where your opencv files are, open the **Terminal** and type:
@code{.bash}
pkg-config --cflags opencv
@endcode
For instance, that command gave me this output:
@code{.bash}
-I/usr/local/include/opencv -I/usr/local/include
@endcode
b. Now go to **GCC C++ Linker**,there you have to fill two spaces:
First in **Library search path (-L)** you have to write the path to where the opencv libraries @note If you do not know where your opencv files are, open the **Terminal** and type:
reside, in my case the path is: : @code{.bash}
pkg-config --cflags opencv
@endcode
For instance, that command gave me this output:
@code{.bash}
-I/usr/local/include/opencv -I/usr/local/include
@endcode
/usr/local/lib -# Now go to **GCC C++ Linker**,there you have to fill two spaces:
Then in **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 3 first First in **Library search path (-L)** you have to write the path to where the opencv libraries
on the list below are enough (for simple applications) . In my case, I am putting all of them reside, in my case the path is: :
since I plan to use the whole bunch:
opencv_core opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_features2d /usr/local/lib
opencv_calib3d opencv_objdetect opencv_contrib opencv_legacy opencv_flann
![image](images/a10.png) Then 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 don't know where your libraries are (or you are just psychotic and want to make sure opencv_core opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_features2d
the path is fine), type in **Terminal**: opencv_calib3d opencv_objdetect opencv_contrib opencv_legacy opencv_flann
@code{.bash}
pkg-config --libs opencv
@endcode
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 ![image](images/a10.png)
Now you are done. Click **OK** 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{.bash}
pkg-config --libs opencv
@endcode
My output (in case you want to check) was:
@code{.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
@endcode
Now you are done. Click **OK**
- Your project should be ready to be built. For this, go to **Project-\>Build all** - Your project should be ready to be built. For this, go to **Project-\>Build all**
...@@ -171,7 +171,7 @@ int main ( int argc, char **argv ) ...@@ -171,7 +171,7 @@ int main ( int argc, char **argv )
} }
@endcode @endcode
1. Create a build directory, say, under *foo*: mkdir /build. Then cd build. 1. Create a build directory, say, under *foo*: mkdir /build. Then cd build.
2. Put a *CmakeLists.txt* file in build: 2. Put a `CmakeLists.txt` file in build:
@code{.bash} @code{.bash}
PROJECT( helloworld_proj ) PROJECT( helloworld_proj )
FIND_PACKAGE( OpenCV REQUIRED ) FIND_PACKAGE( OpenCV REQUIRED )
...@@ -180,21 +180,20 @@ TARGET_LINK_LIBRARIES( helloworld \f${OpenCV_LIBS} ) ...@@ -180,21 +180,20 @@ TARGET_LINK_LIBRARIES( helloworld \f${OpenCV_LIBS} )
@endcode @endcode
1. Run: cmake-gui .. and make sure you fill in where opencv was built. 1. Run: cmake-gui .. and make sure you fill in where opencv was built.
2. Then click configure and then generate. If it's OK, **quit cmake-gui** 2. Then click configure and then generate. If it's OK, **quit cmake-gui**
3. Run make -j4 *(the -j4 is optional, it just tells the compiler to build in 4 threads)*. Make 3. Run `make -j4` (the -j4 is optional, it just tells the compiler to build in 4 threads). Make
sure it builds. sure it builds.
4. Start eclipse . Put the workspace in some directory but **not** in foo or foo\\\\build 4. Start eclipse. Put the workspace in some directory but **not** in foo or `foo\build`
5. Right click in the Project Explorer section. Select Import And then open the C/C++ filter. 5. Right click in the Project Explorer section. Select Import And then open the C/C++ filter.
Choose *Existing Code* as a Makefile Project\`\` Choose *Existing Code* as a Makefile Project.
6. Name your project, say *helloworld*. Browse to the Existing Code location foo\\\\build (where 6. Name your project, say *helloworld*. Browse to the Existing Code location `foo\build` (where
you ran your cmake-gui from). Select *Linux GCC* in the *"Toolchain for Indexer Settings"* and you ran your cmake-gui from). Select *Linux GCC* in the *"Toolchain for Indexer Settings"* and
press *Finish*. press *Finish*.
7. Right click in the Project Explorer section. Select Properties. Under C/C++ Build, set the 7. Right click in the Project Explorer section. Select Properties. Under C/C++ Build, set the
*build directory:* from something like \\f${workspace_loc:/helloworld} to *build directory:* from something like `${workspace_loc:/helloworld}` to
\\f${workspace_loc:/helloworld}/build since that's where you are building to. `${workspace_loc:/helloworld}/build` since that's where you are building to.
a. You can also optionally modify the Build command: from make to something like
make VERBOSE=1 -j4 which tells the compiler to produce detailed symbol files for debugging and
also to compile in 4 parallel threads.
1. Done! -# You can also optionally modify the Build command: from make to something like
`make VERBOSE=1 -j4` which tells the compiler to produce detailed symbol files for debugging and
also to compile in 4 parallel threads.
8. Done!
...@@ -127,10 +127,9 @@ Building OpenCV from Source Using CMake ...@@ -127,10 +127,9 @@ Building OpenCV from Source Using CMake
@code{.bash} @code{.bash}
<cmake_build_dir>/bin/opencv_test_core <cmake_build_dir>/bin/opencv_test_core
@endcode @endcode
@note @note
If the size of the created library is a critical issue (like in case of an Android build) you If the size of the created library is a critical issue (like in case of an Android build) you
can use the install/strip command to get the smallest size as possible. The *stripped* version can use the install/strip command to get the smallest size as possible. The *stripped* version
appears to be twice as small. However, we do not recommend using this unless those extra appears to be twice as small. However, we do not recommend using this unless those extra
megabytes do really matter. megabytes do really matter.
...@@ -3,7 +3,7 @@ Load, Modify, and Save an Image {#tutorial_load_save_image} ...@@ -3,7 +3,7 @@ Load, Modify, and Save an Image {#tutorial_load_save_image}
@note @note
We assume that by now you know how to load an image using @ref cv::imread and to display it in a We assume that by now you know how to load an image using @ref cv::imread and to display it in a
window (using @ref cv::imshow ). Read the @ref Display_Image tutorial otherwise. window (using @ref cv::imshow ). Read the @ref tutorial_display_image tutorial otherwise.
Goals Goals
----- -----
...@@ -103,4 +103,3 @@ And if you check in your folder (in my case *images*), you should have a newly . ...@@ -103,4 +103,3 @@ And if you check in your folder (in my case *images*), you should have a newly .
![image](images/Load_Save_Image_Result_2.jpg) ![image](images/Load_Save_Image_Result_2.jpg)
Congratulations, you are done with this tutorial! Congratulations, you are done with this tutorial!
How to build applications with OpenCV inside the *Microsoft Visual Studio* {#tutorial_windows_visual_studio_Opencv} How to build applications with OpenCV inside the "Microsoft Visual Studio" {#tutorial_windows_visual_studio_Opencv}
========================================================================== ==========================================================================
Everything I describe here will apply to the C\\C++ interface of OpenCV. I start out from the Everything I describe here will apply to the C\\C++ interface of OpenCV. I start out from the
assumption that you have read and completed with success the @ref Windows_Installation tutorial. assumption that you have read and completed with success the @ref tutorial_windows_install tutorial.
Therefore, before you go any further make sure you have an OpenCV directory that contains the OpenCV Therefore, before you go any further make sure you have an OpenCV directory that contains the OpenCV
header files plus binaries and you have set the environment variables as @ref described here header files plus binaries and you have set the environment variables as described here
\<WindowsSetPathAndEnviromentVariable\>. @ref tutorial_windows_install_path.
![image](images/OpenCV_Install_Directory.jpg) ![image](images/OpenCV_Install_Directory.jpg)
The OpenCV libraries, distributed by us, on the Microsoft Windows operating system are in a The OpenCV libraries, distributed by us, on the Microsoft Windows operating system are in a
**D**ynamic **L**inked **L**ibraries (*DLL*). These have the advantage that all the content of the Dynamic Linked Libraries (*DLL*). These have the advantage that all the content of the
library are loaded only at runtime, on demand, and that countless programs may use the same library library are loaded only at runtime, on demand, and that countless programs may use the same library
file. This means that if you have ten applications using the OpenCV library, no need to have around file. This means that if you have ten applications using the OpenCV library, no need to have around
a version for each one of them. Of course you need to have the *dll* of the OpenCV on all systems a version for each one of them. Of course you need to have the *dll* of the OpenCV on all systems
where you want to run your application. where you want to run your application.
Another approach is to use static libraries that have *lib* extensions. You may build these by using Another approach is to use static libraries that have *lib* extensions. You may build these by using
our source files as described in the @ref Windows_Installation tutorial. When you use this the our source files as described in the @ref tutorial_windows_install tutorial. When you use this the
library will be built-in inside your *exe* file. So there is no chance that the user deletes them, library will be built-in inside your *exe* file. So there is no chance that the user deletes them,
for some reason. As a drawback your application will be larger one and as, it will take more time to for some reason. As a drawback your application will be larger one and as, it will take more time to
load it during its startup. load it during its startup.
...@@ -103,13 +103,14 @@ further to someone else who has a different OpenCV install path. Moreover, fixin ...@@ -103,13 +103,14 @@ further to someone else who has a different OpenCV install path. Moreover, fixin
to manually modifying every explicit path. A more elegant solution is to use the environment to manually modifying every explicit path. A more elegant solution is to use the environment
variables. Anything that you put inside a parenthesis started with a dollar sign will be replaced at variables. Anything that you put inside a parenthesis started with a dollar sign will be replaced at
runtime with the current environment variables value. Here comes in play the environment variable runtime with the current environment variables value. Here comes in play the environment variable
setting we already made in our @ref previous tutorial \<WindowsSetPathAndEnviromentVariable\>. setting we already made in our previous tutorial @ref tutorial_windows_install_path.
Next go to the Linker --\> General and under the *"Additional Library Directories"* add the libs Next go to the Linker --\> General and under the *"Additional Library Directories"* add the libs
directory: directory:
@code{.bash} @code{.bash}
\f$(OPENCV_DIR)\lib $(OPENCV_DIR)\lib
@endcode @endcode
![image](images/PropertySheetOpenCVLib.jpg) ![image](images/PropertySheetOpenCVLib.jpg)
Then you need to specify the libraries in which the linker should look into. To do this go to the Then you need to specify the libraries in which the linker should look into. To do this go to the
...@@ -233,5 +234,4 @@ cumbersome task. Luckily, in the Visual Studio there is a menu to automate all t ...@@ -233,5 +234,4 @@ cumbersome task. Luckily, in the Visual Studio there is a menu to automate all t
Specify here the name of the inputs and while you start your application from the Visual Studio Specify here the name of the inputs and while you start your application from the Visual Studio
enviroment you have automatic argument passing. In the next introductionary tutorial you'll see an enviroment you have automatic argument passing. In the next introductionary tutorial you'll see an
in-depth explanation of the upper source code: @ref Display_Image. in-depth explanation of the upper source code: @ref tutorial_display_image.
...@@ -12,9 +12,8 @@ This tutorial assumes that you have the following available: ...@@ -12,9 +12,8 @@ This tutorial assumes that you have the following available:
1. Visual Studio 2012 Professional (or better) with Update 1 installed. Update 1 can be downloaded 1. Visual Studio 2012 Professional (or better) with Update 1 installed. Update 1 can be downloaded
[here](http://www.microsoft.com/en-us/download/details.aspx?id=35774). [here](http://www.microsoft.com/en-us/download/details.aspx?id=35774).
2. An OpenCV installation on your Windows machine (Tutorial: @ref Windows_Installation). 2. An OpenCV installation on your Windows machine (Tutorial: @ref tutorial_windows_install).
3. Ability to create and build OpenCV projects in Visual Studio (Tutorial: @ref 3. Ability to create and build OpenCV projects in Visual Studio (Tutorial: @ref tutorial_windows_visual_studio_Opencv).
Windows_Visual_Studio_How_To).
Installation Installation
------------ ------------
...@@ -178,4 +177,3 @@ Documentation](http://go.microsoft.com/fwlink/?LinkId=285461) for details--you a ...@@ -178,4 +177,3 @@ Documentation](http://go.microsoft.com/fwlink/?LinkId=285461) for details--you a
documentation page by clicking on the *Help* link in the Image Watch window: documentation page by clicking on the *Help* link in the Image Watch window:
![image](images/help_button.jpg) ![image](images/help_button.jpg)
...@@ -15,7 +15,7 @@ Including OpenCV library in your iOS project ...@@ -15,7 +15,7 @@ Including OpenCV library in your iOS project
The OpenCV library comes as a so-called framework, which you can directly drag-and-drop into your The OpenCV library comes as a so-called framework, which you can directly drag-and-drop into your
XCode project. Download the latest binary from XCode project. Download the latest binary from
\<<http://sourceforge.net/projects/opencvlibrary/files/opencv-ios/>\>. Alternatively follow this \<<http://sourceforge.net/projects/opencvlibrary/files/opencv-ios/>\>. Alternatively follow this
guide @ref iOS-Installation to compile the framework manually. Once you have the framework, just guide @ref tutorial_ios_install to compile the framework manually. Once you have the framework, just
drag-and-drop into XCode: drag-and-drop into XCode:
![image](images/xcode_hello_ios_framework_drag_and_drop.png) ![image](images/xcode_hello_ios_framework_drag_and_drop.png)
...@@ -203,4 +203,3 @@ When you are working on grayscale data, turn set grayscale = YES as the YUV colo ...@@ -203,4 +203,3 @@ When you are working on grayscale data, turn set grayscale = YES as the YUV colo
directly access the luminance plane. directly access the luminance plane.
The Accelerate framework provides some CPU-accelerated DSP filters, which come handy in your case. The Accelerate framework provides some CPU-accelerated DSP filters, which come handy in your case.
Introduction to Support Vector Machines {#tutorial_introduction_to_svm} Introduction to Support Vector Machines {#tutorial_introduction_to_svm}
======================================= =======================================
@todo update this tutorial
Goal Goal
---- ----
In this tutorial you will learn how to: In this tutorial you will learn how to:
- Use the OpenCV functions @ref cv::CvSVM::train to build a classifier based on SVMs and @ref - Use the OpenCV functions @ref cv::ml::SVM::train to build a classifier based on SVMs and @ref
cv::CvSVM::predict to test its performance. cv::ml::SVM::predict to test its performance.
What is a SVM? What is a SVM?
-------------- --------------
...@@ -47,7 +49,7 @@ How is the optimal hyperplane computed? ...@@ -47,7 +49,7 @@ How is the optimal hyperplane computed?
Let's introduce the notation used to define formally a hyperplane: Let's introduce the notation used to define formally a hyperplane:
f(x) = beta_{0} + beta\^{T} x, \f[f(x) = \beta_{0} + \beta^{T} x,\f]
where \f$\beta\f$ is known as the *weight vector* and \f$\beta_{0}\f$ as the *bias*. where \f$\beta\f$ is known as the *weight vector* and \f$\beta_{0}\f$ as the *bias*.
...@@ -57,7 +59,7 @@ Friedman. The optimal hyperplane can be represented in an infinite number of dif ...@@ -57,7 +59,7 @@ Friedman. The optimal hyperplane can be represented in an infinite number of dif
scaling of \f$\beta\f$ and \f$\beta_{0}\f$. As a matter of convention, among all the possible scaling of \f$\beta\f$ and \f$\beta_{0}\f$. As a matter of convention, among all the possible
representations of the hyperplane, the one chosen is representations of the hyperplane, the one chosen is
|beta_{0} + beta\^{T} x| = 1 \f[|\beta_{0} + \beta^{T} x| = 1\f]
where \f$x\f$ symbolizes the training examples closest to the hyperplane. In general, the training where \f$x\f$ symbolizes the training examples closest to the hyperplane. In general, the training
examples that are closest to the hyperplane are called **support vectors**. This representation is examples that are closest to the hyperplane are called **support vectors**. This representation is
...@@ -71,20 +73,18 @@ Now, we use the result of geometry that gives the distance between a point \f$x\ ...@@ -71,20 +73,18 @@ Now, we use the result of geometry that gives the distance between a point \f$x\
In particular, for the canonical hyperplane, the numerator is equal to one and the distance to the In particular, for the canonical hyperplane, the numerator is equal to one and the distance to the
support vectors is support vectors is
mathrm{distance}_{text{ support vectors}} = frac{|beta_{0} + beta\^{T} x|}{||beta||} = \f[\mathrm{distance}_{\text{ support vectors}} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||} = \frac{1}{||\beta||}.\f]
frac{1}{||beta||}.
Recall that the margin introduced in the previous section, here denoted as \f$M\f$, is twice the Recall that the margin introduced in the previous section, here denoted as \f$M\f$, is twice the
distance to the closest examples: distance to the closest examples:
M = frac{2}{||beta||} \f[M = \frac{2}{||\beta||}\f]
Finally, the problem of maximizing \f$M\f$ is equivalent to the problem of minimizing a function Finally, the problem of maximizing \f$M\f$ is equivalent to the problem of minimizing a function
\f$L(\beta)\f$ subject to some constraints. The constraints model the requirement for the hyperplane to \f$L(\beta)\f$ subject to some constraints. The constraints model the requirement for the hyperplane to
classify correctly all the training examples \f$x_{i}\f$. Formally, classify correctly all the training examples \f$x_{i}\f$. Formally,
min_{beta, beta_{0}} L(beta) = frac{1}{2}||beta||\^{2} text{ subject to } y_{i}(beta\^{T} \f[\min_{\beta, \beta_{0}} L(\beta) = \frac{1}{2}||\beta||^{2} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 \text{ } \forall i,\f]
x_{i} + beta_{0}) geq 1 text{ } forall i,
where \f$y_{i}\f$ represents each of the labels of the training examples. where \f$y_{i}\f$ represents each of the labels of the training examples.
...@@ -101,19 +101,20 @@ Explanation ...@@ -101,19 +101,20 @@ Explanation
1. **Set up the training data** 1. **Set up the training data**
The training data of this exercise is formed by a set of labeled 2D-points that belong to one of The training data of this exercise is formed by a set of labeled 2D-points that belong to one of
two different classes; one of the classes consists of one point and the other of three points. two different classes; one of the classes consists of one point and the other of three points.
@code{.cpp} @code{.cpp}
float labels[4] = {1.0, -1.0, -1.0, -1.0}; float labels[4] = {1.0, -1.0, -1.0, -1.0};
float trainingData[4][2] = {{501, 10}, {255, 10}, {501, 255}, {10, 501}}; float trainingData[4][2] = {{501, 10}, {255, 10}, {501, 255}, {10, 501}};
@endcode @endcode
The function @ref cv::CvSVM::train that will be used afterwards requires the training data to be The function @ref cv::ml::SVM::train that will be used afterwards requires the training data to be
stored as @ref cv::Mat objects of floats. Therefore, we create these objects from the arrays stored as @ref cv::Mat objects of floats. Therefore, we create these objects from the arrays
defined above: defined above:
@code{.cpp} @code{.cpp}
Mat trainingDataMat(4, 2, CV_32FC1, trainingData); Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
Mat labelsMat (4, 1, CV_32FC1, labels); Mat labelsMat (4, 1, CV_32FC1, labels);
@endcode @endcode
2. **Set up SVM's parameters** 2. **Set up SVM's parameters**
In this tutorial we have introduced the theory of SVMs in the most simple case, when the In this tutorial we have introduced the theory of SVMs in the most simple case, when the
...@@ -121,7 +122,7 @@ Mat labelsMat (4, 1, CV_32FC1, labels); ...@@ -121,7 +122,7 @@ Mat labelsMat (4, 1, CV_32FC1, labels);
used in a wide variety of problems (e.g. problems with non-linearly separable data, a SVM using used in a wide variety of problems (e.g. problems with non-linearly separable data, a SVM using
a kernel function to raise the dimensionality of the examples, etc). As a consequence of this, a kernel function to raise the dimensionality of the examples, etc). As a consequence of this,
we have to define some parameters before training the SVM. These parameters are stored in an we have to define some parameters before training the SVM. These parameters are stored in an
object of the class @ref cv::CvSVMParams . object of the class @ref cv::ml::SVM::Params .
@code{.cpp} @code{.cpp}
ml::SVM::Params params; ml::SVM::Params params;
params.svmType = ml::SVM::C_SVC; params.svmType = ml::SVM::C_SVC;
...@@ -132,14 +133,16 @@ Mat labelsMat (4, 1, CV_32FC1, labels); ...@@ -132,14 +133,16 @@ Mat labelsMat (4, 1, CV_32FC1, labels);
classification (n \f$\geq\f$ 2). This parameter is defined in the attribute classification (n \f$\geq\f$ 2). This parameter is defined in the attribute
*ml::SVM::Params.svmType*. *ml::SVM::Params.svmType*.
@note The important feature of the type of SVM **CvSVM::C_SVC** deals with imperfect separation of classes (i.e. when the training data is non-linearly separable). This feature is not important here since the data is linearly separable and we chose this SVM type only for being the most commonly used. The important feature of the type of SVM **CvSVM::C_SVC** deals with imperfect separation of classes (i.e. when the training data is non-linearly separable). This feature is not important here since the data is linearly separable and we chose this SVM type only for being the most commonly used.
- *Type of SVM kernel*. We have not talked about kernel functions since they are not
- *Type of SVM kernel*. We have not talked about kernel functions since they are not
interesting for the training data we are dealing with. Nevertheless, let's explain briefly interesting for the training data we are dealing with. Nevertheless, let's explain briefly
now the main idea behind a kernel function. It is a mapping done to the training data to now the main idea behind a kernel function. It is a mapping done to the training data to
improve its resemblance to a linearly separable set of data. This mapping consists of improve its resemblance to a linearly separable set of data. This mapping consists of
increasing the dimensionality of the data and is done efficiently using a kernel function. increasing the dimensionality of the data and is done efficiently using a kernel function.
We choose here the type **ml::SVM::LINEAR** which means that no mapping is done. This We choose here the type **ml::SVM::LINEAR** which means that no mapping is done. This
parameter is defined in the attribute *ml::SVMParams.kernel_type*. parameter is defined in the attribute *ml::SVMParams.kernel_type*.
- *Termination criteria of the algorithm*. The SVM training procedure is implemented solving a - *Termination criteria of the algorithm*. The SVM training procedure is implemented solving a
constrained quadratic optimization problem in an **iterative** fashion. Here we specify a constrained quadratic optimization problem in an **iterative** fashion. Here we specify a
maximum number of iterations and a tolerance error so we allow the algorithm to finish in maximum number of iterations and a tolerance error so we allow the algorithm to finish in
...@@ -155,35 +158,36 @@ Mat labelsMat (4, 1, CV_32FC1, labels); ...@@ -155,35 +158,36 @@ Mat labelsMat (4, 1, CV_32FC1, labels);
CvSVM SVM; CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params); SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
@endcode @endcode
4. **Regions classified by the SVM** 4. **Regions classified by the SVM**
The method @ref cv::CvSVM::predict is used to classify an input sample using a trained SVM. In The method @ref cv::ml::SVM::predict is used to classify an input sample using a trained SVM. In
this example we have used this method in order to color the space depending on the prediction done this example we have used this method in order to color the space depending on the prediction done
by the SVM. In other words, an image is traversed interpreting its pixels as points of the by the SVM. In other words, an image is traversed interpreting its pixels as points of the
Cartesian plane. Each of the points is colored depending on the class predicted by the SVM; in Cartesian plane. Each of the points is colored depending on the class predicted by the SVM; in
green if it is the class with label 1 and in blue if it is the class with label -1. green if it is the class with label 1 and in blue if it is the class with label -1.
@code{.cpp} @code{.cpp}
Vec3b green(0,255,0), blue (255,0,0); Vec3b green(0,255,0), blue (255,0,0);
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1,2) << i,j);
float response = SVM.predict(sampleMat);
if (response == 1)
image.at<Vec3b>(j, i) = green;
else
if (response == -1)
image.at<Vec3b>(j, i) = blue;
}
@endcode
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1,2) << i,j);
float response = SVM.predict(sampleMat);
if (response == 1)
image.at<Vec3b>(j, i) = green;
else
if (response == -1)
image.at<Vec3b>(j, i) = blue;
}
@endcode
5. **Support vectors** 5. **Support vectors**
We use here a couple of methods to obtain information about the support vectors. The method @ref We use here a couple of methods to obtain information about the support vectors.
cv::CvSVM::get_support_vector_count outputs the total number of support vectors used in the The method @ref cv::ml::SVM::getSupportVectors obtain all of the support
problem and with the method @ref cv::CvSVM::get_support_vector we obtain each of the support vectors. We have used this methods here to find the training examples that are
vectors using an index. We have used this methods here to find the training examples that are
support vectors and highlight them. support vectors and highlight them.
@code{.cpp} @code{.cpp}
int c = SVM.get_support_vector_count(); int c = SVM.get_support_vector_count();
...@@ -194,6 +198,7 @@ for (int i = 0; i < image.rows; ++i) ...@@ -194,6 +198,7 @@ for (int i = 0; i < image.rows; ++i)
circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType); circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
} }
@endcode @endcode
Results Results
------- -------
...@@ -204,5 +209,4 @@ Results ...@@ -204,5 +209,4 @@ Results
optimal separating hyperplane. optimal separating hyperplane.
- Finally the support vectors are shown using gray rings around the training examples. - Finally the support vectors are shown using gray rings around the training examples.
![image](images/result.png) ![image](images/svm_intro_result.png)
...@@ -182,6 +182,6 @@ Results ...@@ -182,6 +182,6 @@ Results
* Finally the support vectors are shown using gray rings around the training examples. * Finally the support vectors are shown using gray rings around the training examples.
.. image:: images/result.png .. image:: images/svm_intro_result.png
:alt: The seperated planes :alt: The seperated planes
:align: center :align: center
...@@ -218,7 +218,7 @@ Results ...@@ -218,7 +218,7 @@ Results
* Finally the support vectors are shown using gray rings around the training examples. * Finally the support vectors are shown using gray rings around the training examples.
.. image:: images/result.png .. image:: images/svm_non_linear_result.png
:alt: Training data and decision regions given by the SVM :alt: Training data and decision regions given by the SVM
:width: 300pt :width: 300pt
:align: center :align: center
......
...@@ -8,8 +8,8 @@ In this tutorial you will learn how to: ...@@ -8,8 +8,8 @@ In this tutorial you will learn how to:
- Use the @ref cv::CascadeClassifier class to detect objects in a video stream. Particularly, we - Use the @ref cv::CascadeClassifier class to detect objects in a video stream. Particularly, we
will use the functions: will use the functions:
- @ref cv::load to load a .xml classifier file. It can be either a Haar or a LBP classifer - @ref cv::CascadeClassifier::load to load a .xml classifier file. It can be either a Haar or a LBP classifer
- @ref cv::detectMultiScale to perform the detection. - @ref cv::CascadeClassifier::detectMultiScale to perform the detection.
Theory Theory
------ ------
...@@ -126,5 +126,3 @@ Result ...@@ -126,5 +126,3 @@ Result
detection. For the eyes we keep using the file used in the tutorial. detection. For the eyes we keep using the file used in the tutorial.
![image](images/Cascade_Classifier_Tutorial_Result_LBP.jpg) ![image](images/Cascade_Classifier_Tutorial_Result_LBP.jpg)
...@@ -40,11 +40,11 @@ Code ...@@ -40,11 +40,11 @@ Code
In the following you can find the source code. We will let the user chose to process either a video In the following you can find the source code. We will let the user chose to process either a video
file or a sequence of images. file or a sequence of images.
- -
Two different methods are used to generate two foreground masks: Two different methods are used to generate two foreground masks:
1. @ref cv::MOG 1. @ref cv::bgsegm::BackgroundSubtractorMOG
2. @ref cv::MOG2 2. @ref cv::bgsegm::BackgroundSubtractorMOG2
The results as well as the input data are shown on the screen. The results as well as the input data are shown on the screen.
@code{.cpp} @code{.cpp}
...@@ -389,4 +389,3 @@ References ...@@ -389,4 +389,3 @@ References
- Antoine Vacavant, Thierry Chateau, Alexis Wilhelm and Laurent Lequievre. A Benchmark Dataset for - Antoine Vacavant, Thierry Chateau, Alexis Wilhelm and Laurent Lequievre. A Benchmark Dataset for
Foreground/Background Extraction. In ACCV 2012, Workshop: Background Models Challenge, LNCS Foreground/Background Extraction. In ACCV 2012, Workshop: Background Models Challenge, LNCS
7728, 291-300. November 2012, Daejeon, Korea. 7728, 291-300. November 2012, Daejeon, Korea.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment