From de797b3f1be796745ebc3b42958824c6b5753a1c Mon Sep 17 00:00:00 2001 From: Ariel Noyman Date: Fri, 26 Jun 2020 20:36:07 -0400 Subject: [PATCH] meet CityScope API, post only to grid field --- README.md | 34 ++++++++++++++++--- cityscopy.py | 46 +++++++++----------------- keystone.txt | 4 +-- run.py | 7 ++-- settings/cityscope_hanoi.json | 47 -------------------------- settings/cityscopy.json | 62 +++++++++++------------------------ settings/csepel.json | 47 -------------------------- settings/deepscope.json | 46 -------------------------- settings/grasbrook.json | 53 ------------------------------ settings/mocho.json | 46 -------------------------- settings/urbam.json | 47 -------------------------- 11 files changed, 69 insertions(+), 370 deletions(-) delete mode 100644 settings/cityscope_hanoi.json delete mode 100644 settings/csepel.json delete mode 100644 settings/deepscope.json delete mode 100644 settings/grasbrook.json delete mode 100644 settings/mocho.json delete mode 100644 settings/urbam.json diff --git a/README.md b/README.md index 4121f4a..3812e91 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,18 @@ $ git clone https://github.com/CityScope/CS_CityScoPy.git $ cd CS_CityScoPy ``` -- install packages. To produce a list of needed packages, use `pipreqs`, follow instructions https://github.com/bndr/pipreqs. Or, simply run the app and install packages as they appear in errors. +- install packages. To produce a list of needed packages, use `pipreqs`, follow instructions https://github.com/bndr/pipreqs. Or, simply run the app and install packages as they appear as missing. - tweak `__settings__.json` to fit your cityIO table setup. Read [cityIO documentation](https://github.com/cityscope/cs_cityio_backend/wiki) for proper data structure -- setup a path to your settings file +- in `run.py` setup a path to your settings file ``` -cityscopy_settings_path = "__path__/__settings__.json" +CITYSCOPY_SETTINGS_PATH = "__path__/__settings__.json" ``` - initiate the `Cityscopy` class (see `run.py` example) ``` -cityscopy = Cityscopy(cityscopy_settings_path) +cityscopy = Cityscopy(CITYSCOPY_SETTINGS_PATH) ``` - use one or more of the main methods. 'Blocking' means the method will run forever (while true loop). Advanced users can parallel blocking methods using multithreading. @@ -72,10 +72,36 @@ Scanner will detect colors in arrays of 2d-pixel arrays. Than, these color array Tool will start scanning using whatever keystone data was stored in `keystone.txt` make corrections to the key stone using the sliders or keyboard using `1,2,3,4` to select a corner and `[w,a,s,d]` to move `[up,left,down,right]` the selected corner. Press `k` to save change to file and `ctrl-c` twice [in the terminal window] to exit program +#### output + +the app will attempt sending the resulted scan to cityIO server. If successful, the following JSON format data will appear on the cityIO endpoint defined in `settings.json` + +``` + +{ + "grid": [ + [1, 0], + [1, 0], + [0, 0], + [4, 0], + [-1, -1], + [-1, -1], // no type was found will return -1 as type and -1 as rotation + ... + ], + + ... + other cityIO data + ... +} + +``` + ### `Cityscopy.udp_listener()` ##### emulates local UDP server listener +simple helper method to emulate what a local UDP client might see if `cityscopy` would send scan over localhost + ## Errors OS, Python versions, openCV and peripheral devices such as webcams can sometimes cause issues. If you found and issue, please report it as a Github issue. Here're some encountered issues and their solutions: diff --git a/cityscopy.py b/cityscopy.py index 74524a3..0a9df2e 100755 --- a/cityscopy.py +++ b/cityscopy.py @@ -73,7 +73,7 @@ def __init__(self, path): # load info from json file self.SETTINGS_PATH = path # get the table settings. This is used bu many metohds - self.table_settings = self.parse_json_file('table') + self.table_settings = self.parse_json_file('cityscopy') print('getting settings for CityScopy...') # init corners variables @@ -135,12 +135,12 @@ def scanner_function(self, multiprocess_shared_dict): # get init keystones self.init_keystone = self.get_init_keystone() # define the table params - grid_dimensions_x = self.table_settings['header']['spatial']['nrows'] - grid_dimensions_y = self.table_settings['header']['spatial']['ncols'] + grid_dimensions_x = self.table_settings['nrows'] + grid_dimensions_y = self.table_settings['ncols'] array_of_tags_from_json = self.np_string_tags( - self.table_settings['objects']['cityscopy']['tags']) + self.table_settings['tags']) - array_of_maps_form_json = self.table_settings['header']['mapping']['type'] + array_of_maps_form_json = self.table_settings['type'] # init type list array TYPES_LIST = [] @@ -149,7 +149,7 @@ def scanner_function(self, multiprocess_shared_dict): OLD_CELL_COLORS_ARRAY = [] # serial num of camera, to switch between cameras - camPos = self.table_settings['objects']['cityscopy']['camId'] + camPos = self.table_settings['camId'] # try from a device 1 in list, not default webcam video_capture = cv2.VideoCapture(camPos) time.sleep(1) @@ -206,7 +206,7 @@ def scanner_function(self, multiprocess_shared_dict): # else if camera capture is ok else: # mirror camera - if self.table_settings['objects']['cityscopy']['mirror_cam'] is True: + if self.table_settings['mirror_cam'] is True: this_frame = cv2.flip(this_frame, 1) # warp the video based on keystone info keystoned_video = cv2.warpPerspective( @@ -251,7 +251,7 @@ def scanner_function(self, multiprocess_shared_dict): thisColor = DICTIONARY_COLORS[scannerCol] # ? only draw vis if settings has 1 in gui - if self.table_settings['objects']['cityscopy']['gui'] is True: + if self.table_settings['gui'] is True: # draw rects with frame colored by range result cv2.rectangle(keystoned_video, (x+scanner_reduction, @@ -282,7 +282,7 @@ def scanner_function(self, multiprocess_shared_dict): # else don't do it pass - if self.table_settings['objects']['cityscopy']['gui'] is True: + if self.table_settings['gui'] is True: # draw arrow to interaction area self.ui_selected_corner( video_resolution_x, video_resolution_y, keystoned_video) @@ -356,7 +356,7 @@ def get_scanner_pixel_coordinates(self, grid_dimensions_x, grid_dimensions_y, vi pixel_coordinates_list = [] # define a cell gap for grided cases [plexi table setup] - cells_gap = self.table_settings['objects']['cityscopy']['cell_gap'] + cells_gap = self.table_settings['cell_gap'] # create the 4x4 sub grid cells for y in range(0, grid_dimensions_y): @@ -389,8 +389,8 @@ def np_string_tags(self, json_data): # 2nd proccess to def create_data_json(self, multiprocess_shared_dict): - self.table_settings = self.parse_json_file('table') - SEND_INTERVAL = self.table_settings['objects']['cityscopy']['interval'] + self.table_settings = self.parse_json_file('cityscopy') + SEND_INTERVAL = self.table_settings['interval'] # initial dummy value for old grid old_scan_results = [-1] SEND_INTERVAL = timedelta(milliseconds=SEND_INTERVAL) @@ -400,7 +400,7 @@ def create_data_json(self, multiprocess_shared_dict): from_last_sent = datetime.now() - last_sent if (scan_results != old_scan_results) and from_last_sent > SEND_INTERVAL: try: - if self.table_settings['objects']['cityscopy']['cityio'] is True: + if self.table_settings['cityio'] is True: self.send_json_to_cityIO(json.dumps(scan_results)) else: self.send_json_to_UDP(scan_results) @@ -421,7 +421,7 @@ def send_json_to_cityIO(self, cityIO_json): ''' # defining the api-endpoint API_ENDPOINT = "https://cityio.media.mit.edu/api/table/update/" + \ - self.table_settings['header']['name'] + "/grid/" + self.table_settings['cityscope_project_name'] + "/grid/" # sending post request and saving response as response object req = requests.post(url=API_ENDPOINT, data=cityIO_json) if req.status_code != 200: @@ -430,20 +430,6 @@ def send_json_to_cityIO(self, cityIO_json): ################################################## - def init_table(self): - json_struct = self.table_settings - cityIO_json = json.dumps(json_struct) - # defining the api-endpoint - API_ENDPOINT = "https://cityio.media.mit.edu/api/table/update/" + \ - self.table_settings['header']['name'] - # sending post request and saving response as response object - req = requests.post(url=API_ENDPOINT, data=cityIO_json) - if req.status_code != 200: - print("cityIO might be down. so sad.") - print("init table on cityIO", req) - - ################################################## - def send_json_to_UDP(self, scan_results): # defining the udp endpoint UDP_IP = "127.0.0.1" @@ -703,7 +689,7 @@ def keystone(self): print('keystone path:', self.KEYSTONE_PATH) # serial num of camera, to switch between cameras - camPos = self.table_settings['objects']['cityscopy']['camId'] + camPos = self.table_settings['camId'] # try from a device 1 in list, not default webcam WEBCAM = cv2.VideoCapture(camPos) time.sleep(1) @@ -730,7 +716,7 @@ def selectFourPoints(): cv2.setMouseCallback('canvas', save_this_point) # read the WEBCAM frames _, self.FRAME = WEBCAM.read() - if self.table_settings['objects']['cityscopy']['mirror_cam'] is True: + if self.table_settings['mirror_cam'] is True: self.FRAME = cv2.flip(self.FRAME, 1) # draw mouse pos cv2.circle(self.FRAME, self.MOUSE_POSITION, 10, (0, 0, 255), 1) diff --git a/keystone.txt b/keystone.txt index eb746c5..1699e07 100644 --- a/keystone.txt +++ b/keystone.txt @@ -1,4 +1,4 @@ -6.060000000000000000e+02 3.470000000000000000e+02 -9.380000000000000000e+02 3.400000000000000000e+02 +5.890000000000000000e+02 3.060000000000000000e+02 +9.380000000000000000e+02 3.230000000000000000e+02 6.020000000000000000e+02 6.890000000000000000e+02 9.640000000000000000e+02 6.730000000000000000e+02 diff --git a/run.py b/run.py index 5718002..9cd7d19 100755 --- a/run.py +++ b/run.py @@ -58,15 +58,12 @@ ''' ) - cityscopy_settings_path = "settings/cityscopy.json" + CITYSCOPY_SETTINGS_PATH = "settings/cityscopy.json" # init cityscopy class - cityscopy = Cityscopy(cityscopy_settings_path) + cityscopy = Cityscopy(CITYSCOPY_SETTINGS_PATH) # run CityScopy main methods - # keystone the scanned area # cityscopy.keystone() - # create new table instance on cityIO - cityscopy.init_table() # scan the grid and send to cityIO cityscopy.scan() # start local UDP comms diff --git a/settings/cityscope_hanoi.json b/settings/cityscope_hanoi.json deleted file mode 100644 index 1bce76c..0000000 --- a/settings/cityscope_hanoi.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "table": { - "header": { - "name": "cityscope_hanoi", - "spatial": { - "nrows": 15, - "ncols": 15, - "physical_longitude": -71.1009981, - "physical_latitude": 42.3582145, - "longitude": -71.1009981, - "latitude": 42.3582145, - "cellSize": 100, - "rotation": 0 - }, - "owner": { - "name": "Arnaud Grignard", - "title": "", - "institute": "City Science MIT Media Lab" - }, - "block": ["type", "rotation"], - "mapping": { - "type": ["0", "1", "2", "3", "4", "5"], - "rotation": ["0", "1", "2", "3"] - } - }, - "grid": [], - "objects": { - "cityscopy": { - "interval": 250, - "gui": true, - "cityio": true, - "camId": 0, - - "tags": [ - "1100110000000000", - "0011001111111111", - "1100110000110011", - "0000000011111111", - "0000000000000000", - "1111111111111111" - ], - "cell_gap": 0, - "mirror_cam": false - } - } - } -} diff --git a/settings/cityscopy.json b/settings/cityscopy.json index a05f45b..62f2ee4 100644 --- a/settings/cityscopy.json +++ b/settings/cityscopy.json @@ -1,46 +1,22 @@ { - "table": { - "header": { - "name": "cityscopy", - "spatial": { - "nrows": 10, - "ncols": 10, - "physical_longitude": 0, - "physical_latitude": 0, - "longitude": 0, - "latitude": 0, - "cellSize": 500, - "rotation": 0, - "projection": 3395 - }, - "owner": { - "name": "Ariel Noyman", - "title": "", - "institute": "City Science MIT Media Lab" - }, - "block": ["type", "rotation"], - "mapping": { - "type": ["0", "1", "2", "3"], - "rotation": ["0", "1", "2", "3"] - } - }, - "grid": [], - "objects": { - "cityscopy": { - "scan": false, - "camId": 0, - "interval": 250, - "gui": true, - "cityio": true, - "tags": [ - "0000000000000000", - "1111111111111111", - "1111111100000000", - "1000000000000000" - ], - "cell_gap": 0, - "mirror_cam": false - } - } + "cityscopy": { + "cityscope_project_name": "cityscopy", + "type": ["0", "1", "2", "3", "4", "5"], + "rotation": ["0", "1", "2", "3"], + "nrows": 10, + "ncols": 10, + "scan": false, + "camId": 0, + "interval": 250, + "gui": true, + "cityio": true, + "tags": [ + "0000000000000000", + "1111111111111111", + "1111111100000000", + "1000000000000000" + ], + "cell_gap": 0, + "mirror_cam": false } } diff --git a/settings/csepel.json b/settings/csepel.json deleted file mode 100644 index 989ddd3..0000000 --- a/settings/csepel.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "table": { - "header": { - "name": "csepel", - "spatial": { - "nrows": 15, - "ncols": 15, - "physical_longitude": 19.050979614257812, - "physical_latitude": 47.43630292431787, - "longitude": 19.050979614257812, - "latitude": 47.43630292431787, - "cellSize": 50, - "rotation": 260, - "projection": 3836 - }, - "owner": { - "name": "Ariel Noyman", - "title": "", - "institute": "City Science MIT Media Lab" - }, - "block": ["type", "rotation"], - "mapping": { - "type": ["0", "1", "2", "3"], - "rotation": ["0", "1", "2", "3"] - } - }, - "grid": [], - "objects": { - "cityscopy": { - "scan": false, - "camId": 0, - - "interval": 250, - "gui": true, - "cityio": true, - "tags": [ - "0000000000000000", - "1111111111111111", - "1111111100000000", - "1000000000000000" - ], - "cell_gap": 0, - "mirror_cam": true - } - } - } -} diff --git a/settings/deepscope.json b/settings/deepscope.json deleted file mode 100644 index b064ac7..0000000 --- a/settings/deepscope.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "table": { - "header": { - "name": "deepscope", - "spatial": { - "nrows": 16, - "ncols": 16, - "physical_longitude": 0, - "physical_latitude": 0, - "longitude": 0, - "latitude": 0, - "cellSize": 16, - "rotation": 0 - }, - "owner": { - "name": "Ariel Noyman", - "title": "", - "institute": "City Science MIT Media Lab" - }, - "block": ["type", "rotation"], - "mapping": { - "type": ["0", "1", "2", "3", "4"], - "rotation": ["0", "1", "2", "3"] - } - }, - "grid": [], - "objects": { - "cityscopy": { - "interval": 200, - "camId": 0, - - "gui": true, - "cityio": 1, - "tags": [ - "1110111111111111", - "1100110000000000", - "1111111100110011", - "0011001111001100", - "1111111100000000" - ], - "cell_gap": 0, - "mirror_cam": true - } - } - } -} diff --git a/settings/grasbrook.json b/settings/grasbrook.json deleted file mode 100644 index b928065..0000000 --- a/settings/grasbrook.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "table": { - "grid": [], - "header": { - "block": ["type", "rotation"], - "mapping": { - "rotation": ["0", "1", "2", "3", "4"], - "type": [ - "street", - "housing", - "housing2", - "working", - "working_2" - ] - }, - "name": "grasbrook", - "owner": { - "institute": "City Science MIT Media Lab", - "name": "Ariel Noyman", - "title": "" - }, - "spatial": { - "cellSize": 16, - "latitude": 53.532, - "longitude": 10.0121, - "ncols": 10, - "nrows": 10, - "physical_latitude": 53.532, - "physical_longitude": 10.0121, - "rotation": 144.5 - } - }, - "objects": { - "cityscopy": { - "cell_gap": 0, - "camId": 0, - - "cityio": true, - "gui": true, - "interval": 200, - "mirror_cam": true, - "tags": [ - "0000000000000000", - "0011001100000000", - "1100110000110011", - "1111111100110011", - "1111111100000000", - "1111111111111111" - ] - } - } - } -} diff --git a/settings/mocho.json b/settings/mocho.json deleted file mode 100644 index 10a9dfd..0000000 --- a/settings/mocho.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "table": { - "header": { - "name": "mocho", - "spatial": { - "nrows": 16, - "ncols": 16, - "physical_longitude": 53.5369, - "physical_latitude": 10.00748, - "longitude": 53.536898, - "latitude": 10.007472, - "cellSize": 16, - "rotation": 0 - }, - "owner": { - "name": "Ariel Noyman", - "title": "", - "institute": "City Science MIT Media Lab" - }, - "block": ["type", "rotation"], - "mapping": { - "type": ["0", "1", "2", "3", "4"], - "rotation": ["0", "1", "2", "3"] - } - }, - "grid": [], - "objects": { - "cityscopy": { - "interval": 500, - "gui": true, - "cityio": 1, - "camId": 0, - - "tags": [ - "1110111111111111", - "0011001111001100", - "1100110000000000", - "1111111100110011", - "0000000000000000" - ], - "cell_gap": 0, - "mirror_cam": false - } - } - } -} diff --git a/settings/urbam.json b/settings/urbam.json deleted file mode 100644 index 8f11fa3..0000000 --- a/settings/urbam.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "table": { - "header": { - "name": "urbam", - "spatial": { - "nrows": 15, - "ncols": 15, - "physical_longitude": -71.1009981, - "physical_latitude": 42.3582145, - "longitude": 21.028511, - "latitude": 105.804817, - "cellSize": 100, - "rotation": 0 - }, - "owner": { - "name": "Arnaud Grignard", - "title": "", - "institute": "City Science MIT Media Lab" - }, - "block": ["type", "rotation"], - "mapping": { - "type": ["0", "1", "2", "3", "4", "5"], - "rotation": ["0", "1", "2", "3"] - } - }, - "grid": [], - "objects": { - "cityscopy": { - "interval": 250, - "gui": true, - "camId": 0, - - "cityio": true, - "tags": [ - "1100110000000000", - "0011001111111111", - "1100110000110011", - "0000000011111111", - "0000000000000000", - "1111111111111111" - ], - "cell_gap": 0, - "mirror_cam": false - } - } - } -}