=> Download latest release <=

A tool for scanning interactions with a tangible LEGO grid and networking MIT CityScope Projects in Python

CityScoPy is the main component of an interactive MIT CityScope table. It is used for initiating and later run a interactive CityScope instance in any arbitrary geolocated area in the world. CityScoPy can capture, key-stone, scan and send uniquely tagged arrays of 2-dimension physical bricks.


  • install python 3.4 or higher
  • clone this repo
$ git clone
$ cd CS_CityScoPy
  • install packages. To produce a list of needed packages, use pipreqs, follow instructions 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 for proper data structure
  • in setup a path to your settings file
CITYSCOPY_SETTINGS_PATH = "__path__/__settings__.json"
  • initiate the Cityscopy class (see example)
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.
cityscopy.keystone()initial keystone and save to filex
cityscopy.scan()main scanning and sending methodx
cityscopy.udp_listener()emulate local UDP server listenerx
  • in terminal run the tool using $

Class methods


Initial keystone and save to file
  • the tool will start given a cam is connected and working
  • Select 4 corners [up right, up left, bottom right, bottom left, at this order] of keystone region Note: no need to exactly select the corners, as these are only initial guides for scanner method
  • keystone.txt and close


main scanning and sending method

Scanner will detect colors in arrays of 2d-pixel arrays. Then, these color arrays will be compared to list of tags attribute of a given __settings__.json file. Then the tool will return a list of type and rotation for each of the scanned arrays. This list is then converted to cityIO acceptable JSON format and can be sent using POST request.

options in __settings__.json
"cityscopy": {
"cityscope_project_name": "cityscopy", // table name
"type": ["0", "1", "2", ...], // types names
"rotation": ["0", "1", "2", "3"], // default rotations (0, 90, 180, 270)
"nrows": 10, // number of columns to scan
"ncols": 10, // number of rows to scan
"cell_gap": 10, // spacing between grid fields when using physical grid
"camId": 0, // openCV will pick `camID` camera (usually 0)
"interval": 250, // in ms, how many time should this send the packet
"gui": true, // toggle GUI display
"cityio": true, // toggle UDP or cityIO delivery
"tags": [ // 16 digit strings of types being scanned [`1000000100000000`]
"mirror_cam": false

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


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


emulates local UDP server listener

simple helper method to emulate what a local UDP client might see if cityscopy would send scan over localhost


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:


Please see LICENSE file for more details.This tool may require libraries which are subject to own licensing.


Please use GitHub Issues and PR interface for contributions.

Maintained by Ariel Noyman

Repo contributors