Commit ce05d6cb authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #6773 from acinader:add-mask-to-match-template-demo

parents 26bf5b5d bd7c21d8
...@@ -19,6 +19,10 @@ Theory ...@@ -19,6 +19,10 @@ Theory
Template matching is a technique for finding areas of an image that match (are similar) to a Template matching is a technique for finding areas of an image that match (are similar) to a
template image (patch). template image (patch).
While the patch must be a rectangle it may be that not all of the
rectangle is relevant. In such a case, a mask can be used to isolate the portion of the patch
that should be used to find the match.
### How does it work? ### How does it work?
- We need two primary components: - We need two primary components:
...@@ -51,6 +55,30 @@ template image (patch). ...@@ -51,6 +55,30 @@ template image (patch).
- In practice, we use the function @ref cv::minMaxLoc to locate the highest value (or lower, - In practice, we use the function @ref cv::minMaxLoc to locate the highest value (or lower,
depending of the type of matching method) in the *R* matrix. depending of the type of matching method) in the *R* matrix.
### How does the mask work?
- If masking is needed for the match, three components are required:
-# **Source image (I):** The image in which we expect to find a match to the template image
-# **Template image (T):** The patch image which will be compared to the template image
-# **Mask image (M):** The mask, a grayscale image that masks the template
- Only two matching methods currently accept a mask: CV_TM_SQDIFF and CV_TM_CCORR_NORMED (see
below for explanation of all the matching methods available in opencv).
- The mask must have the same dimensions as the template
- The mask should have a CV_8U or CV_32F depth and the same number of channels
as the template image. In CV_8U case, the mask values are treated as binary,
i.e. zero and non-zero. In CV_32F case, the values should fall into [0..1]
range and the template pixels will be multiplied by the corresponding mask pixel
values. Since the input images in the sample have the CV_8UC3 type, the mask
is also read as color image.
![](images/Template_Matching_Mask_Example.jpg)
### Which are the matching methods available in OpenCV? ### Which are the matching methods available in OpenCV?
Good question. OpenCV implements Template matching in the function @ref cv::matchTemplate . The Good question. OpenCV implements Template matching in the function @ref cv::matchTemplate . The
...@@ -88,10 +116,11 @@ Code ...@@ -88,10 +116,11 @@ Code
---- ----
- **What does this program do?** - **What does this program do?**
- Loads an input image and a image patch (*template*) - Loads an input image, an image patch (*template*), and optionally a mask
- Perform a template matching procedure by using the OpenCV function @ref cv::matchTemplate - Perform a template matching procedure by using the OpenCV function @ref cv::matchTemplate
with any of the 6 matching methods described before. The user can choose the method by with any of the 6 matching methods described before. The user can choose the method by
entering its selection in the Trackbar. entering its selection in the Trackbar. If a mask is supplied, it will only be used for
the methods that support masking
- Normalize the output of the matching procedure - Normalize the output of the matching procedure
- Localize the location with higher matching probability - Localize the location with higher matching probability
- Draw a rectangle around the area corresponding to the highest match - Draw a rectangle around the area corresponding to the highest match
...@@ -113,10 +142,14 @@ Explanation ...@@ -113,10 +142,14 @@ Explanation
int match_method; int match_method;
int max_Trackbar = 5; int max_Trackbar = 5;
@endcode @endcode
-# Load the source image and template: -# Load the source image, template, and optionally, if supported for the matching method, a mask:
@code{.cpp} @code{.cpp}
img = imread( argv[1], 1 ); bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
templ = imread( argv[2], 1 ); if (use_mask && method_accepts_mask)
{ matchTemplate( img, templ, result, match_method, mask); }
else
{ matchTemplate( img, templ, result, match_method); }
@endcode @endcode
-# Create the windows to show the results: -# Create the windows to show the results:
@code{.cpp} @code{.cpp}
...@@ -150,10 +183,14 @@ Explanation ...@@ -150,10 +183,14 @@ Explanation
@endcode @endcode
-# Perform the template matching operation: -# Perform the template matching operation:
@code{.cpp} @code{.cpp}
matchTemplate( img, templ, result, match_method ); bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
if (use_mask && method_accepts_mask)
{ matchTemplate( img, templ, result, match_method, mask); }
else
{ matchTemplate( img, templ, result, match_method); }
@endcode @endcode
the arguments are naturally the input image **I**, the template **T**, the result **R** and the the arguments are naturally the input image **I**, the template **T**, the result **R**, the
match_method (given by the Trackbar) match_method (given by the Trackbar), and optionally the mask image **M**
-# We normalize the results: -# We normalize the results:
@code{.cpp} @code{.cpp}
......
...@@ -13,7 +13,8 @@ using namespace std; ...@@ -13,7 +13,8 @@ using namespace std;
using namespace cv; using namespace cv;
/// Global Variables /// Global Variables
Mat img; Mat templ; Mat result; bool use_mask;
Mat img; Mat templ; Mat mask; Mat result;
const char* image_window = "Source Image"; const char* image_window = "Source Image";
const char* result_window = "Result window"; const char* result_window = "Result window";
...@@ -31,7 +32,7 @@ int main( int argc, char** argv ) ...@@ -31,7 +32,7 @@ int main( int argc, char** argv )
if (argc < 3) if (argc < 3)
{ {
cout << "Not enough parameters" << endl; cout << "Not enough parameters" << endl;
cout << "Usage:\n./MatchTemplate_Demo <image_name> <template_name>" << endl; cout << "Usage:\n./MatchTemplate_Demo <image_name> <template_name> [<mask_name>]" << endl;
return -1; return -1;
} }
...@@ -39,7 +40,12 @@ int main( int argc, char** argv ) ...@@ -39,7 +40,12 @@ int main( int argc, char** argv )
img = imread( argv[1], IMREAD_COLOR ); img = imread( argv[1], IMREAD_COLOR );
templ = imread( argv[2], IMREAD_COLOR ); templ = imread( argv[2], IMREAD_COLOR );
if(img.empty() || templ.empty()) if(argc > 3) {
use_mask = true;
mask = imread( argv[3], IMREAD_COLOR );
}
if(img.empty() || templ.empty() || (use_mask && mask.empty()))
{ {
cout << "Can't read one of the images" << endl; cout << "Can't read one of the images" << endl;
return -1; return -1;
...@@ -76,7 +82,12 @@ void MatchingMethod( int, void* ) ...@@ -76,7 +82,12 @@ void MatchingMethod( int, void* )
result.create( result_rows, result_cols, CV_32FC1 ); result.create( result_rows, result_cols, CV_32FC1 );
/// Do the Matching and Normalize /// Do the Matching and Normalize
matchTemplate( img, templ, result, match_method ); bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
if (use_mask && method_accepts_mask)
{ matchTemplate( img, templ, result, match_method, mask); }
else
{ matchTemplate( img, templ, result, match_method); }
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
/// Localizing the best match with minMaxLoc /// Localizing the best match with minMaxLoc
......
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