Doxygen tutorials: cpp done

This commit is contained in:
Maksim Shabunin
2014-11-28 16:21:28 +03:00
parent c5536534d8
commit 36a04ef8de
92 changed files with 2142 additions and 3691 deletions

View File

@@ -28,17 +28,14 @@ Theory
- Let's say you have gotten a skin histogram (Hue-Saturation) based on the image below. The
histogram besides is going to be our *model histogram* (which we know represents a sample of
skin tonality). You applied some mask to capture only the histogram of the skin area:
------ ------
|T0| |T1|
------ ------
![T0](images/Back_Projection_Theory0.jpg)
![T1](images/Back_Projection_Theory1.jpg)
- Now, let's imagine that you get another hand image (Test Image) like the one below: (with its
respective histogram):
![T2](images/Back_Projection_Theory2.jpg)
![T3](images/Back_Projection_Theory3.jpg)
------ ------
|T2| |T3|
------ ------
- 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
@@ -50,7 +47,7 @@ Theory
the *model histogram* first, so the output for the Test Image can be visible for you.
-# Applying the steps above, we get the following BackProjection image for our Test Image:
![image](images/Back_Projection_Theory4.jpg)
![](images/Back_Projection_Theory4.jpg)
-# 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
@@ -83,98 +80,23 @@ Code
in samples.
- **Code at glance:**
@code{.cpp}
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
@includelineno samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp
#include <iostream>
using namespace cv;
using namespace std;
/// Global Variables
Mat src; Mat hsv; Mat hue;
int bins = 25;
/// Function Headers
void Hist_and_Backproj(int, void* );
/* @function main */
int main( int argc, char** argv )
{
/// Read the image
src = imread( argv[1], 1 );
/// Transform it to HSV
cvtColor( src, hsv, COLOR_BGR2HSV );
/// Use only the Hue value
hue.create( hsv.size(), hsv.depth() );
int ch[] = { 0, 0 };
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
/// Create Trackbar to enter the number of bins
char* window_image = "Source image";
namedWindow( window_image, WINDOW_AUTOSIZE );
createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj );
Hist_and_Backproj(0, 0);
/// Show the image
imshow( window_image, src );
/// Wait until user exits the program
waitKey(0);
return 0;
}
/*
* @function Hist_and_Backproj
* @brief Callback to Trackbar
*/
void Hist_and_Backproj(int, void* )
{
MatND hist;
int histSize = MAX( bins, 2 );
float hue_range[] = { 0, 180 };
const float* ranges = { hue_range };
/// Get the Histogram and normalize it
calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false );
normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );
/// Get Backprojection
MatND backproj;
calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true );
/// Draw the backproj
imshow( "BackProj", backproj );
/// Draw the histogram
int w = 400; int h = 400;
int bin_w = cvRound( (double) w / histSize );
Mat histImg = Mat::zeros( w, h, CV_8UC3 );
for( int i = 0; i < bins; i ++ )
{ rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at<float>(i)*h/255.0 ) ), Scalar( 0, 0, 255 ), -1 ); }
imshow( "Histogram", histImg );
}
@endcode
Explanation
-----------
1. Declare the matrices to store our images and initialize the number of bins to be used by our
-# Declare the matrices to store our images and initialize the number of bins to be used by our
histogram:
@code{.cpp}
Mat src; Mat hsv; Mat hue;
int bins = 25;
@endcode
2. Read the input image and transform it to HSV format:
-# Read the input image and transform it to HSV format:
@code{.cpp}
src = imread( argv[1], 1 );
cvtColor( src, hsv, COLOR_BGR2HSV );
@endcode
3. For this tutorial, we will use only the Hue value for our 1-D histogram (check out the fancier
-# For this tutorial, we will use only the Hue value for our 1-D histogram (check out the fancier
code in the links above if you want to use the more standard H-S histogram, which yields better
results):
@code{.cpp}
@@ -182,7 +104,7 @@ Explanation
int ch[] = { 0, 0 };
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
@endcode
as you see, we use the function :mix_channels:mixChannels to get only the channel 0 (Hue) from
as you see, we use the function @ref cv::mixChannels to get only the channel 0 (Hue) from
the hsv image. It gets the following parameters:
- **&hsv:** The source array from which the channels will be copied
@@ -193,7 +115,7 @@ Explanation
case, the Hue(0) channel of &hsv is being copied to the 0 channel of &hue (1-channel)
- **1:** Number of index pairs
4. Create a Trackbar for the user to enter the bin values. Any change on the Trackbar means a call
-# Create a Trackbar for the user to enter the bin values. Any change on the Trackbar means a call
to the **Hist_and_Backproj** callback function.
@code{.cpp}
char* window_image = "Source image";
@@ -201,14 +123,14 @@ Explanation
createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj );
Hist_and_Backproj(0, 0);
@endcode
5. Show the image and wait for the user to exit the program:
-# Show the image and wait for the user to exit the program:
@code{.cpp}
imshow( window_image, src );
waitKey(0);
return 0;
@endcode
6. **Hist_and_Backproj function:** Initialize the arguments needed for @ref cv::calcHist . The
-# **Hist_and_Backproj function:** Initialize the arguments needed for @ref cv::calcHist . The
number of bins comes from the Trackbar:
@code{.cpp}
void Hist_and_Backproj(int, void* )
@@ -218,12 +140,12 @@ Explanation
float hue_range[] = { 0, 180 };
const float* ranges = { hue_range };
@endcode
7. Calculate the Histogram and normalize it to the range \f$[0,255]\f$
-# Calculate the Histogram and normalize it to the range \f$[0,255]\f$
@code{.cpp}
calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false );
normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );
@endcode
8. Get the Backprojection of the same image by calling the function @ref cv::calcBackProject
-# Get the Backprojection of the same image by calling the function @ref cv::calcBackProject
@code{.cpp}
MatND backproj;
calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true );
@@ -231,11 +153,11 @@ Explanation
all the arguments are known (the same as used to calculate the histogram), only we add the
backproj matrix, which will store the backprojection of the source image (&hue)
9. Display backproj:
-# Display backproj:
@code{.cpp}
imshow( "BackProj", backproj );
@endcode
10. Draw the 1-D Hue histogram of the image:
-# Draw the 1-D Hue histogram of the image:
@code{.cpp}
int w = 400; int h = 400;
int bin_w = cvRound( (double) w / histSize );
@@ -246,12 +168,12 @@ Explanation
imshow( "Histogram", histImg );
@endcode
Results
-------
1. Here are the output by using a sample image ( guess what? Another hand ). You can play with the
bin values and you will observe how it affects the results:
------ ------ ------
|R0| |R1| |R2|
------ ------ ------
Here are the output by using a sample image ( guess what? Another hand ). You can play with the
bin values and you will observe how it affects the results:
![R0](images/Back_Projection1_Source_Image.jpg)
![R1](images/Back_Projection1_Histogram.jpg)
![R2](images/Back_Projection1_BackProj.jpg)

View File

@@ -21,7 +21,7 @@ histogram called *Image histogram*. Now we will considerate it in its more gener
- Let's see an example. Imagine that a Matrix contains information of an image (i.e. intensity in
the range \f$0-255\f$):
![image](images/Histogram_Calculation_Theory_Hist0.jpg)
![](images/Histogram_Calculation_Theory_Hist0.jpg)
- What happens if we want to *count* this data in an organized way? Since we know that the *range*
of information value for this case is 256 values, we can segment our range in subparts (called
@@ -36,7 +36,7 @@ histogram called *Image histogram*. Now we will considerate it in its more gener
this to the example above we get the image below ( axis x represents the bins and axis y the
number of pixels in each of them).
![image](images/Histogram_Calculation_Theory_Hist1.jpg)
![](images/Histogram_Calculation_Theory_Hist1.jpg)
- This was just a simple example of how an histogram works and why it is useful. An histogram can
keep count not only of color intensities, but of whatever image features that we want to measure
@@ -73,18 +73,18 @@ Code
Explanation
-----------
1. Create the necessary matrices:
-# Create the necessary matrices:
@code{.cpp}
Mat src, dst;
@endcode
2. Load the source image
-# Load the source image
@code{.cpp}
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
@endcode
3. Separate the source image in its three R,G and B planes. For this we use the OpenCV function
-# Separate the source image in its three R,G and B planes. For this we use the OpenCV function
@ref cv::split :
@code{.cpp}
vector<Mat> bgr_planes;
@@ -93,7 +93,7 @@ Explanation
our input is the image to be divided (this case with three channels) and the output is a vector
of Mat )
4. Now we are ready to start configuring the **histograms** for each plane. Since we are working
-# 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$
-# Establish number of bins (5, 10...):
@code{.cpp}
@@ -137,7 +137,7 @@ Explanation
- **uniform** and **accumulate**: The bin sizes are the same and the histogram is cleared
at the beginning.
5. Create an image to display the histograms:
-# Create an image to display the histograms:
@code{.cpp}
// Draw the histograms for R, G and B
int hist_w = 512; int hist_h = 400;
@@ -145,7 +145,7 @@ Explanation
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
@endcode
6. Notice that before drawing, we first @ref cv::normalize the histogram so its values fall in the
-# Notice that before drawing, we first @ref cv::normalize the histogram so its values fall in the
range indicated by the parameters entered:
@code{.cpp}
/// Normalize the result to [ 0, histImage.rows ]
@@ -164,7 +164,7 @@ Explanation
- **-1:** Implies that the output normalized array will be the same type as the input
- **Mat():** Optional mask
7. Finally, observe that to access the bin (in this case in this 1D-Histogram):
-# Finally, observe that to access the bin (in this case in this 1D-Histogram):
@code{.cpp}
/// Draw for each channel
for( int i = 1; i < histSize; i++ )
@@ -189,7 +189,7 @@ Explanation
b_hist.at<float>( i, j )
@endcode
8. Finally we display our histograms and wait for the user to exit:
-# Finally we display our histograms and wait for the user to exit:
@code{.cpp}
namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
imshow("calcHist Demo", histImage );
@@ -202,10 +202,10 @@ Explanation
Result
------
1. Using as input argument an image like the shown below:
-# Using as input argument an image like the shown below:
![image](images/Histogram_Calculation_Original_Image.jpg)
![](images/Histogram_Calculation_Original_Image.jpg)
2. Produces the following histogram:
-# Produces the following histogram:
![image](images/Histogram_Calculation_Result.jpg)
![](images/Histogram_Calculation_Result.jpg)

View File

@@ -18,25 +18,18 @@ Theory
- OpenCV implements the function @ref cv::compareHist to perform a comparison. It also offers 4
different metrics to compute the matching:
-# **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]
where
\f[\bar{H_k} = \frac{1}{N} \sum _J H_k(J)\f]
and \f$N\f$ is the total number of histogram bins.
-# **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]
-# **Intersection ( method=CV_COMP_INTERSECT )**
\f[d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))\f]
-# **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]
Code
@@ -59,7 +52,7 @@ Code
Explanation
-----------
1. Declare variables such as the matrices to store the base image and the two other images to
-# Declare variables such as the matrices to store the base image and the two other images to
compare ( RGB and HSV )
@code{.cpp}
Mat src_base, hsv_base;
@@ -67,7 +60,7 @@ Explanation
Mat src_test2, hsv_test2;
Mat hsv_half_down;
@endcode
2. Load the base image (src_base) and the other two test images:
-# Load the base image (src_base) and the other two test images:
@code{.cpp}
if( argc < 4 )
{ printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");
@@ -78,17 +71,17 @@ Explanation
src_test1 = imread( argv[2], 1 );
src_test2 = imread( argv[3], 1 );
@endcode
3. Convert them to HSV format:
-# Convert them to HSV format:
@code{.cpp}
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV );
@endcode
4. Also, create an image of half the base image (in HSV format):
-# Also, create an image of half the base image (in HSV format):
@code{.cpp}
hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
@endcode
5. Initialize the arguments to calculate the histograms (bins, ranges and channels H and S ).
-# Initialize the arguments to calculate the histograms (bins, ranges and channels H and S ).
@code{.cpp}
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins, s_bins };
@@ -100,14 +93,14 @@ Explanation
int channels[] = { 0, 1 };
@endcode
6. Create the MatND objects to store the histograms:
-# Create the MatND objects to store the histograms:
@code{.cpp}
MatND hist_base;
MatND hist_half_down;
MatND hist_test1;
MatND hist_test2;
@endcode
7. Calculate the Histograms for the base image, the 2 test images and the half-down base image:
-# Calculate the Histograms for the base image, the 2 test images and the half-down base image:
@code{.cpp}
calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );
normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() );
@@ -121,7 +114,7 @@ Explanation
calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false );
normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() );
@endcode
8. Apply sequentially the 4 comparison methods between the histogram of the base image (hist_base)
-# Apply sequentially the 4 comparison methods between the histogram of the base image (hist_base)
and the other histograms:
@code{.cpp}
for( int i = 0; i < 4; i++ )
@@ -134,34 +127,32 @@ Explanation
printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 );
}
@endcode
Results
-------
1. We use as input the following images:
----------- ----------- -----------
|Base_0| |Test_1| |Test_2|
----------- ----------- -----------
-# We use as input the following images:
![Base_0](images/Histogram_Comparison_Source_0.jpg)
![Test_1](images/Histogram_Comparison_Source_1.jpg)
![Test_2](images/Histogram_Comparison_Source_2.jpg)
where the first one is the base (to be compared to the others), the other 2 are the test images.
We will also compare the first image with respect to itself and with respect of half the base
image.
2. We should expect a perfect match when we compare the base image histogram with itself. Also,
-# We should expect a perfect match when we compare the base image histogram with itself. Also,
compared with the histogram of half the base image, it should present a high match since both
are from the same source. For the other two test images, we can observe that they have very
different lighting conditions, so the matching should not be very good:
3. Here the numeric results:
*Method* Base - Base Base - Half Base - Test 1 Base - Test 2
----------------- ------------- ------------- --------------- ---------------
*Correlation* 1.000000 0.930766 0.182073 0.120447
*Chi-square* 0.000000 4.940466 21.184536 49.273437
*Intersection* 24.391548 14.959809 3.889029 5.775088
*Bhattacharyya* 0.000000 0.222609 0.646576 0.801869
For the *Correlation* and *Intersection* methods, the higher the metric, the more accurate the
match. As we can see, the match *base-base* is the highest of all as expected. Also we can observe
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
test 2 with respect to the base are worse, which again, was expected.
-# Here the numeric results:
*Method* | Base - Base | Base - Half | Base - Test 1 | Base - Test 2
----------------- | ------------ | ------------ | -------------- | ---------------
*Correlation* | 1.000000 | 0.930766 | 0.182073 | 0.120447
*Chi-square* | 0.000000 | 4.940466 | 21.184536 | 49.273437
*Intersection* | 24.391548 | 14.959809 | 3.889029 | 5.775088
*Bhattacharyya* | 0.000000 | 0.222609 | 0.646576 | 0.801869
For the *Correlation* and *Intersection* methods, the higher the metric, the more accurate the
match. As we can see, the match *base-base* is the highest of all as expected. Also we can observe
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
test 2 with respect to the base are worse, which again, was expected.

View File

@@ -17,7 +17,7 @@ Theory
- It is a graphical representation of the intensity distribution of an image.
- It quantifies the number of pixels for each intensity value considered.
![image](images/Histogram_Equalization_Theory_0.jpg)
![](images/Histogram_Equalization_Theory_0.jpg)
### What is Histogram Equalization?
@@ -29,7 +29,7 @@ Theory
*underpopulated* intensities. After applying the equalization, we get an histogram like the
figure in the center. The resulting image is shown in the picture at right.
![image](images/Histogram_Equalization_Theory_1.jpg)
![](images/Histogram_Equalization_Theory_1.jpg)
### How does it work?
@@ -46,7 +46,7 @@ Theory
is 255 ( or the maximum value for the intensity of the image ). From the example above, the
cumulative function is:
![image](images/Histogram_Equalization_Theory_2.jpg)
![](images/Histogram_Equalization_Theory_2.jpg)
- Finally, we use a simple remapping procedure to obtain the intensity values of the equalized
image:
@@ -69,14 +69,14 @@ Code
Explanation
-----------
1. Declare the source and destination images as well as the windows names:
-# Declare the source and destination images as well as the windows names:
@code{.cpp}
Mat src, dst;
char* source_window = "Source image";
char* equalized_window = "Equalized Image";
@endcode
2. Load the source image:
-# Load the source image:
@code{.cpp}
src = imread( argv[1], 1 );
@@ -84,18 +84,18 @@ Explanation
{ cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
return -1;}
@endcode
3. Convert it to grayscale:
-# Convert it to grayscale:
@code{.cpp}
cvtColor( src, src, COLOR_BGR2GRAY );
@endcode
4. Apply histogram equalization with the function @ref cv::equalizeHist :
-# Apply histogram equalization with the function @ref cv::equalizeHist :
@code{.cpp}
equalizeHist( src, dst );
@endcode
As it can be easily seen, the only arguments are the original image and the output (equalized)
image.
5. Display both images (original and equalized) :
-# Display both images (original and equalized) :
@code{.cpp}
namedWindow( source_window, WINDOW_AUTOSIZE );
namedWindow( equalized_window, WINDOW_AUTOSIZE );
@@ -103,7 +103,7 @@ Explanation
imshow( source_window, src );
imshow( equalized_window, dst );
@endcode
6. Wait until user exists the program
-# Wait until user exists the program
@code{.cpp}
waitKey(0);
return 0;
@@ -112,24 +112,24 @@ Explanation
Results
-------
1. To appreciate better the results of equalization, let's introduce an image with not much
-# To appreciate better the results of equalization, let's introduce an image with not much
contrast, such as:
![image](images/Histogram_Equalization_Original_Image.jpg)
![](images/Histogram_Equalization_Original_Image.jpg)
which, by the way, has this histogram:
![image](images/Histogram_Equalization_Original_Histogram.jpg)
![](images/Histogram_Equalization_Original_Histogram.jpg)
notice that the pixels are clustered around the center of the histogram.
2. After applying the equalization with our program, we get this result:
-# After applying the equalization with our program, we get this result:
![image](images/Histogram_Equalization_Equalized_Image.jpg)
![](images/Histogram_Equalization_Equalized_Image.jpg)
this image has certainly more contrast. Check out its new histogram like this:
![image](images/Histogram_Equalization_Equalized_Histogram.jpg)
![](images/Histogram_Equalization_Equalized_Histogram.jpg)
Notice how the number of pixels is more distributed through the intensity range.

View File

@@ -28,12 +28,12 @@ template image (patch).
our goal is to detect the highest matching area:
![image](images/Template_Matching_Template_Theory_Summary.jpg)
![](images/Template_Matching_Template_Theory_Summary.jpg)
- To identify the matching area, we have to *compare* the template image against the source image
by sliding it:
![image](images/Template_Matching_Template_Theory_Sliding.jpg)
![](images/Template_Matching_Template_Theory_Sliding.jpg)
- By **sliding**, we mean moving the patch one pixel at a time (left to right, up to down). At
each location, a metric is calculated so it represents how "good" or "bad" the match at that
@@ -41,7 +41,7 @@ template image (patch).
- For each location of **T** over **I**, you *store* the metric in the *result matrix* **(R)**.
Each location \f$(x,y)\f$ in **R** contains the match metric:
![image](images/Template_Matching_Template_Theory_Result.jpg)
![](images/Template_Matching_Template_Theory_Result.jpg)
the image above is the result **R** of sliding the patch with a metric **TM_CCORR_NORMED**.
The brightest locations indicate the highest matches. As you can see, the location marked by the
@@ -56,23 +56,23 @@ template image (patch).
Good question. OpenCV implements Template matching in the function @ref cv::matchTemplate . The
available methods are 6:
a. **method=CV_TM_SQDIFF**
-# **method=CV_TM_SQDIFF**
\f[R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2\f]
b. **method=CV_TM_SQDIFF_NORMED**
-# **method=CV_TM_SQDIFF_NORMED**
\f[R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}\f]
c. **method=CV_TM_CCORR**
-# **method=CV_TM_CCORR**
\f[R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y'))\f]
d. **method=CV_TM_CCORR_NORMED**
-# **method=CV_TM_CCORR_NORMED**
\f[R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}\f]
e. **method=CV_TM_CCOEFF**
-# **method=CV_TM_CCOEFF**
\f[R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I(x+x',y+y'))\f]
@@ -80,7 +80,7 @@ e. **method=CV_TM_CCOEFF**
\f[\begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array}\f]
f. **method=CV_TM_CCOEFF_NORMED**
-# **method=CV_TM_CCOEFF_NORMED**
\f[R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }\f]
@@ -98,93 +98,12 @@ Code
- **Downloadable code**: Click
[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp)
- **Code at glance:**
@code{.cpp}
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
@includelineno samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp
using namespace std;
using namespace cv;
/// Global Variables
Mat img; Mat templ; Mat result;
char* image_window = "Source Image";
char* result_window = "Result window";
int match_method;
int max_Trackbar = 5;
/// Function Headers
void MatchingMethod( int, void* );
/* @function main */
int main( int argc, char** argv )
{
/// Load image and template
img = imread( argv[1], 1 );
templ = imread( argv[2], 1 );
/// Create windows
namedWindow( image_window, WINDOW_AUTOSIZE );
namedWindow( result_window, WINDOW_AUTOSIZE );
/// Create Trackbar
char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );
MatchingMethod( 0, 0 );
waitKey(0);
return 0;
}
/*
* @function MatchingMethod
* @brief Trackbar callback
*/
void MatchingMethod( int, void* )
{
/// Source image to display
Mat img_display;
img.copyTo( img_display );
/// Create the result matrix
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create( result_cols, result_rows, CV_32FC1 );
/// Do the Matching and Normalize
matchTemplate( img, templ, result, match_method );
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
/// Localizing the best match with minMaxLoc
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
/// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
{ matchLoc = minLoc; }
else
{ matchLoc = maxLoc; }
/// Show me what you got
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
imshow( image_window, img_display );
imshow( result_window, result );
return;
}
@endcode
Explanation
-----------
1. Declare some global variables, such as the image, template and result matrices, as well as the
-# Declare some global variables, such as the image, template and result matrices, as well as the
match method and the window names:
@code{.cpp}
Mat img; Mat templ; Mat result;
@@ -194,33 +113,33 @@ Explanation
int match_method;
int max_Trackbar = 5;
@endcode
2. Load the source image and template:
-# Load the source image and template:
@code{.cpp}
img = imread( argv[1], 1 );
templ = imread( argv[2], 1 );
@endcode
3. Create the windows to show the results:
-# Create the windows to show the results:
@code{.cpp}
namedWindow( image_window, WINDOW_AUTOSIZE );
namedWindow( result_window, WINDOW_AUTOSIZE );
@endcode
4. Create the Trackbar to enter the kind of matching method to be used. When a change is detected
-# Create the Trackbar to enter the kind of matching method to be used. When a change is detected
the callback function **MatchingMethod** is called.
@code{.cpp}
char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );
@endcode
5. Wait until user exits the program.
-# Wait until user exits the program.
@code{.cpp}
waitKey(0);
return 0;
@endcode
6. Let's check out the callback function. First, it makes a copy of the source image:
-# Let's check out the callback function. First, it makes a copy of the source image:
@code{.cpp}
Mat img_display;
img.copyTo( img_display );
@endcode
7. Next, it creates the result matrix that will store the matching results for each template
-# Next, it creates the result matrix that will store the matching results for each template
location. Observe in detail the size of the result matrix (which matches all possible locations
for it)
@code{.cpp}
@@ -229,18 +148,18 @@ Explanation
result.create( result_cols, result_rows, CV_32FC1 );
@endcode
8. Perform the template matching operation:
-# Perform the template matching operation:
@code{.cpp}
matchTemplate( img, templ, result, match_method );
@endcode
the arguments are naturally the input image **I**, the template **T**, the result **R** and the
match_method (given by the Trackbar)
9. We normalize the results:
-# We normalize the results:
@code{.cpp}
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
@endcode
10. We localize the minimum and maximum values in the result matrix **R** by using @ref
-# We localize the minimum and maximum values in the result matrix **R** by using @ref
cv::minMaxLoc .
@code{.cpp}
double minVal; double maxVal; Point minLoc; Point maxLoc;
@@ -256,7 +175,7 @@ Explanation
array.
- **Mat():** Optional mask
11. For the first two methods ( TM_SQDIFF and MT_SQDIFF_NORMED ) the best match are the lowest
-# For the first two methods ( TM_SQDIFF and MT_SQDIFF_NORMED ) the best match are the lowest
values. For all the others, higher values represent better matches. So, we save the
corresponding value in the **matchLoc** variable:
@code{.cpp}
@@ -265,7 +184,7 @@ Explanation
else
{ matchLoc = maxLoc; }
@endcode
12. Display the source image and the result matrix. Draw a rectangle around the highest possible
-# Display the source image and the result matrix. Draw a rectangle around the highest possible
matching area:
@code{.cpp}
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
@@ -274,29 +193,32 @@ Explanation
imshow( image_window, img_display );
imshow( result_window, result );
@endcode
Results
-------
1. Testing our program with an input image such as:
-# Testing our program with an input image such as:
![image](images/Template_Matching_Original_Image.jpg)
![](images/Template_Matching_Original_Image.jpg)
and a template image:
![image](images/Template_Matching_Template_Image.jpg)
![](images/Template_Matching_Template_Image.jpg)
2. Generate the following result matrices (first row are the standard methods SQDIFF, CCORR and
-# Generate the following result matrices (first row are the standard methods SQDIFF, CCORR and
CCOEFF, second row are the same methods in its normalized version). In the first column, the
darkest is the better match, for the other two columns, the brighter a location, the higher the
match.
![Result_0](images/Template_Matching_Correl_Result_0.jpg)
![Result_1](images/Template_Matching_Correl_Result_1.jpg)
![Result_2](images/Template_Matching_Correl_Result_2.jpg)
![Result_3](images/Template_Matching_Correl_Result_3.jpg)
![Result_4](images/Template_Matching_Correl_Result_4.jpg)
![Result_5](images/Template_Matching_Correl_Result_5.jpg)
|Result_0| |Result_2| |Result_4|
------------- ------------- -------------
|Result_1| |Result_3| |Result_5|
3. The right match is shown below (black rectangle around the face of the guy at the right). Notice
-# The right match is shown below (black rectangle around the face of the guy at the right). Notice
that CCORR and CCDEFF gave erroneous best matches, however their normalized version did it
right, this may be due to the fact that we are only considering the "highest match" and not the
other possible high matches.
![image](images/Template_Matching_Image_Result.jpg)
![](images/Template_Matching_Image_Result.jpg)