AKA Math commited on
Commit
c5d647f
·
1 Parent(s): a36a809

initial version

Browse files
Files changed (5) hide show
  1. .gitignore +2 -0
  2. README.md +18 -1
  3. packages.txt +3 -0
  4. requirements.txt +7 -0
  5. template-matching-demo.py +131 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ venv/*
2
+ .vscode*
README.md CHANGED
@@ -1,2 +1,19 @@
1
  # template-matching
2
- This is a simple streamlit + OpenCV demonstration of template matching.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # template-matching
2
+
3
+ This is a demonstration of how template matching works by computing correlation between the search space and the template.
4
+
5
+ [Click here to run this on Streamlit](https://tinyurl.com/template-matching).
6
+
7
+ ## What is Template Matching?
8
+
9
+ *
10
+
11
+ ## What situations could this method be applied to?
12
+
13
+ *
14
+
15
+ ## When would it not work?
16
+
17
+ *
18
+
19
+ ## Are there better similarity measures than correlation?
packages.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ freeglut3-dev
2
+ libgtk2.0-dev
3
+ libgl1-mesa-glx
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ pip==21.3.1
2
+ setuptools==60.2.0
3
+ wheel==0.37.1
4
+ opencv-python-headless
5
+ streamlit
6
+ Pillow
7
+ numpy
template-matching-demo.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Inspired by https://www.loginradius.com/blog/engineering/guest-post/opencv-web-app-with-streamlit/
3
+ """
4
+
5
+ import numpy as np
6
+ import cv2 as cv
7
+ import streamlit as st
8
+
9
+
10
+ def compute_correlation(scene: np.array, template: np.array):
11
+ """
12
+ COMPUTE_CORRELATION computes the correlation between the pixels in scene and template
13
+ when the center of template is placed at location (x, y) on the scene. (x, y) is assumed
14
+ to be within bounds of the scene - this function doesn't check for out of bounds.
15
+ """
16
+ gray_scene = cv.cvtColor(scene, cv.COLOR_BGR2GRAY)
17
+ cv.normalize(gray_scene, gray_scene, 0, 255, cv.NORM_MINMAX)
18
+
19
+ gray_template = cv.cvtColor(template, cv.COLOR_BGR2GRAY)
20
+ cv.normalize(gray_template, gray_template, 0, 255, cv.NORM_MINMAX)
21
+
22
+ res = cv.matchTemplate(gray_scene, gray_template, cv.TM_CCOEFF_NORMED)
23
+ return res
24
+
25
+
26
+ def overlay_correlation(scene: np.array, corr: np.array, template: np.array, x: int, y: int):
27
+ pass
28
+
29
+
30
+ def main_loop():
31
+ """
32
+ MAIN_LOOP is the main loop (duh) for this streamlit App.
33
+ """
34
+
35
+ st.set_page_config(layout="wide")
36
+
37
+ st.title("Template Matching Demo")
38
+ st.subheader(
39
+ "This app demonstrates how a template matching algorithm works: by sliding the template across the scene!")
40
+
41
+ template_image = cv.imread('waldo-template.jpeg')
42
+ template_image = cv.cvtColor(template_image, cv.COLOR_BGR2RGB)
43
+
44
+ st.markdown(
45
+ "To introduce this method, let's first get introduced to our protagonist - Waldo")
46
+
47
+ st.text("Introducing Waldo!")
48
+ st.image(template_image, width=100)
49
+
50
+ st.markdown(
51
+ "Now for the fun bit - can you find Waldo in the scene below? Most of us will take about 20 seconds, if not more!")
52
+
53
+ scene_image = cv.imread("waldo-scene.jpeg")
54
+ scene_image = cv.cvtColor(scene_image, cv.COLOR_BGR2RGB)
55
+
56
+ st.text("Can you find Waldo?")
57
+ st.image(scene_image, width=1000)
58
+
59
+ st.markdown(
60
+ "Can a computer do better? Certainly. The template matching algorithm is conceptually really simple.")
61
+ st.markdown(
62
+ "The idea is to hold the template over all possible patches in the scene, and then compute a similarity.")
63
+ st.markdown(
64
+ "Naturally, the similarity will be the highest when the template matches what's in the patch underneath.")
65
+ st.markdown(
66
+ "We could then record the location of the maximum similarity, and return it when we have scanned everywhere.")
67
+
68
+ corr = compute_correlation(scene_image, template_image)
69
+ norm_corr = (corr - corr.min()) / (corr.max() - corr.min())
70
+ st.text("Here's the correlation image:")
71
+ st.image(norm_corr, width=1000)
72
+
73
+ result_image = scene_image.copy()
74
+ threshold = 0.6
75
+ # finding the values where it exceeds the threshold
76
+ loc = np.where(corr >= threshold)
77
+ template_shape = template_image.shape[::-1]
78
+ for pt in zip(*loc[::-1]):
79
+ # draw rectangle on places where it exceeds threshold
80
+ cv.rectangle(
81
+ result_image, pt, (pt[0] + template_shape[1], pt[1] + template_shape[2]), (0, 255, 0), 2)
82
+
83
+ st.text("Here's the result:")
84
+ st.image(result_image, width=1000)
85
+
86
+ st.markdown("How does this work? The template slides across the scene, and \
87
+ computes the correlation at each location. Use the slider below \
88
+ to see how this works!")
89
+
90
+ alpha = st.slider('Move to slide the template', 0.0,
91
+ 1.0, value=0.00, step=0.0001)
92
+ scene_image = scene_image * 0.25
93
+ scene_image = scene_image.astype(np.uint8)
94
+
95
+ norm_corr = cv.copyMakeBorder(norm_corr,
96
+ template_shape[2]//2, template_shape[2]//2,
97
+ template_shape[1]//2, template_shape[1]//2,
98
+ cv.BORDER_CONSTANT)
99
+ norm_corr = cv.multiply(255.0, norm_corr)
100
+ norm_corr = np.dstack((norm_corr, norm_corr, norm_corr))
101
+
102
+ out_image = scene_image.copy()
103
+ out_shape = out_image.shape # H, W, 3
104
+ print(out_shape)
105
+ print(template_shape) # 3, W, H
106
+ range_movement = (out_shape[1] - template_shape[1]) * \
107
+ (out_shape[0] - template_shape[2])
108
+
109
+ absolute_loc = np.int32(alpha * range_movement)
110
+ absolute_loc_y = absolute_loc // (out_shape[1] - template_shape[1])
111
+ absolute_loc_x = absolute_loc % (out_shape[0] - template_shape[2])
112
+ out_image[0:absolute_loc_y, :, :] = norm_corr[0:absolute_loc_y, :, :]
113
+
114
+ out_image[absolute_loc_y:(absolute_loc_y + template_shape[2]),
115
+ absolute_loc_x:(absolute_loc_x + template_shape[1]), :] = template_image
116
+
117
+ if absolute_loc_y > (pt[1] + template_shape[2]):
118
+ for pt in zip(*loc[::-1]):
119
+ # draw rectangle on places where it exceeds threshold
120
+ cv.rectangle(
121
+ out_image, pt, (pt[0] + template_shape[1], pt[1] + template_shape[2]), (0, 255, 0), 2)
122
+
123
+ st.text("Here's how the correlation is computed:")
124
+ st.image(out_image, width=1000)
125
+
126
+ st.markdown("Image copyrights for Where is Waldo - fully attributed to original owners. \
127
+ It is used here purely for educational purposes.")
128
+
129
+
130
+ if __name__ == '__main__':
131
+ main_loop()