Title: OpenCV Template Matching ( cv2.matchTemplate ) - PyImageSearch

URL Source: https://pyimagesearch.com/2021/03/22/opencv-template-matching-cv2-matchtemplate/

Published Time: 2021-03-22T14:00:00+00:00

Markdown Content:
In this tutorial, you will learn how to perform template matching using OpenCV and the `cv2.matchTemplate` function.

![Image 1](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20450'%3E%3C/svg%3E)

Other than contour filtering and processing, **template matching is arguably one of the most simple forms of object detection:**

*   It’s simple to implement, requiring only 2-3 lines of code
*   Template matching is computationally efficient
*   It doesn’t require you to perform thresholding, edge detection, etc., to generate a binary image (such as contour detection and processing does)
*   And with a basic extension, template matching can detect _multiple instances_ of the same/similar object in an input image (which we’ll cover next week)

Of course, template matching isn’t _perfect._ Despite all the positives, template matching quickly fails if there are factors of variation in your input images, including changes to rotation, scale, viewing angle, etc.

If your input images contain these types of variations, you _should not_ use template matching — utilize dedicated object detectors including HOG + Linear SVM, Faster R-CNN, SSDs, YOLO, etc.

But in situations where you know the rotation, scale, and viewing angle are constant, template matching can work wonders.

**To learn how to perform template matching with OpenCV,** **_just keep reading._**

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

In the first part of this tutorial, we’ll discuss what template matching is and how OpenCV implements template matching via the `cv2.matchTemplate` function.

From there, we’ll configure our development environment and review our project directory structure.

We’ll then implement template matching with OpenCV, apply it to a few example images, and discuss where it worked well, when it didn’t, and how to improve template matching results.

### **What is template matching?**

![Image 3](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20204'%3E%3C/svg%3E)

**Figure 1:** An example of the template matching pipeline where we take the object/template we want to detect _(left)_, the source image _(middle)_, and then find the template in the source image _(right)_.

Template matching can be seen as a very basic form of object detection. Using template matching, we can detect objects in an input image using a “template” containing the object we want to detect.

Essentially, what this means is that we require two images to apply template matching:

1.  **Source image:** This is the image we expect to find a match to our template in.
2.  **Template image:** The “object patch” we are searching for in the _source image._

To find the template in the source image, we slide the template from left-to-right and top-to-bottom across the source:

![Image 4](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20592%20475'%3E%3C/svg%3E)

**Figure 2:** Applying template matching is as simple as sliding the template from left-to-right and top-to-bottom across the source and computing a metric to indicate how good or bad the match is at each location.

At each _(x, y)_\-location, a metric is calculated to represent how “good” or “bad” the match is. Typically, we use the normalized correlation coefficient to determine how “similar” the pixel intensities of the two patches are:

![Image 5](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20149'%3E%3C/svg%3E)

**Figure 3:** The equation for the normalized correlation coefficient for template matching.

For the full derivation of the correlation coefficient, including all other template matching methods OpenCV supports, [refer to the OpenCV documentation.](https://docs.opencv.org/3.4/de/da9/tutorial_template_matching.html)

For each location _T_ over _I_, the computed result metric is stored in our result matrix _R_. Each _(x, y)_\-coordinate in the source image (that also has a valid width and height for the template image) contains an entry in the result matrix _R_:

![Image 6](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20650%20488'%3E%3C/svg%3E)

**Figure 4:** An example of layering the result matrix, _R,_ over the source image. Notice how the result matrix’s brightest region occurs at the coffee mug’s upper-left corner, thus indicating correlation is at its maximum.

Here, we can visualize our result matrix _R_ overlaid on the original image. Notice how _R_ is **_not_** the same size as the original template. This is because the _entire_ template must fit inside the source image for the correlation to be computed. If the template exceeds the source’s boundaries, we do not compute the similarity metric.

**Bright locations of the result matrix** **_R_** **indicate the best matches, where dark regions indicate there is very little correlation between the source and template images.** Notice how the result matrix’s brightest region appears at the coffee mug’s upper-left corner.

While template matching is extremely simple and computationally efficient to apply, there are many limitations. If there are _any_ object scale variations, rotation, or viewing angle, template matching will likely fail.

In nearly all cases, you’ll want to ensure that the template you are detecting is nearly identical to the object you want to detect in the source. Even small, minor deviations in appearance can dramatically affect template matching results and render it effectively useless.

### **OpenCV’s “cv2.matchTemplate” function**

![Image 7](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20320'%3E%3C/svg%3E)

**Figure 5:** OpenCV’s _“cv2.matchTemplate”_ function is used for template matching.

We can apply template matching using OpenCV and the `cv2.matchTemplate` function:

result = cv2.matchTemplate(image, template, cv2.TM\_CCOEFF\_NORMED)

Here, you can see that we are providing the `cv2.matchTemplate` function with three parameters:

1.  The input `image` that contains the object we want to detect
2.  The `template` of the object (i.e., what we want to detect in the `image`)
3.  The template matching method

Here, we are using the normalized correlation coefficient, which is typically the template matching method you’ll want to use, [but OpenCV supports other template matching methods as well.](https://docs.opencv.org/3.4/de/da9/tutorial_template_matching.html)

The output `result` from `cv2.matchTemplate` is a matrix with spatial dimensions:

*   **Width:** `image.shape[1] - template.shape[1] + 1`
*   **Height:** `image.shape[0] - template.shape[0] + 1`

We can then find the location in the `result` that has the maximum correlation coefficient, which corresponds to the most likely region that the template can be found in (which you’ll learn how to do later in this tutorial).

It’s also worth noting that if you wanted to detect objects within only a _specific_ region of an input image, you could supply a mask, like the following:

result = cv2.matchTemplate(image, template, cv2.TM\_CCOEFF\_NORMED, mask)

The `mask` must have the same spatial dimensions and data type as the `template`. For regions of the input `image` you _don’t_ want to be searched, the `mask` should be set to zero. For regions of the `image` you want to be searched, be sure the `mask` has a corresponding value of `255`.

### **Configuring your development environment**

To follow this guide, you need to have the OpenCV library installed on your system.

Luckily, OpenCV is pip-installable:

$ pip install opencv-contrib-python

**If you need help configuring your development environment for OpenCV, I _highly recommend_ that you read my** [**_pip install OpenCV_ guide**](https://pyimagesearch.com/2018/09/19/pip-install-opencv/) — it will have you up and running in a matter of minutes.

### **Having problems configuring your development environment?**

[![Image 8](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20500%20334'%3E%3C/svg%3E)](https://pyimagesearch.com/pyimagesearch-plus/)

**Figure 6:** Having trouble configuring your dev environment? Want access to pre-configured Jupyter Notebooks running on Google Colab? Be sure to join [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-plus/) — you’ll be up and running with this tutorial in a matter of minutes.

All that said, are you:

*   Short on time?
*   Learning on your employer’s administratively locked system?
*   Wanting to skip the hassle of fighting with the command line, package managers, and virtual environments?
*   **Ready to run the code _right now_ on your Windows, macOS, or Linux systems?**

Then join [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-plus/) today!

**Gain access to Jupyter Notebooks for this tutorial and other PyImageSearch guides that are** **_pre-configured_** **to run on Google Colab’s ecosystem right in your web browser!** No installation required.

And best of all, these Jupyter Notebooks will run on Windows, macOS, and Linux!

### **Project structure**

Before we get too far, let’s review our project directory structure.

Start by accessing the **_“Downloads”_** section of this tutorial to retrieve the source code and example images.

Your directory should look like the following:

$ tree . --dirsfirst
.
├── images
│   ├── 8\_diamonds.png
│   ├── coke\_bottle.png
│   ├── coke\_bottle\_rotated.png
│   ├── coke\_logo.png
│   └── diamonds\_template.png
└── single\_template\_matching.py

1 directory, 6 files

We have a single Python script to review today, `single_template_matching.py`, which will perform template matching with OpenCV.

Inside the `images` directory, we have five images to which we’ll be applying template matching. We’ll see each of these images later in the tutorial.

### **Implementing template matching with OpenCV**

With our project directory structure reviewed, let’s move on to implementing template matching with OpenCV.

Open the `single_template_matching.py` file in your directory structure and insert the following code:

\# import the necessary packages
import argparse
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--image", type=str, required=True,
	help="path to input image where we'll apply template matching")
ap.add\_argument("-t", "--template", type=str, required=True,
	help="path to template image")
args = vars(ap.parse\_args())

On **Lines 2 and 3,** we import our required Python packages. We only need `argparse` for command line argument parsing and `cv2` for our OpenCV bindings.

From there, we move on to parsing our command line arguments:

1.  `--image`: The path to the input image on disk that we’ll be applying template matching to (i.e., the image we want to detect objects in).
2.  `--template`: The example template image we want to find instances of in the input image.

Next, let’s prepare our image and template for template matching:

\# load the input image and template image from disk, then display
# them on our screen
print("\[INFO\] loading images...")
image = cv2.imread(args\["image"\])
template = cv2.imread(args\["template"\])
cv2.imshow("Image", image)
cv2.imshow("Template", template)

# convert both the image and template to grayscale
imageGray = cv2.cvtColor(image, cv2.COLOR\_BGR2GRAY)
templateGray = cv2.cvtColor(template, cv2.COLOR\_BGR2GRAY)

We start by loading our `image` and `template`, then displaying them on our screen.

Template matching is typically applied to grayscale images, so **Lines 22 and 23** convert the image to grayscale.

Next, all that needs to be done is call `cv2.matchTemplate`:

\# perform template matching
print("\[INFO\] performing template matching...")
result = cv2.matchTemplate(imageGray, templateGray,
	cv2.TM\_CCOEFF\_NORMED)
(minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(result)

**Lines 27 and 28** perform template matching itself via the `cv2.matchTemplate` function. We pass in three required arguments to this function:

1.  The input image that we want to find objects in
2.  The template image of the object we want to detect in the input image
3.  The template matching method

Typically the normalized correlation coefficient (`cv2.TM_CCOEF_NORMED`) works well in most situations, [but you can refer to the OpenCV documentation for more details on other template matching methods.](https://docs.opencv.org/3.4/de/da9/tutorial_template_matching.html)

Once we’ve applied the `cv2.matchTemplate`, we receive a `result` matrix with the following spatial dimensions:

*   **Width:** `image.shape[1] - template.shape[1] + 1`
*   **Height:** `image.shape[0] - template.shape[0] + 1`

The `result` matrix will have a _large value_ (closer to `1`), where there is _more likely_ to be a template match. Similarly, the `result` matrix will have a _small value_ (closer to `0`), where matches are _less likely_.

To find the location with the largest value, and therefore the most likely match, we make a call to `cv2.minMaxLoc` (**Line 29**), passing in the `result` matrix.

Once we have the _(x, y)_\-coordinates of the location with the largest normalized correlation coefficient (`maxLoc`), we can extract the coordinates and derive the bounding box coordinates:

\# determine the starting and ending (x, y)-coordinates of the
# bounding box
(startX, startY) = maxLoc
endX = startX + template.shape\[1\]
endY = startY + template.shape\[0\]

**Line 33** extracts the starting _(x, y)_\-coordinates from our `maxLoc`, derived from calling `cv2.minMaxLoc` in the previous codeblock.

Using the `startX` and `endX` coordinates, we can derive the `endX` and `endY` coordinates on **Lines 34 and 35** by adding the template width and height to the `startX` and `endX` coordinates, respectively.

The final step is to draw the detected bounding box on the `image`:

\# draw the bounding box on the image
cv2.rectangle(image, (startX, startY), (endX, endY), (255, 0, 0), 3)

# show the output image
cv2.imshow("Output", image)
cv2.waitKey(0)

A call to `cv2.rectangle` on **Line 38** draws the bounding box on the image.

**Lines 41 and 42** then show our output `image` on our screen.

### **OpenCV template matching results**

We are now ready to apply template matching with OpenCV!

Access the **_“Downloads”_** section of this tutorial to retrieve the source code and example images.

From there, open a terminal and execute the following command:

$ python single\_template\_matching.py --image images/coke\_bottle.png \\
	--template images/coke\_logo.png
\[INFO\] loading images...
\[INFO\] performing template matching...

In this example, we have an input image containing a Coca-Cola bottle:

![Image 9](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20500%20500'%3E%3C/svg%3E)

**Figure 7:** Our example input image.

Our goal is to detect the Coke logo in the image:

![Image 10](https://b2633864.smushcdn.com/2633864/wp-content/uploads/2021/02/template_matching_coke_logo.png?lossy=2&strip=1&webp=1)

**Figure 8:** The template image containing the Coke logo. Our goal is to detect the Coke logo in the input image.

By applying OpenCV and the `cv2.matchTemplate` function, we can correctly localize _where_ in the `coke_bottle.png` image the `coke_logo.png` image is:

![Image 11](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20458%20475'%3E%3C/svg%3E)

**Figure 9:** Successfully applying template matching with OpenCV.

This method works because the Coca-Cola logo in `coke_logo.png` is the same size (in terms of scale) as the logo in `coke_bottle.png`. Similarly, the logos are viewed at the same viewing angle and are not rotated.

If the logos differed in scale or the viewing angle was different, the method would fail.

For example, let’s try this example image, but this time I have rotated the Coca-Cola bottle slightly and scaled the bottle down:

$ python single\_template\_matching.py \\
	--image images/coke\_bottle\_rotated.png \\
	--template images/coke\_logo.png
\[INFO\] loading images...
\[INFO\] performing template matching...

![Image 12](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20311'%3E%3C/svg%3E)

**Figure 10:** _Left:_ An input image containing the same Coca-Cola bottle, but this image has been rotated and slightly scaled down. _Middle:_ The template image we want to detect in the _left_ image. _Right:_ Output of applying template matching. Notice how we’ve failed to detect the Coca-Cola logo successfully.

Notice how we have a false-positive detection! We have failed to detect the Coca-Cola logo now that the scale and rotation are different.

**The key point here is that template matching is** **_tremendously sensitive_** **to changes in rotation, viewing angle, and scale.** When that happens, you may need to apply more advanced object detection techniques.

In the following example, we’re working with a deck of cards and are trying to detect the “diamond” symbols on the eight of diamonds playing card:

$ python single\_template\_matching.py --image images/8\_diamonds.png \\
	--template images/diamonds\_template.png 
\[INFO\] loading images...
\[INFO\] performing template matching...

![Image 13](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20406'%3E%3C/svg%3E)

**Figure 11:** _Left:_ Input image containing a template of a “diamond.” _Middle:_ The template of a “diamond” that we want to detect in the _left_ image. _Right:_ Output of applying basic template matching with OpenCV. Standard template matching is _not_ designed to handle multiple detections.

On the _left,_ we have our `diamonds_template.png` image. We use OpenCV and the `cv2.matchTemplate` function to find all the diamond symbols _(right)_…

…but what happened here?

**Why haven’t all the diamond symbols been detected?**

The answer is that the `cv2.matchTemplate` function, by itself, _cannot detect multiple objects!_

There is a solution, though — and I’ll be covering multi-template matching with OpenCV in next week’s tutorial.

### **A note on false-positive detections with template matching**

You’ll note that in our rotated Coca-Cola logo example, we failed to detect the Coke logo; however, our code still “reported” that the logo was found:

![Image 14](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20311'%3E%3C/svg%3E)

**Figure 12:** Failing to detect the Coca-Cola logo using template matching.

Keep in mind that the `cv2.matchTemplate` function _truly has no idea_ if the object was correctly found or not — it’s simply sliding the template image across the input image, computing a normalized correlation score, and then returning the location where the score is the largest.

Template matching is an example of a “dumb algorithm.” There’s _no_ machine learning going on, and it has _no idea_ what is in the input image.

To filter out false-positive detections, you should grab the `maxVal` and use an `if` statement to filter out scores that are below a certain threshold.

### **Credits and References**

I would like to thank TheAILearner for [their excellent article on template matching](https://theailearner.com/2020/12/12/template-matching-using-opencv/) — I cannot take credit for the idea of using playing cards to demonstrate template matching. That was their idea, and it was an excellent one at that. Credits to them for coming up with that example, which I shamelessly used here, thank you.

Additionally, the eight of diamonds image was obtained from the [Reddit post](https://www.reddit.com/r/mildlyinfuriating/comments/91bqun/this_8_of_diamonds_card_has_10_diamonds_on_it/) by u/fireball\_73.

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

**Summary**
-----------

In this tutorial, you learned how to perform template matching using OpenCV and the `cv2.matchTemplate` function.

Template matching is a basic form of object detection. It’s very fast and efficient, but the downside is that it fails when the rotation, scale, or viewing angle of an object changes — when that happens, you need a more advanced object detection technique.

Nevertheless, suppose you can control the scale or normalize the scale of objects in the environment where you are capturing photos. In that case, you could potentially get away with template matching and avoid the tedious task of labeling your data, training an object detector, and tuning its hyperparameters.

**To download the source code to this post (and be notified when future tutorials are published here on PyImageSearch), _simply enter your email address in the form below!_**

![Image 15](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and a **FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.** Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!