“Eyes on the Street”: Estimating Natural Surveillance Along Amsterdam’s City Streets Using Street-Level Imagery
This code belongs to the paper “Eyes on the Street”: Estimating Natural Surveillance Along Amsterdam’s City Streets Using Street-Level Imagery, available here.
For a more expansive document on the research and code, see this document.
Neighborhood safety and its perception are important determinants of citizens’ health and well-being. Contemporary urban design guidelines often advocate urban forms that encourage natural surveillance or “eyes on the street” to promote community safety. However, assessing a neighborhood’s level of natural surveillance is challenging due to its subjective nature and a lack of relevant data. We propose a method for measuring natural surveillance at scale by employing a combination of street-level imagery and computer vision techniques. We detect windows on building facades and calculate sightlines from the street level and surrounding buildings across forty neighborhoods in Amsterdam, the Netherlands. By correlating our measurements with the city’s Safety Index, we also validate how our method can be used as an estimator of neighborhood safety. We show how perceived safety varies with window level and building distance from the street, and we find a non-linear relationship between natural surveillance and (perceived) safety.
This project was originally written and tested in Python 3.9, but should work with newer versions of Python.
Clone the repository:
git clone https://github.com/timovanasten/natural-surveillance.git
cd natural-surveillanceOptionally, create and activate a virtual environment:
For MacOS/Linux:
python3 -m venv ./venv
source ./venv/bin/activateor for Windows:
python3 -m venv ./venv
.\venv\Scripts\activate.batLastly, install the dependencies:
pip install -r requirements.txtThe trained model used for detecting building openings within the street view imagery can be downloaded here.
Download resnet18_model_latest.pth.tar. Next, create the /labeling/heatmap_fusion/model directory. For example by running
mkdir ./labeling/heatmap_fusion/modeland place resnet18_model_latest.pth.tar into the natural-surveillance/labeling/heatmap_fusion/model directory.
Alternatively, point to the path the model is located in settings.yaml.
Obtain an API key for the Google Street View Static API within the Google Cloud platform and add it to .secrets.yaml.
To not overshoot available credit, enter your credit in dollar in data/gsv_budget.txt.
A dataset in CSV format with the estimated natural surveillance scores for over 6500 street segments spread over 43 neighborhoods in Amsterdam can be found in the data/results directory.
To create a nice visualization of the dataset, such as the one above, check out kepler.gl.
A dataset containing the estimated geolocation of 872 360 building openings is also available. Please contact me for access.
The code that was ran for the experiment outlined in the thesis document can be found in main.py.
To obtain your own data, update the EPSG of the local coordinate reference system in settings.yaml to one of the area of interest and create a Pipeline object using either a polygon, address or neighborhood name*:
from shapely.geometry import Polygon
from pipeline import Pipeline, PipelineConfig, PipelineStep
# Option 1: using area polygon
polygon = Polygon([4.4359826, 52.2269100],
...,
[4.4364993, 52.2271558])
config = PipelineConfig(pipeline_name,
field_of_view,
sightline_distance,
viewing_angle,
polygon=polygon)
# Option 2: using address
config = PipelineConfig(pipeline_name,
field_of_view,
sightline_distance,
viewing_angle,
address="Mekelweg 4, Delft",
distance_around_address=100)
# Option 3: using neighborhood name
config = PipelineConfig(pipeline_name,
field_of_view,
sightline_distance,
viewing_angle,
neighborhood_name="Staatliedenbuurt")
# Create the pipeline
pipeline = Pipeline(config)
# Execute all steps in the pipeline:
pipeline.execute_all()
# ...or only certain step(s):
pipeline.execute_step(PipelineStep.LOCALIZE_OPENINGS)
pipeline.execute_up_to_and_including(PipelineStep.LOCALIZE_OPENINGS)
pipeline.execute_from(PipelineStep.CALCULATE_SIGHTLINES)
# Pipelines are saved after each step.
# To load a prevously saved pipeline into memory use:
pipeline = Pipeline.load_from_state_file(pipeline_name)*This repository only contains the neighborhood geometries for Amsterdam. To use other neighborhood boundaries,
alter neighborhoods.py and settings.yaml.
For any questions or requests, feel free to contact me at timovanasten@gmail.com.




