Advertisement
Guest User

Untitled

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