detect.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import argparse
  2. import json
  3. from detection.utils import *
  4. from os.path import splitext, basename, join
  5. def main():
  6. ap = argparse.ArgumentParser()
  7. ap.add_argument("-i", "--input", required=True, help="input image")
  8. ap.add_argument("-s", "--scale", type=float, default=0.1, help="scale images by this factor (default: x0.1)")
  9. ap.add_argument("-c", "--config", type=str, default="config.json",
  10. help="name file to load config (default: config.json)")
  11. ap.add_argument("-o", "--output", type=str, help="give a directory name to save the game files in it")
  12. ap.add_argument("--hide", action='store_true', default=False, help="hide images")
  13. args = vars(ap.parse_args())
  14. with open(args['config'], 'r') as file:
  15. config = json.load(file)
  16. orig, blob_mask, blob, food_mask, food_img, food_list = detect(args['input'], config)
  17. discrete_img, discrete_blob, discrete_food_list, known_food = discretize(blob, food_list, config['Discrete Width'],
  18. config['Discrete Height'])
  19. if args['output'] is not None:
  20. filename = splitext(basename(args['input']))[0]
  21. dir = args['output']
  22. save(join(dir, filename), discrete_img, discrete_blob, discrete_food_list, known_food)
  23. if not args['hide']:
  24. print_results(orig, blob_mask, blob, food_mask, food_img, discrete_img, args['scale'])
  25. def detect(input_file, config):
  26. img = cv2.imread(input_file)
  27. height, width, _ = img.shape
  28. aspect_ratio = config["Aspect Ratio"]
  29. height = int(width*aspect_ratio)
  30. """ Resize image to limits in config file """
  31. limits = np.array(config['Limits'])
  32. transform_mat = cv2.getPerspectiveTransform(np.float32(limits), np.float32(
  33. [[0, 0], [width, 0], [width, height], [0, height]]))
  34. img = cv2.warpPerspective(img, transform_mat, (width, height))
  35. """ Prepare upper and lower mask board """
  36. upper_mask = np.zeros(img.shape[0:2], np.uint8)
  37. lower_mask = np.zeros(img.shape[0:2], np.uint8)
  38. upper_mask = cv2.rectangle(upper_mask, (0, 0), (width, int(height/2)), 255, thickness=cv2.FILLED)
  39. lower_mask = cv2.rectangle(lower_mask, (0, int(height / 2)), (width, height), 255, thickness=cv2.FILLED)
  40. """ Find blob """
  41. sat = saturation(img)
  42. # sum = mean_image([satA, satB])
  43. blob_mask = find_blob(sat)
  44. blob = cv2.bitwise_and(img, img, mask=blob_mask)
  45. """ Print blob information """
  46. print("Blob covering:")
  47. print("\t{:.2f}% of the board.".format(mean_percent_value(blob_mask)))
  48. print("\t{:.2f}% of the upper board.".format(
  49. mean_percent_value(cv2.bitwise_and(blob_mask, blob_mask, mask=upper_mask), img_ratio=0.5)))
  50. print("\t{:.2f}% of the lower board.".format(
  51. mean_percent_value(cv2.bitwise_and(blob_mask, blob_mask, mask=lower_mask), img_ratio=0.5)))
  52. """ Find food """
  53. food_list, food_mask, food_img = find_food(img, 100, config['Low Food Color'], config['High Food Color'])
  54. """ Print food information """
  55. print("Total food discovered: " + str(len(food_list)))
  56. for i, food in enumerate(food_list):
  57. print("\tFood N°" + str(i) + ": " + str(food))
  58. return img, blob_mask, blob, food_mask, food_img, food_list
  59. def print_results(orig, blob_mask, blob, food_mask, food, discrete, scale=1.0):
  60. padding = 35
  61. nbr_width = 2
  62. nbr_height = 3
  63. font = cv2.FONT_HERSHEY_SIMPLEX
  64. fontsize = 0.45
  65. thickness = 1
  66. scaled_height = int(orig.shape[0]*scale)
  67. scaled_width = int(orig.shape[1]*scale)
  68. pad = np.zeros((scaled_height, padding, orig.shape[2]), dtype=np.uint8)
  69. line_pad = np.zeros((padding, (scaled_width + padding) * nbr_width + padding, orig.shape[2]), dtype=np.uint8)
  70. print_img = cv2.resize(orig, (scaled_width, scaled_height))
  71. middle = ((0, int(scaled_height/2)), (scaled_width, int(scaled_height/2)))
  72. cv2.line(print_img, middle[0], middle[1], (0, 255, 0), thickness=1)
  73. cv2.putText(print_img, 'Mid Line', (middle[0][0] + 5, middle[0][1] - 5),
  74. font, fontsize, (0, 255, 0), thickness, cv2.LINE_AA)
  75. print_blob_mask = cv2.resize(cv2.cvtColor(blob_mask, cv2.COLOR_GRAY2BGR), (scaled_width, scaled_height))
  76. print_blob = cv2.resize(blob, (scaled_width, scaled_height))
  77. print_food_mask = cv2.resize(cv2.cvtColor(food_mask, cv2.COLOR_GRAY2BGR), (scaled_width, scaled_height))
  78. print_food = cv2.resize(food, (scaled_width, scaled_height))
  79. print_discrete = cv2.resize(discrete, (scaled_width, scaled_height))
  80. concat_line1 = np.concatenate((pad, print_img, pad, print_discrete, pad), axis=1)
  81. concat_line2 = np.concatenate((pad, print_blob_mask, pad, print_blob, pad), axis=1)
  82. concat_line3 = np.concatenate((pad, print_food_mask, pad, print_food, pad), axis=1)
  83. aggregate = np.concatenate((line_pad, concat_line1, line_pad, concat_line2, line_pad, concat_line3, line_pad))
  84. cv2.putText(aggregate, 'Original:',
  85. (0 * (scaled_width + padding) + padding + 5, 0 * (scaled_height + padding) + padding - 5),
  86. font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
  87. cv2.putText(aggregate, 'Discrete:',
  88. (1 * (scaled_width + padding) + padding + 5, 0 * (scaled_height + padding) + padding - 5),
  89. font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
  90. cv2.putText(aggregate, 'Blob Mask:',
  91. (0 * (scaled_width + padding) + padding + 5, 1 * (scaled_height + padding) + padding - 5),
  92. font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
  93. cv2.putText(aggregate, 'Blob:',
  94. (1 * (scaled_width + padding) + padding + 5, 1 * (scaled_height + padding) + padding - 5),
  95. font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
  96. cv2.putText(aggregate, 'Food Mask:',
  97. (0 * (scaled_width + padding) + padding + 5, 2 * (scaled_height + padding) + padding - 5),
  98. font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
  99. cv2.putText(aggregate, 'Food Regions:',
  100. (1 * (scaled_width + padding) + padding + 5, 2 * (scaled_height + padding) + padding - 5),
  101. font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
  102. cv2.imshow("Results", aggregate)
  103. print("\nPress any key...")
  104. cv2.waitKey(0)
  105. def discretize(blob_img, food_list, width, height):
  106. img_height, img_width, _ = blob_img.shape
  107. discrete_blob = cv2.resize(blob_img, (width, height), interpolation=cv2.INTER_NEAREST)
  108. discrete_food_list = []
  109. for food in food_list:
  110. x = int((food[0] + food[2]/2) / img_width * width)
  111. y = int((food[1] + food[3]/2) / img_height * height)
  112. discrete_food_list.append((x,y))
  113. height, width, _ = discrete_blob.shape
  114. discrete_blob = cv2.cvtColor(discrete_blob, cv2.COLOR_BGR2GRAY)
  115. known_food = []
  116. for food in discrete_food_list:
  117. if discrete_blob[food[1], food[0]] != 0:
  118. known_food.append([food[0], food[1]])
  119. discrete_blob_bgr = cv2.cvtColor(discrete_blob, cv2.COLOR_GRAY2BGR)
  120. discrete_img = cv2.resize(discrete_blob_bgr, (0, 0), fx=10, fy=10, interpolation=cv2.INTER_NEAREST)
  121. for (x, y) in discrete_food_list:
  122. cv2.rectangle(discrete_img, (x * 10, y * 10), ((x + 1) * 10, (y + 1) * 10), (0, 255, 0), thickness=cv2.FILLED)
  123. for (x, y) in known_food:
  124. cv2.drawMarker(discrete_img, (x * 10 + 5, y * 10 + 5), (255, 255, 255), thickness=2, markerSize=9,
  125. markerType=cv2.MARKER_TILTED_CROSS)
  126. return discrete_img, discrete_blob, discrete_food_list, known_food
  127. def save(filename, discrete_img, discrete_blob, discrete_food_list, known_food):
  128. height, width = discrete_blob.shape
  129. board_str = str(width) + ' ' + str(height) + '\n'
  130. for x in range(height):
  131. for y in range(width):
  132. board_str += format(discrete_blob[x, y] != 0, 'd') + "," + format((y, x) in discrete_food_list, 'd') \
  133. + "," + str(discrete_blob[x, y]) + " "
  134. board_str = board_str[:-1]
  135. board_str += "\n"
  136. board_str = board_str[:-1]
  137. with open(filename + ".board", 'w') as board_file:
  138. board_file.write(board_str)
  139. with open(filename + ".blob", 'w') as blob_file:
  140. knowledge = dict()
  141. knowledge['food'] = known_food
  142. knowledge['max_scouters'] = len(known_food)
  143. json.dump(knowledge, blob_file)
  144. with open(filename + ".player", 'w') as player_file:
  145. player_file.write("0")
  146. cv2.imwrite(filename + ".jpg", discrete_img)
  147. if __name__ == "__main__":
  148. main()