script_match_template.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #!/usr/bin/env python
  2. """ match_template.py - Version 1.0 2012-02-28
  3. Find a template image within a test image
  4. """
  5. import cv2.cv as cv
  6. import cv2
  7. import numpy as np
  8. from time import clock
  9. help_message = '''USAGE: pyrdown.py [<template_image>] [<test_image>] [<n_pyr>]
  10. '''
  11. if __name__ == '__main__':
  12. import sys
  13. try:
  14. target_file = sys.argv[1]
  15. test_file = sys.argv[2]
  16. except:
  17. target_file = "test_images/mona_lisa_face.png"
  18. test_file = "test_images/mona_lisa.png"
  19. print help_message
  20. try:
  21. n_pyr = int(sys.argv[3])
  22. except:
  23. n_pyr = 2
  24. # If we don't need different scales and orientations, set this to False
  25. scale_and_rotate = True
  26. show_all_matches = False
  27. ignore_threshold = False
  28. # Match threshold
  29. match_threshold = 0.7
  30. # Smallest template size in pixels we will consider
  31. min_template_size = 75
  32. max_template_size = 250
  33. # What multiplier should we use between adjacent scales
  34. scale_factor = 1.2 # 20% increases
  35. # Read in the template and test image
  36. template = cv2.imread(target_file, cv.CV_LOAD_IMAGE_COLOR)
  37. image = cv2.imread(test_file, cv.CV_LOAD_IMAGE_COLOR)
  38. if scale_and_rotate:
  39. # Compute the min and max scales to use on the template
  40. height_ratio = float(image.shape[0]) / template.shape[0]
  41. width_ratio = float(image.shape[1]) / template.shape[1]
  42. max_scale = 0.9 * min(width_ratio, height_ratio)
  43. max_template_dimension = max(template.shape[0], template.shape[1])
  44. min_scale = 1.2 * float(min_template_size) / max_template_dimension
  45. # Create a list of scales we will use
  46. scales = list()
  47. scale = min_scale
  48. while scale < max_scale:
  49. scales.append(scale)
  50. scale *= scale_factor
  51. if scale * max_template_dimension > max_template_size:
  52. break
  53. # And a set of rotation angles
  54. rotations = [-30, 0, 30]
  55. else:
  56. scales = [1]
  57. rotations = [0]
  58. print "Number of scales:", len(scales)
  59. print "Number of orientations:", len(rotations)
  60. # We need a copy of the original images for later work
  61. template_start = template.copy()
  62. image_copy = image.copy()
  63. # Make sure the template is smaller than the test image
  64. while template_start.shape[0] > image.shape[0] or template_start.shape[1] > image.shape[1]:
  65. template_start = cv2.resize(template_start, (int(0.5 * template_start.shape[0]), int(0.5 * template_start.shape[1])))
  66. # Use pyrDown() n_pyr times on the test image. We only need to do this once for this image.
  67. for i in range(n_pyr):
  68. image_copy = cv2.pyrDown(image_copy)
  69. # Time how long this is going to take
  70. start = clock()
  71. # Track which scale and rotation gives the best match
  72. maxScore = -1
  73. best_s = 1
  74. best_r = 0
  75. best_x = 0
  76. best_y = 0
  77. match_boxes = list()
  78. for s in scales:
  79. for r in rotations:
  80. template_height, template_width = template_start.shape[0], template_start.shape[1]
  81. # Scale the template by s
  82. template_copy = cv2.resize(template_start, (int(template_width * s), int(template_height * s)))
  83. # Rotate the template through r degrees
  84. rotation_matrix = cv2.getRotationMatrix2D((template_copy.shape[1]/2, template_copy.shape[0]/2), r, 1.0)
  85. template_copy = cv2.warpAffine(template_copy, rotation_matrix, (template_copy.shape[1], template_copy.shape[0]), borderMode=cv2.BORDER_REPLICATE)
  86. # Use pyrDown() n_pyr times on the scaled and rotated template
  87. for i in range(n_pyr):
  88. template_copy = cv2.pyrDown(template_copy)
  89. # Store the dimension of the transformed template and image
  90. h,w = template_copy.shape[:2]
  91. H,W = image_copy.shape[:2]
  92. result_width = W - w + 1
  93. result_height = H - h + 1
  94. # Run matchTemplate() on the reduced images
  95. result = cv2.matchTemplate(image_copy, template_copy, cv2.TM_CCOEFF_NORMED)
  96. # Squaring (or even cubing) the result exaggerates the differences
  97. display_result = np.abs(result)**2
  98. # Then do a sub-maximal suppression to emphasize the peaks
  99. #val, result = cv2.threshold(result, 0.01, 0, cv2.THRESH_TOZERO)
  100. # And normalize
  101. #result_normed = cv2.normalize(result, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
  102. # Find the maximum value on the result map
  103. (minValue, maxValue, minLoc, maxLoc) = cv2.minMaxLoc(result)
  104. if show_all_matches and maxValue > match_threshold:
  105. print "Match at: ", maxValue
  106. x, y = maxLoc
  107. x *= int(pow(2.0, n_pyr))
  108. y *= int(pow(2.0, n_pyr))
  109. h,w = template_start.shape[:2]
  110. h = int(h * s)
  111. w = int(w * s)
  112. match_boxes.append(((x + w/2, y + h/2), (w, h), -r))
  113. #cv2.imshow("Tmp Result" + str(r)+str(s), result)
  114. #cv2.imshow("Template" + str(s)+str(r), template_copy)
  115. if maxValue > maxScore:
  116. maxScore = maxValue
  117. best_x, best_y = maxLoc
  118. best_s = s
  119. best_r = r
  120. best_template = template_copy.copy()
  121. best_result = display_result.copy()
  122. # Transform back to original image sizes
  123. best_x *= int(pow(2.0, n_pyr))
  124. best_y *= int(pow(2.0, n_pyr))
  125. h,w = template_start.shape[:2]
  126. h = int(h * best_s)
  127. w = int(w * best_s)
  128. best_match_box = ((best_x + w/2, best_y + h/2), (w, h), -best_r)
  129. print "Best match found at scale:", best_s, "and rotation:", best_r, "and score: ", maxScore
  130. # Stop the clock and print elapsed time
  131. elapsed = (clock() - start) * 1000
  132. print "Time elapsed: ", elapsed, "ms"
  133. best_result = cv2.resize(best_result, (int(pow(2.0, n_pyr)) * best_result.shape[1], int(pow(2.0, n_pyr)) * best_result.shape[0]))
  134. best_template = cv2.resize(best_template, (int(pow(2.0, n_pyr)) * best_template.shape[1], int(pow(2.0, n_pyr)) * best_template.shape[0]))
  135. # Draw a rotated ellipse around the best match location
  136. if show_all_matches and match_boxes:
  137. for match_box in match_boxes:
  138. cv2.ellipse(image, match_box, cv.RGB(255, 255, 50), 2)
  139. if maxScore > match_threshold or ignore_threshold:
  140. cv2.ellipse(image, best_match_box, cv.RGB(50, 255, 50), 4)
  141. #cv2.rectangle(image, (best_x, best_y), (best_x + w, best_y + h), cv.RGB(50, 255, 50), 4)
  142. cv2.imshow("Template", template_start)
  143. cv2.imshow("Test Image", image)
  144. cv2.namedWindow("Correlation", cv.CV_WINDOW_AUTOSIZE)
  145. cv2.imshow("Correlation", best_result)
  146. cv2.imshow("Best Template", best_template)
  147. cv.MoveWindow("Template", 10, 10)
  148. cv.MoveWindow("Test Image", template_start.shape[1] + 20, 10)
  149. cv.MoveWindow("Correlation", template_start.shape[1] + image.shape[1] + 40, 10)
  150. cv2.waitKey()