def __init__(self): self._rect_finder = RectFinder() self._image = None self._contour_filter = ContourFilter(min_size_scale = 0.7, max_size_scale = 1.25, min_aspect_ratio = 0.75, max_aspect_ratio = 2.25)
class PlayfieldDetector(Detector): LEFT_MASK_AREA_WIDTH = 5 RELATIVE_PLAYFIELD_AREA_SIZE = Vector2(0.95, 0.65) def __init__(self): self._rect_finder = RectFinder() self._image = None self._contour_filter = ContourFilter(min_size_scale = 0.7, max_size_scale = 1.25, min_aspect_ratio = 0.75, max_aspect_ratio = 2.25) def detect(self, image): self._image = image self._contour_filter.target_size = image.size * self.RELATIVE_PLAYFIELD_AREA_SIZE return self._perform_detection(image) def _perform_detection(self, image): playfield_mask = self._create_playfield_mask(image) playfield_contour = self._find_playfield_contour(playfield_mask, image) playfield_rect, detected_corners = self._find_rect_corners(playfield_contour) self._adjust_playfield_width(image, playfield_rect) return Playfield(playfield_rect) def _create_playfield_mask(self, image): mask = self._create_mask(image, ColorRange(Color.from_hsv(0, 0, 0), Color.from_hsv(360, 255, 75)), closure_kernel_size = 14) mask.invert() self._draw_left_exclusion_area(mask, image) self._draw_right_exclusion_area(mask, image) return mask def _draw_left_exclusion_area(self, mask, image): OpenCV.fill_rectangle(mask, Rect.from_size(Vector2(self.LEFT_MASK_AREA_WIDTH, image.height)), Color.BLACK) def _draw_right_exclusion_area(self, mask, image): charging_station_area_width = ChargingStation.PHYSICAL_SIZE_CM.width / Playfield.PHYSICAL_SIZE_CM.width * image.width OpenCV.fill_rectangle(mask, Rect(Vector2(image.width - charging_station_area_width, 0), Vector2(charging_station_area_width, image.height)), Color.BLACK) def _find_playfield_contour(self, playfield_mask, image): contours = self._find_contours(playfield_mask, image) playfield_contours = self._contour_filter.filter_contours(contours) self._log_contour_detection_step("Playfield Contours", playfield_contours, self._image) if len(playfield_contours) != 1: raise DetectionError("Playfield detection failed. Detected contours: {0}.".format(len(playfield_contours))) return playfield_contours[0] def _find_rect_corners(self, playfield_contour): table_rect, detected_corners = self._rect_finder.find_rectangle(playfield_contour) self._log_rect_corners_detection_step(table_rect, detected_corners) return table_rect, detected_corners def _adjust_playfield_width(self, image, playfield_rect): playfield_rect.left = 0 playfield_rect.width = playfield_rect.height * Playfield.PHYSICAL_SIZE_CM.aspect_ratio # Logging def _log_rect_corners_detection_step(self, table_rect, detected_corners): if Logger.get_instance().save_blob_data: self._image.save_state() OpenCV.draw_rectangle(self._image, table_rect, Color.YELLOW, thickness = 3) for corner in detected_corners: OpenCV.draw_circle(self._image, Vector2(corner[0], corner[1]), radius = 10, color = Color.RED, thickness = 3) self._log_detection_step("Playfield Rect Corners", self._image) self._image.restore_state() def _log_playfield_detection_step(self, image, playfield_rect): if Logger.get_instance().save_blob_data: self._image.save_state() image.crop(playfield_rect) self._log_detection_step("Playfield", image) self._image.restore_state()