From 7d11467fd361a82a6a9643d1ac38a8d964a9ee1e Mon Sep 17 00:00:00 2001 From: ori Date: Wed, 8 May 2019 08:54:05 -0700 Subject: [PATCH 1/7] initial work --- backend/app/classes/SettingsManager.py | 3 ++- backend/app/handlers/VisionHandler.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/app/classes/SettingsManager.py b/backend/app/classes/SettingsManager.py index 3f9c35f07..64bb50d01 100644 --- a/backend/app/classes/SettingsManager.py +++ b/backend/app/classes/SettingsManager.py @@ -25,7 +25,8 @@ class SettingsManager(metaclass=Singleton): "dilate": False, "area": [0, 100], "ratio": [0, 20], - "extent": [0, 100] + "extent": [0, 100], + "is_binary": "Normal" } default_general_settings = { "team_number": 1577, diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index 269ec7af3..e596cc6f5 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -7,6 +7,7 @@ from cscore import CameraServer from app.classes.SettingsManager import SettingsManager import time import json +import multiprocessing class VisionHandler: @@ -75,7 +76,8 @@ class VisionHandler: # NetworkTables.initialize() for cam in SettingsManager().usb_cameras: - self.camera_process(SettingsManager().usb_cameras[cam],cam) + multiprocessing.Process(target=self.camera_process(SettingsManager().usb_cameras[cam],cam)) + # self.camera_process(SettingsManager().usb_cameras[cam],cam) def camera_process(self, camera,cam_name): From 1340a2e260e4b51a45eea3aada8433f1291932fe Mon Sep 17 00:00:00 2001 From: ori Date: Fri, 10 May 2019 07:01:39 -0700 Subject: [PATCH 2/7] sagi this is for you --- backend/Main.py | 23 +++++++++++++++++------ backend/app/handlers/VisionHandler.py | 7 +++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/backend/Main.py b/backend/Main.py index 09d7ccd94..b36cd27d8 100644 --- a/backend/Main.py +++ b/backend/Main.py @@ -1,22 +1,33 @@ import tornado.ioloop +import multiprocessing from app.ChameleonVisionApp import ChameleonApplication from app.classes.SettingsManager import SettingsManager from tornado.options import options from app.handlers.VisionHandler import VisionHandler -if __name__ == "__main__": - SettingsManager() - - VisionHandler().run() - # SettingsManager().save_settings() - +def run_server(): tornado.options.parse_command_line() app = ChameleonApplication() print(f"Serving on port {options.port}") app.listen(options.port) tornado.ioloop.IOLoop.current().start() +if __name__ == "__main__": + SettingsManager() + + procs = VisionHandler().run() + # proc = multiprocessing.Process(target=run_server) + # procs.append(proc) + # proc.start() + + + for i in procs: + i.start() + # SettingsManager().save_settings() + + + #TODO: create process for each camera # create proccess loop and camera publisher # bridge network tables for each camera \ No newline at end of file diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index e596cc6f5..82cb7c35c 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -70,14 +70,17 @@ class VisionHandler: return input_image def run(self): + procs = [] camera_server = cscore.CameraServer.getInstance() # NetworkTables.startClientTeam(team=SettingsManager.general_settings.get("team_number", 1577)) NetworkTables.initialize("localhost") # NetworkTables.initialize() for cam in SettingsManager().usb_cameras: - multiprocessing.Process(target=self.camera_process(SettingsManager().usb_cameras[cam],cam)) + proc = multiprocessing.Process(target=self.camera_process, args=(SettingsManager().usb_cameras[cam],cam)) + procs.append(proc) # self.camera_process(SettingsManager().usb_cameras[cam],cam) + return procs def camera_process(self, camera,cam_name): @@ -102,7 +105,7 @@ class VisionHandler: flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) table.addEntryListenerEx(mode_listener, key="Driver_Mode", flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) - change_camera_values() + # change_camera_values() cs = CameraServer.getInstance() cv_sink = cs.getVideo(camera=camera) cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], From 45f76b8c5f38459b04ffd8065ce53a7c8640857b Mon Sep 17 00:00:00 2001 From: ori Date: Fri, 24 May 2019 05:16:15 -0700 Subject: [PATCH 3/7] spaning tree using threading and process --- backend/Main.py | 25 +++-- backend/app/handlers/VisionHandler.py | 128 +++++++++++++++++--------- 2 files changed, 94 insertions(+), 59 deletions(-) diff --git a/backend/Main.py b/backend/Main.py index b36cd27d8..f965254c8 100644 --- a/backend/Main.py +++ b/backend/Main.py @@ -1,11 +1,17 @@ +from multiprocessing import Queue +from multiprocessing.managers import BaseManager + import tornado.ioloop import multiprocessing +import logging +from cscore import CameraServer from app.ChameleonVisionApp import ChameleonApplication from app.classes.SettingsManager import SettingsManager from tornado.options import options from app.handlers.VisionHandler import VisionHandler + def run_server(): tornado.options.parse_command_line() app = ChameleonApplication() @@ -13,21 +19,14 @@ def run_server(): app.listen(options.port) tornado.ioloop.IOLoop.current().start() + + if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) SettingsManager() - - procs = VisionHandler().run() - # proc = multiprocessing.Process(target=run_server) - # procs.append(proc) - # proc.start() + VisionHandler().run() - for i in procs: - i.start() - # SettingsManager().save_settings() + while True: + pass - - -#TODO: create process for each camera -# create proccess loop and camera publisher -# bridge network tables for each camera \ No newline at end of file diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index 82cb7c35c..f18d762fd 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -5,12 +5,13 @@ import cv2 import numpy from cscore import CameraServer from app.classes.SettingsManager import SettingsManager +from ..classes.Singleton import Singleton import time -import json -import multiprocessing +from multiprocessing import Process, Pipe +import threading -class VisionHandler: +class VisionHandler(metaclass=Singleton): def __init__(self): self.kernel = numpy.ones((5, 5), numpy.uint8) @@ -71,59 +72,94 @@ class VisionHandler: def run(self): procs = [] - camera_server = cscore.CameraServer.getInstance() # NetworkTables.startClientTeam(team=SettingsManager.general_settings.get("team_number", 1577)) NetworkTables.initialize("localhost") # NetworkTables.initialize() + cs = CameraServer.getInstance() + pipes = [] - for cam in SettingsManager().usb_cameras: - proc = multiprocessing.Process(target=self.camera_process, args=(SettingsManager().usb_cameras[cam],cam)) - procs.append(proc) - # self.camera_process(SettingsManager().usb_cameras[cam],cam) - return procs + for cam_name in SettingsManager().usb_cameras: + threading.Thread(target=self.thred_proc, args=(cs,cam_name)).start() - def camera_process(self, camera,cam_name): + + + # parent, child = Pipe() + # cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name]) + # image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], + # SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) + # cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], + # height=SettingsManager().cams[cam_name]["video_mode"]["height"]) + # + # proc = Process(target=self.camera_process, + # args=(SettingsManager.usb_cameras[cam_name], cam_name, child)) + # proc.start() + # pipes.append( + # { + # "cam": SettingsManager.usb_cameras[cam_name], + # "cv_sink": cv_sink, + # "pipe": parent, + # "image": image, + # "publish":cv_publish + # } + # ) + # + # while True: + # for dic in pipes: + # a,b = dic["cv_sink"].grabFrame(dic["image"]) + # dic["pipe"].send(a) + # dic["publish"].putFrame(b) + + + def thred_proc(self,cs,cam_name): + cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name]) + image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], + SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) + cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], + height=SettingsManager().cams[cam_name]["video_mode"]["height"]) + parent,child = Pipe() + proc = Process(target=self.camera_process, args=(SettingsManager.usb_cameras[cam_name], cam_name, child)).start() + while True: + _, image = cv_sink.grabFrame(image) + parent.send(image) + cv_publish.putFrame(image) + + + def camera_process(self, camera, cam_name, pipe): curr_pipline = list(SettingsManager.cams[cam_name]["pipelines"].values())[0] - def change_camera_values(): - camera.setBrightness(0) - camera.setExposureManual(0) - - def pipeline_listener(table, key, value, is_new): - if(is_new): - curr_pipline = SettingsManager.cams[cam_name]["pipelines"][value] - change_camera_values() - - def mode_listener(table, key, value, is_new): - pass - - image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) - table = NetworkTables.getTable("/Chameleon-Vision/" + camera.getInfo().name) - - table.addEntryListenerEx(pipeline_listener, key="Pipeline", - flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) - table.addEntryListenerEx(mode_listener, key="Driver_Mode", - flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) + # def change_camera_values(): + # camera.setBrightness(0) + # camera.setExposureManual(0) + # + # def pipeline_listener(table, key, value, is_new): + # if (is_new): + # curr_pipline = SettingsManager.cams[cam_name]["pipelines"][value] + # change_camera_values() + # + # def mode_listener(table, key, value, is_new): + # pass + # + # table = NetworkTables.getTable("/Chameleon-Vision/" + camera.getInfo().name) + # + # table.addEntryListenerEx(pipeline_listener, key="Pipeline", + # flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) + # table.addEntryListenerEx(mode_listener, key="Driver_Mode", + # flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) # change_camera_values() - cs = CameraServer.getInstance() - cv_sink = cs.getVideo(camera=camera) - cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], - height=SettingsManager().cams[cam_name]["video_mode"]["height"]) - cam_area = SettingsManager().cams[cam_name]["video_mode"]["width"] * SettingsManager().cams[cam_name]["video_mode"]["height"] + cam_area = SettingsManager().cams[cam_name]["video_mode"]["width"] * \ + SettingsManager().cams[cam_name]["video_mode"]["height"] + while True: start = time.time() - _, image = cv_sink.grabFrame(image) - hsv_image = self._hsv_threshold(curr_pipline["hue"], - curr_pipline["saturation"], curr_pipline["value"], - image, curr_pipline["erode"], curr_pipline["dilate"]) + image = pipe.recv() + # hsv_image = self._hsv_threshold(curr_pipline["hue"], + # curr_pipline["saturation"], curr_pipline["value"], + # image, curr_pipline["erode"], curr_pipline["dilate"]) + # # if table.getBoolean("Driver_Mode", False): + # contours = self.find_contours(hsv_image) + # filtered_contours = self.filter_contours(contours, cam_area, curr_pipline["area"], curr_pipline["ratio"], curr_pipline["extent"]) + # image = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) - - # if table.getBoolean("Driver_Mode", False): - contours = self.find_contours(hsv_image) - filtered_contours = self.filter_contours(contours, cam_area, curr_pipline["area"], curr_pipline["ratio"], curr_pipline["extent"]) - image = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) - cv_publish.putFrame(image) end = time.time() - print(1/(end-start)) - + print(1 / (end - start)) \ No newline at end of file From 2b75059910c67c0aec90f81a129be70639e98389 Mon Sep 17 00:00:00 2001 From: Sagi Frimer Date: Fri, 24 May 2019 17:23:33 +0300 Subject: [PATCH 4/7] fixed something in settingsmng --- backend/app/classes/SettingsManager.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/backend/app/classes/SettingsManager.py b/backend/app/classes/SettingsManager.py index 64bb50d01..bb2bde79a 100644 --- a/backend/app/classes/SettingsManager.py +++ b/backend/app/classes/SettingsManager.py @@ -95,16 +95,12 @@ class SettingsManager(metaclass=Singleton): def _init_usb_cameras(self): for i in self.usb_cameras_info: device = self.usb_cameras_info[i] - device_name = device.name + suffix = 1 - if device_name in self.usb_cameras: - suffix = 1 - device_name = device.name + f"({str(suffix)})" - - while device_name in self.usb_cameras: - suffix += 1 - device_name = "pipeline" + f"({str(suffix)})" + while device_name in self.usb_cameras: + suffix += 1 + device_name = f"{device.name}({str(suffix)})" camera = cscore.UsbCamera(name=device_name, dev=device.dev) From 94f56a0f7c3d1d68964bb752d0cdd7883ccbf4d9 Mon Sep 17 00:00:00 2001 From: ori Date: Sat, 25 May 2019 06:20:25 -0700 Subject: [PATCH 5/7] playing with pipe send and recive and async task --- backend/app/classes/SettingsManager.py | 6 +-- backend/app/handlers/VisionHandler.py | 66 +++++++++----------------- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/backend/app/classes/SettingsManager.py b/backend/app/classes/SettingsManager.py index bb2bde79a..d2d8e9ca0 100644 --- a/backend/app/classes/SettingsManager.py +++ b/backend/app/classes/SettingsManager.py @@ -81,12 +81,12 @@ class SettingsManager(metaclass=Singleton): true_cameras = [] usb_devices = cscore.UsbCamera.enumerateUsbCameras() - for index in range(len(usb_devices)): - cap = cv2.VideoCapture(index) + for index, device in enumerate(usb_devices): + cap = cv2.VideoCapture(device.dev) if cap.isOpened(): true_cameras.append(index) cap.release() - index += 1 + for i in true_cameras: self.usb_cameras_info[usb_devices[i].name] = usb_devices[i] diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index f18d762fd..9bb270cef 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -8,9 +8,9 @@ from app.classes.SettingsManager import SettingsManager from ..classes.Singleton import Singleton import time from multiprocessing import Process, Pipe +import multiprocessing import threading - class VisionHandler(metaclass=Singleton): def __init__(self): self.kernel = numpy.ones((5, 5), numpy.uint8) @@ -82,49 +82,31 @@ class VisionHandler(metaclass=Singleton): threading.Thread(target=self.thred_proc, args=(cs,cam_name)).start() - - # parent, child = Pipe() - # cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name]) - # image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], - # SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) - # cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], - # height=SettingsManager().cams[cam_name]["video_mode"]["height"]) - # - # proc = Process(target=self.camera_process, - # args=(SettingsManager.usb_cameras[cam_name], cam_name, child)) - # proc.start() - # pipes.append( - # { - # "cam": SettingsManager.usb_cameras[cam_name], - # "cv_sink": cv_sink, - # "pipe": parent, - # "image": image, - # "publish":cv_publish - # } - # ) - # - # while True: - # for dic in pipes: - # a,b = dic["cv_sink"].grabFrame(dic["image"]) - # dic["pipe"].send(a) - # dic["publish"].putFrame(b) - - def thred_proc(self,cs,cam_name): + async def pipe_send(pipe, data): + pipe.send(data) + + async def pipe_recive(pipe): + return pipe.recv() cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name]) image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], height=SettingsManager().cams[cam_name]["video_mode"]["height"]) parent,child = Pipe() - proc = Process(target=self.camera_process, args=(SettingsManager.usb_cameras[cam_name], cam_name, child)).start() + Process(target=self.camera_process, args=(SettingsManager.usb_cameras[cam_name], cam_name, child)).start() while True: + start = time.time() _, image = cv_sink.grabFrame(image) parent.send(image) + # pipe_send(parent,image) + image = parent.recv() cv_publish.putFrame(image) + end = time.time() + print(cam_name + " " + str(1 / (end - start))) - def camera_process(self, camera, cam_name, pipe): + def camera_process(self, camera, cam_name, child_pipe): curr_pipline = list(SettingsManager.cams[cam_name]["pipelines"].values())[0] @@ -149,17 +131,13 @@ class VisionHandler(metaclass=Singleton): # change_camera_values() cam_area = SettingsManager().cams[cam_name]["video_mode"]["width"] * \ SettingsManager().cams[cam_name]["video_mode"]["height"] - while True: - start = time.time() - image = pipe.recv() - # hsv_image = self._hsv_threshold(curr_pipline["hue"], - # curr_pipline["saturation"], curr_pipline["value"], - # image, curr_pipline["erode"], curr_pipline["dilate"]) - # # if table.getBoolean("Driver_Mode", False): - # contours = self.find_contours(hsv_image) - # filtered_contours = self.filter_contours(contours, cam_area, curr_pipline["area"], curr_pipline["ratio"], curr_pipline["extent"]) - # image = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) - - end = time.time() - print(1 / (end - start)) \ No newline at end of file + image = child_pipe.recv() + hsv_image = self._hsv_threshold(curr_pipline["hue"], + curr_pipline["saturation"], curr_pipline["value"], + image, curr_pipline["erode"], curr_pipline["dilate"]) + # if table.getBoolean("Driver_Mode", False): + contours = self.find_contours(hsv_image) + filtered_contours = self.filter_contours(contours, cam_area, curr_pipline["area"], curr_pipline["ratio"], curr_pipline["extent"]) + image = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) + child_pipe.send(image) From ab46bee5a8fdeddc776c96f0e5348207c69667c1 Mon Sep 17 00:00:00 2001 From: Sagi Frimer Date: Sat, 25 May 2019 17:26:11 +0300 Subject: [PATCH 6/7] try async pipe --- backend/app/handlers/VisionHandler.py | 32 +++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index 9bb270cef..1301d4d6d 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -11,6 +11,7 @@ from multiprocessing import Process, Pipe import multiprocessing import threading + class VisionHandler(metaclass=Singleton): def __init__(self): self.kernel = numpy.ones((5, 5), numpy.uint8) @@ -79,36 +80,37 @@ class VisionHandler(metaclass=Singleton): pipes = [] for cam_name in SettingsManager().usb_cameras: - threading.Thread(target=self.thred_proc, args=(cs,cam_name)).start() + threading.Thread(target=self.thred_proc, args=(cs, cam_name)).start() - - def thred_proc(self,cs,cam_name): + def thred_proc(self, cs, cam_name): async def pipe_send(pipe, data): pipe.send(data) async def pipe_recive(pipe): return pipe.recv() + cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name]) image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], - SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) + SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], - height=SettingsManager().cams[cam_name]["video_mode"]["height"]) - parent,child = Pipe() + height=SettingsManager().cams[cam_name]["video_mode"]["height"]) + parent, child = Pipe() Process(target=self.camera_process, args=(SettingsManager.usb_cameras[cam_name], cam_name, child)).start() + while True: start = time.time() _, image = cv_sink.grabFrame(image) parent.send(image) # pipe_send(parent,image) - image = parent.recv() + if parent.poll(): + image = parent.recv() cv_publish.putFrame(image) end = time.time() - print(cam_name + " " + str(1 / (end - start))) - + print(cam_name + " " + str(1 / (end - start))) def camera_process(self, camera, cam_name, child_pipe): - curr_pipline = list(SettingsManager.cams[cam_name]["pipelines"].values())[0] + curr_pipeline = list(SettingsManager.cams[cam_name]["pipelines"].values())[0] # def change_camera_values(): # camera.setBrightness(0) @@ -131,13 +133,15 @@ class VisionHandler(metaclass=Singleton): # change_camera_values() cam_area = SettingsManager().cams[cam_name]["video_mode"]["width"] * \ SettingsManager().cams[cam_name]["video_mode"]["height"] + while True: image = child_pipe.recv() - hsv_image = self._hsv_threshold(curr_pipline["hue"], - curr_pipline["saturation"], curr_pipline["value"], - image, curr_pipline["erode"], curr_pipline["dilate"]) + hsv_image = self._hsv_threshold(curr_pipeline["hue"], + curr_pipeline["saturation"], curr_pipeline["value"], + image, curr_pipeline["erode"], curr_pipeline["dilate"]) # if table.getBoolean("Driver_Mode", False): contours = self.find_contours(hsv_image) - filtered_contours = self.filter_contours(contours, cam_area, curr_pipline["area"], curr_pipline["ratio"], curr_pipline["extent"]) + filtered_contours = self.filter_contours(contours, cam_area, curr_pipeline["area"], curr_pipeline["ratio"], + curr_pipeline["extent"]) image = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) child_pipe.send(image) From 5b68083a566b9216ba61a034898c2f6ff8059175 Mon Sep 17 00:00:00 2001 From: ori Date: Sun, 9 Jun 2019 11:00:08 -0700 Subject: [PATCH 7/7] finished multiprocessing --- backend/Main.py | 4 -- backend/app/classes/SettingsManager.py | 26 +++++------ backend/app/handlers/VisionHandler.py | 60 ++++++++++++++------------ 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/backend/Main.py b/backend/Main.py index f965254c8..6ec97a0f6 100644 --- a/backend/Main.py +++ b/backend/Main.py @@ -20,13 +20,9 @@ def run_server(): tornado.ioloop.IOLoop.current().start() - if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) SettingsManager() VisionHandler().run() - while True: - pass - diff --git a/backend/app/classes/SettingsManager.py b/backend/app/classes/SettingsManager.py index d2d8e9ca0..70906bdb6 100644 --- a/backend/app/classes/SettingsManager.py +++ b/backend/app/classes/SettingsManager.py @@ -69,12 +69,12 @@ class SettingsManager(metaclass=Singleton): if os.path.exists(os.path.join(self.cams_path, cam.name + '.json')): with open(os.path.join(self.cams_path, cam.name + '.json'), 'r') as camera: - self.cams[cam.name] = json.load(camera) + self.cams[cam_name] = json.load(camera) if len(self.cams[cam.name]["pipelines"]) == 0: - self.create_new_pipeline(cam_name=cam.name) + self.create_new_pipeline(cam_name=cam_name) else: - self.create_new_cam(cam.name) + self.create_new_cam(cam_name) # Initiate true usb cameras(filters microphones and double cameras) def _init_cameras_info(self): @@ -87,20 +87,20 @@ class SettingsManager(metaclass=Singleton): true_cameras.append(index) cap.release() - for i in true_cameras: - self.usb_cameras_info[usb_devices[i].name] = usb_devices[i] + device_name = usb_devices[i].name + suffix = 0 + + while device_name in self.usb_cameras_info: + suffix += 1 + device_name = f"{device.name}({str(suffix)})" + + self.usb_cameras_info[device_name] = usb_devices[i] # Initiate cscore usb devices def _init_usb_cameras(self): - for i in self.usb_cameras_info: - device = self.usb_cameras_info[i] - device_name = device.name - suffix = 1 - - while device_name in self.usb_cameras: - suffix += 1 - device_name = f"{device.name}({str(suffix)})" + for device_name in self.usb_cameras_info: + device = self.usb_cameras_info[device_name] camera = cscore.UsbCamera(name=device_name, dev=device.dev) diff --git a/backend/app/handlers/VisionHandler.py b/backend/app/handlers/VisionHandler.py index 1301d4d6d..8b511d5e6 100644 --- a/backend/app/handlers/VisionHandler.py +++ b/backend/app/handlers/VisionHandler.py @@ -7,9 +7,10 @@ from cscore import CameraServer from app.classes.SettingsManager import SettingsManager from ..classes.Singleton import Singleton import time -from multiprocessing import Process, Pipe +from multiprocessing import Process import multiprocessing import threading +import zmq class VisionHandler(metaclass=Singleton): @@ -72,43 +73,42 @@ class VisionHandler(metaclass=Singleton): return input_image def run(self): - procs = [] # NetworkTables.startClientTeam(team=SettingsManager.general_settings.get("team_number", 1577)) NetworkTables.initialize("localhost") # NetworkTables.initialize() cs = CameraServer.getInstance() - pipes = [] + port = 5550 for cam_name in SettingsManager().usb_cameras: - threading.Thread(target=self.thred_proc, args=(cs, cam_name)).start() - - def thred_proc(self, cs, cam_name): - async def pipe_send(pipe, data): - pipe.send(data) - - async def pipe_recive(pipe): - return pipe.recv() + threading.Thread(target=self.thread_proc, args=(cs, cam_name, str(port))).start() + port += 1 + def thread_proc(self, cs, cam_name, port="5557"): cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name]) - image = numpy.zeros(shape=(SettingsManager().cams[cam_name]["video_mode"]["width"], - SettingsManager().cams[cam_name]["video_mode"]["height"], 3), dtype=numpy.uint8) - cv_publish = cs.putVideo(name=cam_name, width=SettingsManager().cams[cam_name]["video_mode"]["width"], - height=SettingsManager().cams[cam_name]["video_mode"]["height"]) - parent, child = Pipe() - Process(target=self.camera_process, args=(SettingsManager.usb_cameras[cam_name], cam_name, child)).start() + width = SettingsManager().cams[cam_name]["video_mode"]["width"] + height = SettingsManager().cams[cam_name]["video_mode"]["height"] + + image = numpy.zeros(shape=(width, height, 3), dtype=numpy.uint8) + + cv_publish = cs.putVideo(name=cam_name, width=width, height=height) + + context = zmq.Context() + socket = context.socket(zmq.REQ) + socket.bind("tcp://*:%s" % port) + + p = Process(target=self.camera_process, args=(SettingsManager.usb_cameras[cam_name], cam_name, port)) + p.start() while True: start = time.time() _, image = cv_sink.grabFrame(image) - parent.send(image) - # pipe_send(parent,image) - if parent.poll(): - image = parent.recv() + socket.send_pyobj(image) + image = socket.recv_pyobj() cv_publish.putFrame(image) end = time.time() print(cam_name + " " + str(1 / (end - start))) - def camera_process(self, camera, cam_name, child_pipe): + def camera_process(self, camera, cam_name, port): curr_pipeline = list(SettingsManager.cams[cam_name]["pipelines"].values())[0] @@ -131,11 +131,17 @@ class VisionHandler(metaclass=Singleton): # table.addEntryListenerEx(mode_listener, key="Driver_Mode", # flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE) # change_camera_values() - cam_area = SettingsManager().cams[cam_name]["video_mode"]["width"] * \ - SettingsManager().cams[cam_name]["video_mode"]["height"] + width = SettingsManager().cams[cam_name]["video_mode"]["width"] + height = SettingsManager().cams[cam_name]["video_mode"]["height"] + cam_area = width * height + + context = zmq.Context() + socket = context.socket(zmq.REP) + socket.connect("tcp://localhost:%s" % port) while True: - image = child_pipe.recv() + image = socket.recv_pyobj() + hsv_image = self._hsv_threshold(curr_pipeline["hue"], curr_pipeline["saturation"], curr_pipeline["value"], image, curr_pipeline["erode"], curr_pipeline["dilate"]) @@ -143,5 +149,5 @@ class VisionHandler(metaclass=Singleton): contours = self.find_contours(hsv_image) filtered_contours = self.filter_contours(contours, cam_area, curr_pipeline["area"], curr_pipeline["ratio"], curr_pipeline["extent"]) - image = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) - child_pipe.send(image) + res = self.draw_image(input_image=image, is_binary=False, rectangles=filtered_contours) + socket.send_pyobj(res)