anchors.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import numpy as np
  2. class AnchorBox():
  3. def __init__(self, input_shape, min_size, max_size=None, aspect_ratios=None, flip=True):
  4. self.input_shape = input_shape
  5. self.min_size = min_size
  6. self.max_size = max_size
  7. self.aspect_ratios = []
  8. for ar in aspect_ratios:
  9. self.aspect_ratios.append(ar)
  10. self.aspect_ratios.append(1.0 / ar)
  11. def call(self, layer_shape, mask=None):
  12. # --------------------------------- #
  13. # 获取输入进来的特征层的宽和高
  14. # 比如38x38
  15. # --------------------------------- #
  16. layer_height = layer_shape[0]
  17. layer_width = layer_shape[1]
  18. # --------------------------------- #
  19. # 获取输入进来的图片的宽和高
  20. # 比如300x300
  21. # --------------------------------- #
  22. img_height = self.input_shape[0]
  23. img_width = self.input_shape[1]
  24. box_widths = []
  25. box_heights = []
  26. # --------------------------------- #
  27. # self.aspect_ratios一般有两个值
  28. # [1, 1, 2, 1/2]
  29. # [1, 1, 2, 1/2, 3, 1/3]
  30. # --------------------------------- #
  31. for ar in self.aspect_ratios:
  32. # 首先添加一个较小的正方形
  33. if ar == 1 and len(box_widths) == 0:
  34. box_widths.append(self.min_size)
  35. box_heights.append(self.min_size)
  36. # 然后添加一个较大的正方形
  37. elif ar == 1 and len(box_widths) > 0:
  38. box_widths.append(np.sqrt(self.min_size * self.max_size))
  39. box_heights.append(np.sqrt(self.min_size * self.max_size))
  40. # 然后添加长方形
  41. elif ar != 1:
  42. box_widths.append(self.min_size * np.sqrt(ar))
  43. box_heights.append(self.min_size / np.sqrt(ar))
  44. # --------------------------------- #
  45. # 获得所有先验框的宽高1/2
  46. # --------------------------------- #
  47. box_widths = 0.5 * np.array(box_widths)
  48. box_heights = 0.5 * np.array(box_heights)
  49. # --------------------------------- #
  50. # 每一个特征层对应的步长
  51. # --------------------------------- #
  52. step_x = img_width / layer_width
  53. step_y = img_height / layer_height
  54. # --------------------------------- #
  55. # 生成网格中心
  56. # --------------------------------- #
  57. linx = np.linspace(0.5 * step_x, img_width - 0.5 * step_x,
  58. layer_width)
  59. liny = np.linspace(0.5 * step_y, img_height - 0.5 * step_y,
  60. layer_height)
  61. centers_x, centers_y = np.meshgrid(linx, liny)
  62. centers_x = centers_x.reshape(-1, 1)
  63. centers_y = centers_y.reshape(-1, 1)
  64. # 每一个先验框需要两个(centers_x, centers_y),前一个用来计算左上角,后一个计算右下角
  65. num_anchors_ = len(self.aspect_ratios)
  66. anchor_boxes = np.concatenate((centers_x, centers_y), axis=1)
  67. anchor_boxes = np.tile(anchor_boxes, (1, 2 * num_anchors_))
  68. # 获得先验框的左上角和右下角
  69. anchor_boxes[:, ::4] -= box_widths
  70. anchor_boxes[:, 1::4] -= box_heights
  71. anchor_boxes[:, 2::4] += box_widths
  72. anchor_boxes[:, 3::4] += box_heights
  73. # --------------------------------- #
  74. # 将先验框变成小数的形式
  75. # 归一化
  76. # --------------------------------- #
  77. anchor_boxes[:, ::2] /= img_width
  78. anchor_boxes[:, 1::2] /= img_height
  79. anchor_boxes = anchor_boxes.reshape(-1, 4)
  80. anchor_boxes = np.minimum(np.maximum(anchor_boxes, 0.0), 1.0)
  81. return anchor_boxes
  82. #---------------------------------------------------#
  83. # 用于计算共享特征层的大小
  84. #---------------------------------------------------#
  85. def get_vgg_output_length(height, width):
  86. filter_sizes = [3, 3, 3, 3, 3, 3, 3, 3]
  87. padding = [1, 1, 1, 1, 1, 1, 0, 0]
  88. stride = [2, 2, 2, 2, 2, 2, 1, 1]
  89. feature_heights = []
  90. feature_widths = []
  91. for i in range(len(filter_sizes)):
  92. height = (height + 2*padding[i] - filter_sizes[i]) // stride[i] + 1
  93. width = (width + 2*padding[i] - filter_sizes[i]) // stride[i] + 1
  94. feature_heights.append(height)
  95. feature_widths.append(width)
  96. return np.array(feature_heights)[-6:], np.array(feature_widths)[-6:]
  97. def get_mobilenet_output_length(height, width):
  98. filter_sizes = [3, 3, 3, 3, 3, 3, 3, 3, 3]
  99. padding = [1, 1, 1, 1, 1, 1, 1, 1, 1]
  100. stride = [2, 2, 2, 2, 2, 2, 2, 2, 2]
  101. feature_heights = []
  102. feature_widths = []
  103. for i in range(len(filter_sizes)):
  104. height = (height + 2*padding[i] - filter_sizes[i]) // stride[i] + 1
  105. width = (width + 2*padding[i] - filter_sizes[i]) // stride[i] + 1
  106. feature_heights.append(height)
  107. feature_widths.append(width)
  108. return np.array(feature_heights)[-6:], np.array(feature_widths)[-6:]
  109. def get_anchors(input_shape = [300,300], anchors_size = [30, 60, 111, 162, 213, 264, 315], backbone = 'vgg'):
  110. if backbone == 'vgg':
  111. feature_heights, feature_widths = get_vgg_output_length(input_shape[0], input_shape[1])
  112. aspect_ratios = [[1, 2], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2], [1, 2]]
  113. else:
  114. feature_heights, feature_widths = get_mobilenet_output_length(input_shape[0], input_shape[1])
  115. aspect_ratios = [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
  116. anchors = []
  117. for i in range(len(feature_heights)):
  118. anchor_boxes = AnchorBox(input_shape, anchors_size[i], max_size = anchors_size[i+1],
  119. aspect_ratios = aspect_ratios[i]).call([feature_heights[i], feature_widths[i]])
  120. anchors.append(anchor_boxes)
  121. anchors = np.concatenate(anchors, axis=0)
  122. return anchors.astype(np.float32)
  123. if __name__ == '__main__':
  124. import matplotlib.pyplot as plt
  125. class AnchorBox_for_Vision():
  126. def __init__(self, input_shape, min_size, max_size=None, aspect_ratios=None, flip=True):
  127. # 获得输入图片的大小,300x300
  128. self.input_shape = input_shape
  129. # 先验框的短边
  130. self.min_size = min_size
  131. # 先验框的长边
  132. self.max_size = max_size
  133. # [1, 2] => [1, 1, 2, 1/2]
  134. # [1, 2, 3] => [1, 1, 2, 1/2, 3, 1/3]
  135. self.aspect_ratios = []
  136. for ar in aspect_ratios:
  137. self.aspect_ratios.append(ar)
  138. self.aspect_ratios.append(1.0 / ar)
  139. def call(self, layer_shape, mask=None):
  140. # --------------------------------- #
  141. # 获取输入进来的特征层的宽和高
  142. # 比如3x3
  143. # --------------------------------- #
  144. layer_height = layer_shape[0]
  145. layer_width = layer_shape[1]
  146. # --------------------------------- #
  147. # 获取输入进来的图片的宽和高
  148. # 比如300x300
  149. # --------------------------------- #
  150. img_height = self.input_shape[0]
  151. img_width = self.input_shape[1]
  152. box_widths = []
  153. box_heights = []
  154. # --------------------------------- #
  155. # self.aspect_ratios一般有两个值
  156. # [1, 1, 2, 1/2]
  157. # [1, 1, 2, 1/2, 3, 1/3]
  158. # --------------------------------- #
  159. for ar in self.aspect_ratios:
  160. # 首先添加一个较小的正方形
  161. if ar == 1 and len(box_widths) == 0:
  162. box_widths.append(self.min_size)
  163. box_heights.append(self.min_size)
  164. # 然后添加一个较大的正方形
  165. elif ar == 1 and len(box_widths) > 0:
  166. box_widths.append(np.sqrt(self.min_size * self.max_size))
  167. box_heights.append(np.sqrt(self.min_size * self.max_size))
  168. # 然后添加长方形
  169. elif ar != 1:
  170. box_widths.append(self.min_size * np.sqrt(ar))
  171. box_heights.append(self.min_size / np.sqrt(ar))
  172. print("box_widths:", box_widths)
  173. print("box_heights:", box_heights)
  174. # --------------------------------- #
  175. # 获得所有先验框的宽高1/2
  176. # --------------------------------- #
  177. box_widths = 0.5 * np.array(box_widths)
  178. box_heights = 0.5 * np.array(box_heights)
  179. # --------------------------------- #
  180. # 每一个特征层对应的步长
  181. # 3x3的步长为100
  182. # --------------------------------- #
  183. step_x = img_width / layer_width
  184. step_y = img_height / layer_height
  185. # --------------------------------- #
  186. # 生成网格中心
  187. # --------------------------------- #
  188. linx = np.linspace(0.5 * step_x, img_width - 0.5 * step_x, layer_width)
  189. liny = np.linspace(0.5 * step_y, img_height - 0.5 * step_y, layer_height)
  190. # 构建网格
  191. centers_x, centers_y = np.meshgrid(linx, liny)
  192. centers_x = centers_x.reshape(-1, 1)
  193. centers_y = centers_y.reshape(-1, 1)
  194. if layer_height == 3:
  195. fig = plt.figure()
  196. ax = fig.add_subplot(111)
  197. plt.ylim(-50,350)
  198. plt.xlim(-50,350)
  199. plt.scatter(centers_x,centers_y)
  200. # 每一个先验框需要两个(centers_x, centers_y),前一个用来计算左上角,后一个计算右下角
  201. num_anchors_ = len(self.aspect_ratios)
  202. anchor_boxes = np.concatenate((centers_x, centers_y), axis=1)
  203. anchor_boxes = np.tile(anchor_boxes, (1, 2 * num_anchors_))
  204. # 获得先验框的左上角和右下角
  205. anchor_boxes[:, ::4] -= box_widths
  206. anchor_boxes[:, 1::4] -= box_heights
  207. anchor_boxes[:, 2::4] += box_widths
  208. anchor_boxes[:, 3::4] += box_heights
  209. print(np.shape(anchor_boxes))
  210. if layer_height == 3:
  211. rect1 = plt.Rectangle([anchor_boxes[4, 0],anchor_boxes[4, 1]],box_widths[0]*2,box_heights[0]*2,color="r",fill=False)
  212. rect2 = plt.Rectangle([anchor_boxes[4, 4],anchor_boxes[4, 5]],box_widths[1]*2,box_heights[1]*2,color="r",fill=False)
  213. rect3 = plt.Rectangle([anchor_boxes[4, 8],anchor_boxes[4, 9]],box_widths[2]*2,box_heights[2]*2,color="r",fill=False)
  214. rect4 = plt.Rectangle([anchor_boxes[4, 12],anchor_boxes[4, 13]],box_widths[3]*2,box_heights[3]*2,color="r",fill=False)
  215. ax.add_patch(rect1)
  216. ax.add_patch(rect2)
  217. ax.add_patch(rect3)
  218. ax.add_patch(rect4)
  219. plt.show()
  220. # --------------------------------- #
  221. # 将先验框变成小数的形式
  222. # 归一化
  223. # --------------------------------- #
  224. anchor_boxes[:, ::2] /= img_width
  225. anchor_boxes[:, 1::2] /= img_height
  226. anchor_boxes = anchor_boxes.reshape(-1, 4)
  227. anchor_boxes = np.minimum(np.maximum(anchor_boxes, 0.0), 1.0)
  228. return anchor_boxes
  229. # 输入图片大小为300, 300
  230. input_shape = [300, 300]
  231. # 指定先验框的大小,即宽高
  232. anchors_size = [30, 60, 111, 162, 213, 264, 315]
  233. # feature_heights [38, 19, 10, 5, 3, 1]
  234. # feature_widths [38, 19, 10, 5, 3, 1]
  235. feature_heights, feature_widths = get_vgg_output_length(input_shape[0], input_shape[1])
  236. # 对先验框的数量进行一个指定 4,6
  237. aspect_ratios = [[1, 2], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2], [1, 2]]
  238. anchors = []
  239. for i in range(len(feature_heights)):
  240. anchors.append(AnchorBox_for_Vision(input_shape, anchors_size[i], max_size = anchors_size[i+1],
  241. aspect_ratios = aspect_ratios[i]).call([feature_heights[i], feature_widths[i]]))
  242. anchors = np.concatenate(anchors, axis=0)
  243. print(np.shape(anchors))