svn repository web references are replaced with links to git
This commit is contained in:
@@ -14,7 +14,7 @@ In this tutorial you will learn:
|
||||
* What is Back Projection and why it is useful
|
||||
|
||||
* How to use the OpenCV function :calc_back_project:`calcBackProject <>` to calculate Back Projection
|
||||
|
||||
|
||||
* How to mix different channels of an image by using the OpenCV function :mix_channels:`mixChannels <>`
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ What is Back Projection?
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Back Projection is a way of recording how well the pixels of a given image fit the distribution of pixels in a histogram model.
|
||||
|
||||
* To make it simpler: For Back Projection, you calculate the histogram model of a feature and then use it to find this feature in an image.
|
||||
|
||||
* To make it simpler: For Back Projection, you calculate the histogram model of a feature and then use it to find this feature in an image.
|
||||
|
||||
* Application example: If you have a histogram of flesh color (say, a Hue-Saturation histogram ), then you can use it to find flesh color areas in an image:
|
||||
|
||||
@@ -42,9 +42,9 @@ How does it work?
|
||||
|
||||
* 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| |T1|
|
||||
====== ======
|
||||
|
||||
.. |T0| image:: images/Back_Projection_Theory0.jpg
|
||||
:align: middle
|
||||
@@ -55,9 +55,9 @@ How does it work?
|
||||
|
||||
* Now, let's imagine that you get another hand image (Test Image) like the one below: (with its respective histogram):
|
||||
|
||||
====== ======
|
||||
|T2| |T3|
|
||||
====== ======
|
||||
====== ======
|
||||
|T2| |T3|
|
||||
====== ======
|
||||
|
||||
.. |T2| image:: images/Back_Projection_Theory2.jpg
|
||||
:align: middle
|
||||
@@ -70,7 +70,7 @@ How does it work?
|
||||
|
||||
a. In each pixel of our Test Image (i.e. :math:`p(i,j)` ), collect the data and find the correspondent bin location for that pixel (i.e. :math:`( h_{i,j}, s_{i,j} )` ).
|
||||
|
||||
b. Lookup the *model histogram* in the correspondent bin - :math:`( h_{i,j}, s_{i,j} )` - and read the bin value.
|
||||
b. Lookup the *model histogram* in the correspondent bin - :math:`( h_{i,j}, s_{i,j} )` - and read the bin value.
|
||||
|
||||
c. 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.
|
||||
|
||||
@@ -88,7 +88,7 @@ Code
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* **What does this program do?**
|
||||
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Loads an image
|
||||
@@ -99,9 +99,9 @@ Code
|
||||
|
||||
* **Downloadable code**:
|
||||
|
||||
a. Click `here <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp>`_ 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 skin area) you can check the `improved demo <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp>`_
|
||||
c. ...or you can always check out the classical `camshiftdemo <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/camshiftdemo.cpp>`_ in samples.
|
||||
a. Click `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp>`_ 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 skin area) you can check the `improved demo <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp>`_
|
||||
c. ...or you can always check out the classical `camshiftdemo <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/camshiftdemo.cpp>`_ in samples.
|
||||
|
||||
* **Code at glance:**
|
||||
|
||||
@@ -116,7 +116,7 @@ Code
|
||||
using namespace std;
|
||||
|
||||
/// Global Variables
|
||||
Mat src; Mat hsv; Mat hue;
|
||||
Mat src; Mat hsv; Mat hue;
|
||||
int bins = 25;
|
||||
|
||||
/// Function Headers
|
||||
@@ -133,7 +133,7 @@ Code
|
||||
/// Use only the Hue value
|
||||
hue.create( hsv.size(), hsv.depth() );
|
||||
int ch[] = { 0, 0 };
|
||||
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
|
||||
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
|
||||
|
||||
/// Create Trackbar to enter the number of bins
|
||||
char* window_image = "Source image";
|
||||
@@ -146,7 +146,7 @@ Code
|
||||
|
||||
/// Wait until user exits the program
|
||||
waitKey(0);
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ Code
|
||||
void Hist_and_Backproj(int, void* )
|
||||
{
|
||||
MatND hist;
|
||||
int histSize = MAX( bins, 2 );
|
||||
int histSize = MAX( bins, 2 );
|
||||
float hue_range[] = { 0, 180 };
|
||||
const float* ranges = { hue_range };
|
||||
|
||||
@@ -168,16 +168,16 @@ Code
|
||||
/// 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 );
|
||||
int bin_w = cvRound( (double) w / histSize );
|
||||
Mat histImg = Mat::zeros( w, h, CV_8UC3 );
|
||||
|
||||
for( int i = 0; i < bins; i ++ )
|
||||
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 );
|
||||
@@ -190,7 +190,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
Mat src; Mat hsv; Mat hue;
|
||||
Mat src; Mat hsv; Mat hue;
|
||||
int bins = 25;
|
||||
|
||||
#. Read the input image and transform it to HSV format:
|
||||
@@ -206,7 +206,7 @@ Explanation
|
||||
|
||||
hue.create( hsv.size(), hsv.depth() );
|
||||
int ch[] = { 0, 0 };
|
||||
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
|
||||
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
|
||||
|
||||
as you see, we use the function :mix_channels:`mixChannels` to get only the channel 0 (Hue) from the hsv image. It gets the following parameters:
|
||||
|
||||
@@ -214,15 +214,15 @@ Explanation
|
||||
|
||||
+ **&hsv:** The source array from which the channels will be copied
|
||||
+ **1:** The number of source arrays
|
||||
+ **&hue:** The destination array of the copied channels
|
||||
+ **&hue:** The destination array of the copied channels
|
||||
+ **1:** The number of destination arrays
|
||||
+ **ch[] = {0,0}:** The array of index pairs indicating how the channels are copied. In this case, the Hue(0) channel of &hsv is being copied to the 0 channel of &hue (1-channel)
|
||||
+ **1:** Number of index pairs
|
||||
|
||||
+ **1:** Number of index pairs
|
||||
|
||||
#. 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-block:: cpp
|
||||
|
||||
|
||||
char* window_image = "Source image";
|
||||
namedWindow( window_image, CV_WINDOW_AUTOSIZE );
|
||||
createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj );
|
||||
@@ -235,7 +235,7 @@ Explanation
|
||||
imshow( window_image, src );
|
||||
|
||||
waitKey(0);
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
#. **Hist_and_Backproj function:** Initialize the arguments needed for :calc_hist:`calcHist <>`. The number of bins comes from the Trackbar:
|
||||
|
||||
@@ -245,7 +245,7 @@ Explanation
|
||||
void Hist_and_Backproj(int, void* )
|
||||
{
|
||||
MatND hist;
|
||||
int histSize = MAX( bins, 2 );
|
||||
int histSize = MAX( bins, 2 );
|
||||
float hue_range[] = { 0, 180 };
|
||||
const float* ranges = { hue_range };
|
||||
|
||||
@@ -264,7 +264,7 @@ Explanation
|
||||
calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true );
|
||||
|
||||
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)
|
||||
|
||||
|
||||
#. Display backproj:
|
||||
|
||||
.. code-block:: cpp
|
||||
@@ -276,10 +276,10 @@ Explanation
|
||||
.. code-block:: cpp
|
||||
|
||||
int w = 400; int h = 400;
|
||||
int bin_w = cvRound( (double) w / histSize );
|
||||
int bin_w = cvRound( (double) w / histSize );
|
||||
Mat histImg = Mat::zeros( w, h, CV_8UC3 );
|
||||
|
||||
for( int i = 0; i < bins; i ++ )
|
||||
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 );
|
||||
@@ -291,9 +291,9 @@ Results
|
||||
|
||||
#. 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|
|
||||
====== ====== ======
|
||||
====== ====== ======
|
||||
|R0| |R1| |R2|
|
||||
====== ====== ======
|
||||
|
||||
.. |R0| image:: images/Back_Projection1_Source_Image.jpg
|
||||
:align: middle
|
||||
|
||||
@@ -13,7 +13,7 @@ In this tutorial you will learn how to:
|
||||
* Use the OpenCV function :split:`split <>` to divide an image into its correspondent planes.
|
||||
|
||||
* To calculate histograms of arrays of images by using the OpenCV function :calc_hist:`calcHist <>`
|
||||
|
||||
|
||||
* To normalize an array by using the function :normalize:`normalize <>`
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ What are histograms?
|
||||
|
||||
|
||||
.. image:: images/Histogram_Calculation_Theory_Hist0.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
* 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 **bins**) like:
|
||||
|
||||
@@ -42,22 +42,22 @@ What are histograms?
|
||||
\begin{array}{l}
|
||||
[0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\
|
||||
range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} }
|
||||
\end{array}
|
||||
\end{array}
|
||||
|
||||
and we can keep count of the number of pixels that fall in the range of each :math:`bin_{i}`. Applying 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
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
* 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 (i.e. gradients, directions, etc).
|
||||
|
||||
* 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 (i.e. gradients, directions, etc).
|
||||
|
||||
* 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** 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**
|
||||
c. **range**: The limits for the values to be measured. In this case: **range = [0,255]**
|
||||
|
||||
c. **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 (in which x and y would be :math:`bin_{x}` and :math:`bin_{y}` for each feature and z would be the number of counts for each combination of :math:`(bin_{x}, bin_{y})`. The same would apply for more features (of course it gets trickier).
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ What OpenCV offers you
|
||||
-----------------------
|
||||
|
||||
For simple purposes, OpenCV implements the function :calc_hist:`calcHist <>`, which calculates the histogram of a set of arrays (usually images or image planes). It can operate with up to 32 dimensions. We will see it in the code below!
|
||||
|
||||
|
||||
|
||||
Code
|
||||
====
|
||||
@@ -73,7 +73,7 @@ Code
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* **What does this program do?**
|
||||
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Loads an image
|
||||
@@ -82,7 +82,7 @@ Code
|
||||
* Plot the three histograms in a window
|
||||
|
||||
* **Downloadable code**:
|
||||
Click `here <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp>`_
|
||||
Click `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp>`_
|
||||
|
||||
* **Code at glance:**
|
||||
|
||||
@@ -181,7 +181,7 @@ Explanation
|
||||
if( !src.data )
|
||||
{ return -1; }
|
||||
|
||||
#. Separate the source image in its three R,G and B planes. For this we use the OpenCV function :split:`split <>`:
|
||||
#. Separate the source image in its three R,G and B planes. For this we use the OpenCV function :split:`split <>`:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -195,7 +195,7 @@ Explanation
|
||||
a. Establish number of bins (5, 10...):
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
|
||||
int histSize = 256; //from 0 to 255
|
||||
|
||||
b. Set the range of values (as we said, between 0 and 255 )
|
||||
@@ -219,25 +219,25 @@ Explanation
|
||||
Mat b_hist, g_hist, r_hist;
|
||||
|
||||
e. We proceed to calculate the histograms by using the OpenCV function :calc_hist:`calcHist <>`:
|
||||
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
/// 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 );
|
||||
|
||||
|
||||
where the arguments are:
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
|
||||
+ **&bgr_planes[0]:** The source array(s)
|
||||
+ **1**: The number of source arrays (in this case we are using 1. We can enter here also a list of arrays )
|
||||
+ **0**: The channel (*dim*) to be measured. In this case it is just the intensity (each array is single-channel) so we just write 0.
|
||||
+ **Mat()**: A mask to be used on the source array ( zeros indicating pixels to be ignored ). If not defined it is not used
|
||||
+ **b_hist**: The Mat object where the histogram will be stored
|
||||
+ **1**: The histogram dimensionality.
|
||||
+ **histSize:** The number of bins per each used dimension
|
||||
+ **1**: The histogram dimensionality.
|
||||
+ **histSize:** The number of bins per each used dimension
|
||||
+ **histRange:** The range of values to be measured per each dimension
|
||||
+ **uniform** and **accumulate**: The bin sizes are the same and the histogram is cleared at the beginning.
|
||||
|
||||
@@ -264,7 +264,7 @@ Explanation
|
||||
this function receives these arguments:
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
|
||||
+ **b_hist:** Input array
|
||||
+ **b_hist:** Output normalized array (can be the same)
|
||||
+ **0** and**histImage.rows**: For this example, they are the lower and upper limits to normalize the values of **r_hist**
|
||||
@@ -291,7 +291,7 @@ Explanation
|
||||
}
|
||||
|
||||
|
||||
we use the expression:
|
||||
we use the expression:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -315,7 +315,7 @@ Explanation
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
Result
|
||||
======
|
||||
@@ -323,10 +323,10 @@ Result
|
||||
#. Using as input argument an image like the shown below:
|
||||
|
||||
.. image:: images/Histogram_Calculation_Original_Image.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
#. Produces the following histogram:
|
||||
|
||||
.. image:: images/Histogram_Calculation_Result.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
|
||||
@@ -25,43 +25,43 @@ Theory
|
||||
|
||||
|
||||
a. **Correlation ( CV\_COMP\_CORREL )**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
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}}
|
||||
|
||||
|
||||
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}}
|
||||
|
||||
where
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
\bar{H_k} = \frac{1}{N} \sum _J H_k(J)
|
||||
|
||||
|
||||
|
||||
\bar{H_k} = \frac{1}{N} \sum _J H_k(J)
|
||||
|
||||
|
||||
and :math:`N` is the total number of histogram bins.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
b. **Chi-Square ( CV\_COMP\_CHISQR )**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}
|
||||
|
||||
|
||||
|
||||
d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}
|
||||
|
||||
|
||||
c. **Intersection ( method=CV\_COMP\_INTERSECT )**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))
|
||||
|
||||
|
||||
|
||||
d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))
|
||||
|
||||
|
||||
d. **Bhattacharyya distance ( CV\_COMP\_BHATTACHARYYA )**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
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)}}
|
||||
|
||||
|
||||
|
||||
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)}}
|
||||
|
||||
|
||||
|
||||
Code
|
||||
====
|
||||
@@ -69,7 +69,7 @@ Code
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* **What does this program do?**
|
||||
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Loads a *base image* and 2 *test images* to be compared with it.
|
||||
@@ -79,8 +79,8 @@ Code
|
||||
* Compare the histogram of the *base image* with respect to the 2 test histograms, the histogram of the lower half base image and with the same base image histogram.
|
||||
* Display the numerical matching parameters obtained.
|
||||
|
||||
* **Downloadable code**:
|
||||
Click `here <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp>`_
|
||||
* **Downloadable code**:
|
||||
Click `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp>`_
|
||||
|
||||
* **Code at glance:**
|
||||
|
||||
@@ -105,7 +105,7 @@ Code
|
||||
/// Load three images with different environment settings
|
||||
if( argc < 4 )
|
||||
{ printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
src_base = imread( argv[1], 1 );
|
||||
@@ -117,7 +117,7 @@ Code
|
||||
cvtColor( src_test1, hsv_test1, CV_BGR2HSV );
|
||||
cvtColor( src_test2, hsv_test2, CV_BGR2HSV );
|
||||
|
||||
hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
|
||||
hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
|
||||
|
||||
/// Using 30 bins for hue and 32 for saturation
|
||||
int h_bins = 50; int s_bins = 60;
|
||||
@@ -153,14 +153,14 @@ Code
|
||||
|
||||
/// Apply the histogram comparison methods
|
||||
for( int i = 0; i < 4; i++ )
|
||||
{ int compare_method = i;
|
||||
{ int compare_method = i;
|
||||
double base_base = compareHist( hist_base, hist_base, compare_method );
|
||||
double base_half = compareHist( hist_base, hist_half_down, compare_method );
|
||||
double base_test1 = compareHist( hist_base, hist_test1, compare_method );
|
||||
double base_test2 = compareHist( hist_base, hist_test2, compare_method );
|
||||
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
printf( "Done \n" );
|
||||
|
||||
@@ -171,7 +171,7 @@ Code
|
||||
Explanation
|
||||
===========
|
||||
|
||||
#. Declare variables such as the matrices to store the base image and the two other images to compare ( RGB and HSV )
|
||||
#. Declare variables such as the matrices to store the base image and the two other images to compare ( RGB and HSV )
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -186,7 +186,7 @@ Explanation
|
||||
|
||||
if( argc < 4 )
|
||||
{ printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
src_base = imread( argv[1], 1 );
|
||||
@@ -205,7 +205,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
|
||||
hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
|
||||
|
||||
#. Initialize the arguments to calculate the histograms (bins, ranges and channels H and S ).
|
||||
|
||||
@@ -233,7 +233,7 @@ Explanation
|
||||
#. Calculate the Histograms for the base image, the 2 test images and the half-down base image:
|
||||
|
||||
.. code-block:: 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() );
|
||||
|
||||
@@ -252,24 +252,24 @@ Explanation
|
||||
.. code-block:: cpp
|
||||
|
||||
for( int i = 0; i < 4; i++ )
|
||||
{ int compare_method = i;
|
||||
{ int compare_method = i;
|
||||
double base_base = compareHist( hist_base, hist_base, compare_method );
|
||||
double base_half = compareHist( hist_base, hist_half_down, compare_method );
|
||||
double base_test1 = compareHist( hist_base, hist_test1, compare_method );
|
||||
double base_test2 = compareHist( hist_base, hist_test2, compare_method );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
Results
|
||||
========
|
||||
|
||||
#. We use as input the following images:
|
||||
|
||||
============ ============ ============
|
||||
============ ============ ============
|
||||
|Base_0| |Test_1| |Test_2|
|
||||
============ ============ ============
|
||||
============ ============ ============
|
||||
|
||||
.. |Base_0| image:: images/Histogram_Comparison_Source_0.jpg
|
||||
:align: middle
|
||||
@@ -289,10 +289,10 @@ 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
|
||||
*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
|
||||
=============== =============== =============== =============== ===============
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ In this tutorial you will learn:
|
||||
|
||||
* What an image histogram is and why it is useful
|
||||
|
||||
* To equalize histograms of images by using the OpenCV function:equalize_hist:`equalizeHist <>`
|
||||
* To equalize histograms of images by using the OpenCV function:equalize_hist:`equalizeHist <>`
|
||||
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ What is an Image Histogram?
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* It is a graphical representation of the intensity distribution of an image.
|
||||
* 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
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
|
||||
What is Histogram Equalization?
|
||||
@@ -42,30 +42,30 @@ What is Histogram Equalization?
|
||||
* To make it clearer, from the image above, you can see that the pixels seem clustered around the middle of the available range of intensities. What Histogram Equalization does is to *stretch out* this range. Take a look at the figure below: The green circles indicate the *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
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
How does it work?
|
||||
-----------------
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Equalization implies *mapping* one distribution (the given histogram) to another distribution (a wider and more uniform distribution of intensity values) so the intensity values are spreaded over the whole range.
|
||||
* Equalization implies *mapping* one distribution (the given histogram) to another distribution (a wider and more uniform distribution of intensity values) so the intensity values are spreaded over the whole range.
|
||||
|
||||
* To accomplish the equalization effect, the remapping should be the *cumulative distribution function (cdf)* (more details, refer to *Learning OpenCV*). For the histogram :math:`H(i)`, its *cumulative distribution* :math:`H^{'}(i)` is:
|
||||
|
||||
.. math::
|
||||
|
||||
H^{'}(i) = \sum_{0 \le j < i} H(j)
|
||||
H^{'}(i) = \sum_{0 \le j < i} H(j)
|
||||
|
||||
To use this as a remapping function, we have to normalize :math:`H^{'}(i)` such that the maximum value 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
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
* Finally, we use a simple remapping procedure to obtain the intensity values of the equalized image:
|
||||
|
||||
.. math::
|
||||
|
||||
|
||||
equalized( x, y ) = H^{'}( src(x,y) )
|
||||
|
||||
Code
|
||||
@@ -74,16 +74,16 @@ Code
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* **What does this program do?**
|
||||
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Loads an image
|
||||
* Convert the original image to grayscale
|
||||
* Convert the original image to grayscale
|
||||
* Equalize the Histogram by using the OpenCV function :equalize_hist:`EqualizeHist <>`
|
||||
* Display the source and equalized images in a window.
|
||||
|
||||
* **Downloadable code**:
|
||||
Click `here <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp>`_
|
||||
Click `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp>`_
|
||||
|
||||
* **Code at glance:**
|
||||
|
||||
@@ -117,15 +117,15 @@ Code
|
||||
|
||||
/// Apply Histogram Equalization
|
||||
equalizeHist( src, dst );
|
||||
|
||||
|
||||
/// Display results
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( equalized_window, CV_WINDOW_AUTOSIZE );
|
||||
|
||||
imshow( source_window, src );
|
||||
imshow( equalized_window, dst );
|
||||
|
||||
/// Wait until user exits the program
|
||||
|
||||
/// Wait until user exits the program
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
@@ -134,7 +134,7 @@ Code
|
||||
Explanation
|
||||
===========
|
||||
|
||||
#. 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-block:: cpp
|
||||
|
||||
@@ -144,7 +144,7 @@ Explanation
|
||||
char* equalized_window = "Equalized Image";
|
||||
|
||||
#. Load the source image:
|
||||
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
src = imread( argv[1], 1 );
|
||||
@@ -164,7 +164,7 @@ Explanation
|
||||
.. code-block:: cpp
|
||||
|
||||
equalizeHist( src, dst );
|
||||
|
||||
|
||||
As it can be easily seen, the only arguments are the original image and the output (equalized) image.
|
||||
|
||||
#. Display both images (original and equalized) :
|
||||
@@ -176,9 +176,9 @@ Explanation
|
||||
|
||||
imshow( source_window, src );
|
||||
imshow( equalized_window, dst );
|
||||
|
||||
|
||||
#. Wait until user exists the program
|
||||
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
waitKey(0);
|
||||
@@ -191,19 +191,19 @@ Results
|
||||
#. 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
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
which, by the way, has this histogram:
|
||||
|
||||
.. image:: images/Histogram_Equalization_Original_Histogram.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
notice that the pixels are clustered around the center of the histogram.
|
||||
|
||||
#. After applying the equalization with our program, we get this result:
|
||||
|
||||
.. image:: images/Histogram_Equalization_Equalized_Image.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
this image has certainly more contrast. Check out its new histogram like this:
|
||||
|
||||
|
||||
@@ -31,81 +31,81 @@ How does it work?
|
||||
|
||||
* We need two primary components:
|
||||
|
||||
a. **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
|
||||
a. **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
|
||||
|
||||
our goal is to detect the highest matching area:
|
||||
|
||||
.. image:: images/Template_Matching_Template_Theory_Summary.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
* 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
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
* 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 location is (or how similar the patch is to that particular area of the source image).
|
||||
|
||||
* For each location of **T** over **I**, you *store* the metric in the *result matrix* **(R)**. Each location :math:`(x,y)` in **R** contains the match metric:
|
||||
|
||||
.. image:: images/Template_Matching_Template_Theory_Result.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
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 red circle is probably the one with the highest value, so that location (the rectangle formed by that point as a corner and width and height equal to the patch image) is considered the match.
|
||||
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 red circle is probably the one with the highest value, so that location (the rectangle formed by that point as a corner and width and height equal to the patch image) is considered the match.
|
||||
|
||||
* In practice, we use the function :min_max_loc:`minMaxLoc <>` to locate the highest value (or lower, depending of the type of matching method) in the *R* matrix.
|
||||
|
||||
|
||||
Which are the matching methods available in OpenCV?
|
||||
----------------------------------------------------
|
||||
|
||||
Good question. OpenCV implements Template matching in the function :match_template:`matchTemplate <>`. The available methods are 6:
|
||||
|
||||
a. **method=CV\_TM\_SQDIFF**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2
|
||||
|
||||
|
||||
|
||||
R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2
|
||||
|
||||
|
||||
b. **method=CV\_TM\_SQDIFF\_NORMED**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
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}}
|
||||
|
||||
|
||||
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}}
|
||||
|
||||
|
||||
c. **method=CV\_TM\_CCORR**
|
||||
|
||||
.. math::
|
||||
|
||||
R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y'))
|
||||
|
||||
|
||||
d. **method=CV\_TM\_CCORR\_NORMED**
|
||||
|
||||
.. math::
|
||||
|
||||
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}}
|
||||
|
||||
|
||||
R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y'))
|
||||
|
||||
|
||||
d. **method=CV\_TM\_CCORR\_NORMED**
|
||||
|
||||
.. math::
|
||||
|
||||
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}}
|
||||
|
||||
|
||||
e. **method=CV\_TM\_CCOEFF**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I(x+x',y+y'))
|
||||
|
||||
|
||||
R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I(x+x',y+y'))
|
||||
|
||||
where
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
\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}
|
||||
|
||||
|
||||
|
||||
\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. **method=CV\_TM\_CCOEFF\_NORMED**
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
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} }
|
||||
|
||||
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} }
|
||||
|
||||
|
||||
Code
|
||||
@@ -115,7 +115,7 @@ Code
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* **What does this program do?**
|
||||
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
* Loads an input image and a image patch (*template*)
|
||||
@@ -125,13 +125,13 @@ Code
|
||||
* Draw a rectangle around the area corresponding to the highest match
|
||||
|
||||
* **Downloadable code**:
|
||||
Click `here <http://code.opencv.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp>`_
|
||||
Click `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp>`_
|
||||
|
||||
* **Code at glance:**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
@@ -160,7 +160,7 @@ Code
|
||||
/// Create windows
|
||||
namedWindow( image_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( result_window, CV_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 );
|
||||
@@ -180,11 +180,11 @@ Code
|
||||
/// 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;
|
||||
|
||||
int result_rows = img.rows - templ.rows + 1;
|
||||
|
||||
result.create( result_cols, result_rows, CV_32FC1 );
|
||||
|
||||
/// Do the Matching and Normalize
|
||||
@@ -194,18 +194,18 @@ Code
|
||||
/// 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
|
||||
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 );
|
||||
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 );
|
||||
@@ -241,7 +241,7 @@ Explanation
|
||||
|
||||
namedWindow( image_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( result_window, CV_WINDOW_AUTOSIZE );
|
||||
|
||||
|
||||
#. 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-block:: cpp
|
||||
@@ -255,7 +255,7 @@ Explanation
|
||||
|
||||
waitKey(0);
|
||||
return 0;
|
||||
|
||||
|
||||
#. Let's check out the callback function. First, it makes a copy of the source image:
|
||||
|
||||
.. code-block:: cpp
|
||||
@@ -267,12 +267,12 @@ Explanation
|
||||
#. 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-block:: cpp
|
||||
|
||||
|
||||
int result_cols = img.cols - templ.cols + 1;
|
||||
int result_rows = img.rows - templ.rows + 1;
|
||||
|
||||
int result_rows = img.rows - templ.rows + 1;
|
||||
|
||||
result.create( result_cols, result_rows, CV_32FC1 );
|
||||
|
||||
|
||||
#. Perform the template matching operation:
|
||||
|
||||
.. code-block:: cpp
|
||||
@@ -287,18 +287,18 @@ Explanation
|
||||
|
||||
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
|
||||
|
||||
#. We localize the minimum and maximum values in the result matrix **R** by using :min_max_loc:`minMaxLoc <>`.
|
||||
#. We localize the minimum and maximum values in the result matrix **R** by using :min_max_loc:`minMaxLoc <>`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
double minVal; double maxVal; Point minLoc; Point maxLoc;
|
||||
Point matchLoc;
|
||||
|
||||
|
||||
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
|
||||
|
||||
|
||||
the function calls as arguments:
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
+ **result:** The source array
|
||||
+ **&minVal** and **&maxVal:** Variables to save the minimum and maximum values in **result**
|
||||
@@ -309,18 +309,18 @@ Explanation
|
||||
#. For the first two methods ( CV\_SQDIFF and CV\_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-block:: cpp
|
||||
|
||||
|
||||
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
|
||||
{ matchLoc = minLoc; }
|
||||
else
|
||||
else
|
||||
{ matchLoc = maxLoc; }
|
||||
|
||||
#. Display the source image and the result matrix. Draw a rectangle around the highest possible matching area:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
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 );
|
||||
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 );
|
||||
@@ -333,19 +333,19 @@ Results
|
||||
|
||||
.. image:: images/Template_Matching_Original_Image.jpg
|
||||
:align: center
|
||||
|
||||
|
||||
and a template image:
|
||||
|
||||
.. image:: images/Template_Matching_Template_Image.jpg
|
||||
:align: center
|
||||
:align: center
|
||||
|
||||
#. 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| |Result_2| |Result_4|
|
||||
============ ============ ============
|
||||
============ ============ ============
|
||||
|Result_1| |Result_3| |Result_5|
|
||||
============ ============ ============
|
||||
============ ============ ============
|
||||
|
||||
.. |Result_0| image:: images/Template_Matching_Correl_Result_0.jpg
|
||||
:align: middle
|
||||
|
||||
Reference in New Issue
Block a user