diff --git a/backend/app/classes/Exceptions.py b/backend/app/classes/Exceptions.py new file mode 100644 index 000000000..237733710 --- /dev/null +++ b/backend/app/classes/Exceptions.py @@ -0,0 +1,5 @@ + +class PipelineAlreadyExistsException(Excetion): + + def __init__(self, pipe_name): + super(f"Pipeline {pipe_name} already exists") diff --git a/backend/app/classes/SettingsManager.py b/backend/app/classes/SettingsManager.py index 6abecb733..a2be94f9a 100644 --- a/backend/app/classes/SettingsManager.py +++ b/backend/app/classes/SettingsManager.py @@ -4,10 +4,12 @@ import cscore import networktables from .Singleton import Singleton from .CamerasHandler import CamerasHandler +from .Exceptions import PipelineAlreadyExistsException class SettingsManager(metaclass=Singleton): cams = {} + settings = {} def __init__(self): self.settings_path = os.path.join(os.getcwd(), "settings") @@ -16,19 +18,16 @@ class SettingsManager(metaclass=Singleton): self._init_cameras() def _init_general_settings(self): - def init_default_settings(): + try: + with open(os.path.join(self.settings_path, 'settings.json')) as setting_file: + self.settings = json.load(setting_file) + except FileNotFoundError: self.settings = { "team_number": 1577, "curr_camera": "cam1", "curr_pipeline": "pipeline1" } - try: - with open(os.path.join(self.settings_path, 'settings.json')) as setting_file: - self.settings = json.load(setting_file) - except FileNotFoundError: - init_default_settings() - def _init_cameras(self): cameras = CamerasHandler.get_cameras() @@ -72,7 +71,14 @@ class SettingsManager(metaclass=Singleton): cam_name = self.settings["curr_camera"] if not pipe_name: - pipe_name = "pipeline" + str(len(self.cams[cam_name])) + suffix = 0 + pipe_name = "pipeline" + str(suffix) + + while pipe_name not in self.cams[cam_name]["pipelines"]: + suffix += 1 + pipe_name = "pipeline" + str(suffix) + elif self.cams[cam_name]["pipelines"][pipe_name]: + raise PipelineAlreadyExistsException(pipe_name) self.cams[cam_name]["pipelines"][pipe_name] = { "exposure": 50, diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index 9d2a0c6ce..6dfa476bb 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -4,83 +4,75 @@ import cv2 import numpy from app.classes.SettingsManager import SettingsManager + class VisionHandler: def __init__(self): self.kernel = numpy.ones((5, 5), numpy.uint8) - -def hsv_threshold(self,hue: list, saturation: list, value: list, img: numpy.ndarray, is_erode: bool, is_dilate: bool): - # img = cv2.medianBlur(img, 1) - # not sure if we need noise reduction now with erode it hurts the precision if val is to high + def _hsv_threshold(self, hue: list, saturation: list, value: list, img: numpy.ndarray, is_erode: bool, is_dilate: bool): + # img = cv2.medianBlur(img, 1) + # not sure if we need noise reduction now with erode it hurts the precision if val is to high - img = cv2.erode(img, kernel=self.kernel, iterations=is_erode) - img = cv2.dilate(img, kernel=self.kernel, iterations=is_dilate) - out = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) - return cv2.inRange(out, (hue[0], saturation[0], value[0]), (hue[1], saturation[1], value[1])) + img = cv2.erode(img, kernel=self.kernel, iterations=is_erode) + img = cv2.dilate(img, kernel=self.kernel, iterations=is_dilate) + out = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + return cv2.inRange(out, (hue[0], saturation[0], value[0]), (hue[1], saturation[1], value[1])) + def find_contours(self, binary_img: numpy.ndarray): + _, contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + return contours -def find_contours(self, binary_img: numpy.ndarray): - _, contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - return contours + def filter_contours(self, input_contours, camera_area, min_area, max_area, min_ratio, max_ratio, min_extent, + max_extent): + output = [] + rectangle = [] + for contour in input_contours: -def filter_contours(self, input_contours, camera_area, min_area, max_area, min_ratio, max_ratio, min_extent, max_extent): - output = [] - rectangle = [] + rect = cv2.minAreaRect(contour) + # center_point = rect[0] + contour_area = cv2.contourArea(contour) + rect_area = rect[1][0] * rect[1][1] - for contour in input_contours: + try: + extent = float(contour_area) / rect_area + ratio = float(rect[1][0]) / rect[1][1] + area = rect_area / camera_area + except: + continue - rect = cv2.minAreaRect(contour) - # center_point = rect[0] - contour_area = cv2.contourArea(contour) - rect_area = rect[1][0] * rect[1][1] + if area < min_area or area > max_area: + continue + if ratio < min_ratio or ratio > max_ratio: + continue + if extent < min_extent or extent > max_extent: + continue - try: - extent = float(contour_area) / rect_area - ratio = float(rect[1][0]) / rect[1][1] - area = rect_area / camera_area - except: - continue + output.append(contour) + rectangle.append(rect) - if area < min_area or area > max_area: - continue - if ratio < min_ratio or ratio > max_ratio: - continue - if extent < min_extent or extent > max_extent: - continue + return [output, rectangle] - output.append(contour) - rectangle.append(rect) - - return [output, rectangle] - - -def draw_image(self, input_image: numpy.ndarray, is_binary: bool, rectangles): - if is_binary: - input_image = cv2.cvtColor(input_image, cv2.COLOR_GRAY2RGB) - for rectangle in rectangles[1]: - box = cv2.boxPoints(rectangle) - box = numpy.int0(box) - cv2.drawContours(input_image, [box], 0, (0, 0, 255), 2) - center_point = (int(rectangle[0][0]), int(rectangle[0][1])) - cv2.circle(input_image, center_point, 0, (0, 255, 0), thickness=3, lineType=8, shift=0) - return input_image - - -def run(): - - camera_server = cscore.CameraServer.getInstance() - networktables.NetworkTables.startClientTeam(team=SettingsManager.settings["team_number"]) - networktables.NetworkTables.initialize() - - -def camera_process(cv_sink,stream): - image = numpy.zeros(shape=(0,0,3), dtype=numpy.uint8) - table = networktables.NetworkTables.getTable("/Chameleon-Vision/"+"cam name") - while True: - _, image = cv_sink.grabFrame(image) - - stream.putFrame(image) + def draw_image(self, input_image: numpy.ndarray, is_binary: bool, rectangles): + if is_binary: + input_image = cv2.cvtColor(input_image, cv2.COLOR_GRAY2RGB) + for rectangle in rectangles[1]: + box = cv2.boxPoints(rectangle) + box = numpy.int0(box) + cv2.drawContours(input_image, [box], 0, (0, 0, 255), 2) + center_point = (int(rectangle[0][0]), int(rectangle[0][1])) + cv2.circle(input_image, center_point, 0, (0, 255, 0), thickness=3, lineType=8, shift=0) + return input_image + def run(self): + camera_server = cscore.CameraServer.getInstance() + networktables.NetworkTables.startClientTeam(team=SettingsManager.settings["team_number"]) + networktables.NetworkTables.initialize() + def camera_process(cv_sink, stream): + image = numpy.zeros(shape=(0, 0, 3), dtype=numpy.uint8) + table = networktables.NetworkTables.getTable("/Chameleon-Vision/" + "cam name") + while True: + _, image = cv_sink.grabFrame(image) + stream.putFrame(image)