Advertisement
Guest User

Untitled

a guest
Apr 26th, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.46 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Harris Corner Detector
  4. #
  5. # Finds the interest points between two images
  6. # Gets the response matrix built with descriptors which can be used to find matches
  7. # RANSAC used to remove outliers
  8. # Stiches new image
  9. #
  10. # Authors: Raj Sha (13104195)
  11. # Ian Lodovica (13131567)
  12. # Oran Murray (12134228)
  13.  
  14. import sys
  15. import numpy as np
  16. from scipy.ndimage import filters
  17. from PIL import Image
  18. import matplotlib.pylab as pyl
  19.  
  20.  
  21. def harris_matrix_algorithm(img, sigma=2):
  22. """ step 1.1 - algorithm to compute harris corner detector response matrix """
  23.  
  24. ix = np.zeros(img.shape)
  25. filters.gaussian_filter(img, 1, (0, 1), output=ix) # (1,1) -> (sigma,sigma)
  26. iy = np.zeros(img.shape)
  27. filters.gaussian_filter(img, 1, (1, 0), output=iy) # (1,1) -> (sigma,sigma)
  28.  
  29. # compute components of the Harris matrix
  30. A = filters.gaussian_filter(ix * ix, sigma)
  31. B = filters.gaussian_filter(ix * iy, sigma)
  32. C = filters.gaussian_filter(iy * iy, sigma)
  33.  
  34. # calculate trace and determinant
  35. det_M = (A * C) - (B ** 2)
  36. tr_M = (A + C)
  37.  
  38. # return response matrix R
  39. return det_M / tr_M
  40.  
  41.  
  42. def get_harris_interest_points(harris_im, min_distance=10, threshold=0.1):
  43. """ step 1.2 - select Harris corner points above a threshold and perform nonmax
  44. suppression in a region +/- min_distance.
  45. min_distance is the minimum number of pixels separating corner and image boundary (spec = 11)"""
  46.  
  47. # find top corner candidates above a threshold
  48. corner_threshold = harris_im.max() * threshold
  49. harris_im_th = (harris_im > corner_threshold) # expect True/False
  50.  
  51. # find the co-ordinates of these candidates
  52. coords = np.array(harris_im_th.nonzero()).T
  53. # and their values
  54. candidate_values = np.array([harris_im[c[0], c[1]] for c in coords])
  55. indices = np.argsort(candidate_values)
  56.  
  57. # store allowed point locations in a boolean image
  58. allowed_locations = np.zeros(harris_im.shape, dtype='bool')
  59. allowed_locations[min_distance:-min_distance, min_distance:-min_distance] = True
  60.  
  61. # select best points, using nonmax suppression based on allowed_locations array (taking min_distance into account)
  62. filtered_coords = []
  63. for i in indices[::-1]: # back to front
  64. r, c = coords[i] # note reversed indices
  65. if allowed_locations[r, c]:
  66. filtered_coords.append((r, c))
  67. allowed_locations[r - min_distance:r + min_distance + 1, c - min_distance:c + min_distance + 1] = False
  68.  
  69. return filtered_coords
  70.  
  71.  
  72. def plot_harris_interest_points(img, hips):
  73. """ plot interest points """
  74. pyl.figure('Harris points/corners')
  75. pyl.imshow(img, cmap='gray')
  76. pyl.plot([p[1] for p in hips], [p[0] for p in hips], 'ro')
  77. pyl.axis('off')
  78. pyl.show()
  79.  
  80.  
  81. def descriptors(img, hips, wid=5):
  82. """ step 2 - return pixel values around harris interest points using width 2*wid+1 (=11, as per spec) """
  83.  
  84. descriptor = []
  85. for coords in hips:
  86. patch = img[coords[0] - wid:coords[0] + wid + 1, coords[1] - wid:coords[1] + wid + 1].flatten()
  87. # mean must be subtracted first then divided by norm
  88. # doing all in one line caused errors
  89. patch -= np.mean(patch)
  90. patch /= np.linalg.norm(patch)
  91. descriptor.append(patch)
  92.  
  93. return descriptor
  94.  
  95.  
  96. def match(descriptor1, descriptor2, threshold=0.95):
  97. # convert descriptors to arrays
  98. m1 = np.asarray(descriptor1, dtype=np.float32)
  99. m2 = np.asarray(descriptor2, dtype=np.float32).T
  100.  
  101. # calculate the response matrix by finding the inner product
  102. response_matrix = np.dot(m1, m2)
  103. print "Max is: " + str(m1.max())
  104. print "Max is: " + str(m2.max())
  105. print "Max is: " + str(response_matrix.max())
  106. img = Image.fromarray(response_matrix * 255)
  107. pairs = []
  108. for r in range(response_matrix.shape[0]):
  109. row_max = response_matrix[r][0]
  110.  
  111. for c in range(response_matrix.shape[1]):
  112. # pick only one
  113. if response_matrix[r][c] > threshold and response_matrix[r][c] > row_max:
  114. pairs.append((r, c))
  115. else:
  116. response_matrix[r][c] = 0
  117.  
  118. # plot a comparison between the response matrix before and after
  119. # it was updated
  120. img2 = Image.fromarray(response_matrix * 255)
  121. pyl.subplot(121)
  122. pyl.imshow(img)
  123. pyl.subplot(122)
  124. pyl.imshow(img2)
  125. pyl.show()
  126. return pairs
  127.  
  128.  
  129. def plot_matches(image1, image2, hips_image1, hips_image2, pairs):
  130. """ step 3.3 - output a concatenation of images (appended side by side) showing the 'true' matches between points. """
  131. rows1 = image1.shape[0]
  132. rows2 = image2.shape[0]
  133.  
  134. # select image with least rows and pad accordingly (wrt to larger image)
  135. if rows1 < rows2:
  136. image1 = np.concatenate((image1, np.zeros((rows2 - rows1, image1.shape[1]))), axis=0)
  137. elif rows2 < rows1:
  138. image2 = np.concatenate((image2, np.zeros((rows1 - rows2, image2.shape[1]))), axis=0)
  139.  
  140. # create new image with two input images appended side-by-side, then plot matches
  141. image3 = np.concatenate((image1, image2), axis=1)
  142.  
  143. pyl.figure('Both images side by side with matches plotted') # note incorrect matches! - use RANSAC
  144. pyl.imshow(image3, cmap="gray")
  145. column1 = image1.shape[1]
  146.  
  147. for i in range(len(pairs)):
  148. index1, index2 = pairs[i]
  149. pyl.plot([hips_image1[index1][1], hips_image2[index2][1] + column1],
  150. [hips_image1[index1][0], hips_image2[index2][0]], 'c')
  151. pyl.axis('off')
  152. pyl.show()
  153.  
  154.  
  155. def basic_RANSAC(matches, coord_list1, coord_list2, match_dist=1.6):
  156. """Carry out a simple version of the RANSAC procedure for calculating
  157. the appropriate translation needed to map image 2 onto image 1.
  158. N.B., this isn't true RANSAC because it doesn't carry out *random*
  159. consensus, instead it works exhaustively: for each offset in the
  160. list of possible offsets it checks to see how many other offsets
  161. agree with it (that point's consensus set), then returns the average
  162. offset of all the points in the largest consensus set. Hence it is
  163. not performing *random* consensus, but rather *exhaustive*
  164. consensus.
  165.  
  166. matches - List of matches, i.e., index pairs, (i1,i2). i1 is the
  167. index of the matching coordinate from coord_list1 and i2 the index
  168. of the coordinate in coord_list2 that it matches. This list of
  169. matches is generated by a previous call to "match".
  170.  
  171. coord_list1, coord_list2 -- lists of interest point coordinates in
  172. the first and second images.
  173.  
  174. match_dist -- maximum distance between offsets for them to be
  175. considered part of a consensus set.
  176.  
  177. Returns -- (row_offset,column_offset,match_count) -- a tuple,
  178. the first two elements are the best_offset relating the second image to
  179. the first, the third is the number of point-pairs supporting this
  180. offset according to this "Exhaustive RANSAC" matcher, i.e., the
  181. "strength" of this offset.
  182. """
  183. d2 = match_dist ** 2 ## Square the match distance.
  184. ## Build a list of offsets from the lists of matching points for the
  185. ## first and second images.
  186. offsets = np.zeros((len(matches), 2))
  187. for i in range(len(matches)):
  188. index1, index2 = matches[i]
  189. offsets[i, 0] = coord_list1[index1][0] - coord_list2[index2][0]
  190. offsets[i, 1] = coord_list1[index1][1] - coord_list2[index2][1]
  191.  
  192. ## Run the comparison. best_match_count keeps track of the size of the
  193. ## largest consensus set, and (best_row_offset,best_col_offset) the
  194. ## current offset associated with the largest consensus set found so far.
  195. best_match_count = -1
  196. best_row_offset, best_col_offset = 1e6, 1e6
  197. for i in range(len(offsets)):
  198. match_count = 1.0
  199. offi0 = offsets[i, 0]
  200. offi1 = offsets[i, 1]
  201. ## Only continue into j loop looking for consensus if this point hasn't
  202. ## been found and folded into a consensus set earlier. Just improves
  203. ## efficiency.
  204. if (offi0 - best_row_offset) ** 2 + (offi1 - best_col_offset) ** 2 >= d2:
  205. sum_row_offsets, sum_col_offsets = offi0, offi1
  206. for j in range(len(matches)):
  207. if j != i:
  208. offj0 = offsets[j, 0]
  209. offj1 = offsets[j, 1]
  210. if (offi0 - offj0) ** 2 + (offi1 - offj1) ** 2 < d2:
  211. sum_row_offsets += offj0
  212. sum_col_offsets += offj1
  213. match_count += 1.0
  214. if match_count >= best_match_count:
  215. best_row_offset = sum_row_offsets / match_count
  216. best_col_offset = sum_col_offsets / match_count
  217. best_match_count = match_count
  218. return best_row_offset, best_col_offset, best_match_count
  219.  
  220.  
  221. def appendimage(image1, image2, row_offset, col_offset):
  222. row_offset = int(row_offset)
  223. col_offset = int(col_offset)
  224. height_1, width_1 = image1.size
  225. canvas = Image.new(image1.mode, (width_1 + abs(col_offset), width_1 + abs(row_offset)))
  226. height_c, width_c = canvas.size
  227. canvas.paste(image1, (0, height_c - height_1))
  228. canvas.paste(image2, (col_offset, height_c - height_1 + row_offset))
  229.  
  230. pyl.figure('Final Composite Image')
  231. pyl.imshow(canvas)
  232. pyl.axis('off')
  233. pyl.show()
  234.  
  235. # load images (accept cmdline arguments) # pass the two images with .py at cmd
  236. print "Loading images..."
  237. image1 = np.array(Image.open(sys.argv[1]).convert('L'), dtype=np.float32)
  238. image2 = np.array(Image.open(sys.argv[2]).convert('L'), dtype=np.float32)
  239. print "Done."
  240.  
  241. # Step 1 - Find HIPS by computing and thresholding harris response matrix
  242. print "Retrieving harris images"
  243. harris_image1 = harris_matrix_algorithm(image1, 2) # sigma = 2
  244. harris_image2 = harris_matrix_algorithm(image2, 2) # sigma = 2
  245.  
  246. # plot the harris response
  247. pyl.subplot(121)
  248. pyl.imshow(harris_image1, cmap="gray")
  249. pyl.subplot(122)
  250. pyl.imshow(harris_image2, cmap="gray")
  251. pyl.show()
  252.  
  253. print "Finding interest points"
  254. hips_image1 = get_harris_interest_points(harris_image1, min_distance=10, threshold=0.1)
  255. hips_image2 = get_harris_interest_points(harris_image2, min_distance=10, threshold=0.1)
  256. print "Interest Points (img1): " + str(len(hips_image1))
  257. print "Interest Points (img2): " + str(len(hips_image2))
  258.  
  259. print "Plotting interest points"
  260. plot_harris_interest_points(image1, hips_image1)
  261. plot_harris_interest_points(image2, hips_image2)
  262.  
  263. # Step 2 - Form normalised patch descriptor vectors for all HIPScompute feature locations/descriptors
  264. print "Developing descriptors"
  265. descriptor1 = descriptors(image1, hips_image1)
  266. descriptor2 = descriptors(image2, hips_image2)
  267.  
  268. # Step 3 - Match descriptors -> plot all matching descriptors
  269. print "Matching descriptors"
  270. pairs = match(descriptor1, descriptor2)
  271.  
  272. # matches = match_stabilised(descriptor1, descriptor2)
  273. plot_matches(image1, image2, hips_image1, hips_image2, pairs)
  274.  
  275. # Step 4 - Exhaustive RANSAC
  276. row_offset, col_offset, best_matchcount = basic_RANSAC(pairs, hips_image1, hips_image2)
  277. print '--Exhaustive RANSAC--'
  278. print 'Number of agreements (best match count): %d' % best_matchcount
  279. print 'Row offset: %d' % row_offset
  280. print 'Column offset: %d' % col_offset
  281.  
  282. # Step 5 - Create composite image using RANSAC translation
  283. image1_rgb = Image.open(sys.argv[1])
  284. image2_rgb = Image.open(sys.argv[2])
  285. appendimage(image1_rgb, image2_rgb, int(row_offset), int(col_offset))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement