I Built a Full-Stack Vehicle Counting Web App 🚗

In May, 2017, I was fortunate to be hired to design and implement a web application for a state transportation agency. The research group I was working with had developed command-line vehicle-counting tools, which worked well but could be quite tedious for non-technical people to operate. As a result, the agency was looking for a more user-friendly and easily-accessible client-side solution.

Background

In conducting transportation research, it’s crucial to be able to estimate the volume of vehicles passing through a given intersection and to categorize their movements. This information helps target locations for infrastructure and traffic control improvements.

Ideally, counts could be obtained from a network of physical sensors and recorded automatically. But a vast network of traffic cameras already exists and algorithmic detection of objects in video has become increasingly more accurate, so determining counts by camera is a more maintainable and cost-effective solution. This is where my app comes in.

Requirements

Working with my advisor and the traffic researchers, we were able to develop a list of security, functional, and usability requirements for the application, some of which are below:

  • For security, the app should be available only to authenticated users and should be served over HTTPS. 🔒
  • Users should be able to add new traffic cameras and view camera locations on a map view. 🎥
  • Users should be able to upload and delete traffic videos and edit their metadata. 📼
  • Upon uploading a file, the system should run a tool which counts the number of vehicles in the video and records the result. ⚙️
  • Users should be able to draw paths on top of a video and receive vehicle counts along each path. ✏️
  • Users should be able to download a generated CSV file, per camera, of results for each path. 📊

Tech Stack

As the sole developer starting this project from scratch, I had the unusual freedom of choosing which technologies would make the product easiest to implement and most maintainable.

With frequent data exchange and event emission among components, a jQuery solution would have quickly become unmaintainable. Although I have some familiarity with all three major front-end frameworks (Angular, React, and Vue), I decided on Vue because it performs just as quickly as React but features what I consider to be a simpler syntax, easily-integrated CSS transitions, and simple single-file components. Its popularity is also rising enough that it should still be around for a while in this rapidly-changing JavaScript world. 😊

Node’s single-threaded event-driven model handles lots of requests like a champ, which was necessary as the app polls frequently for video processing and counting progress. I also love JavaScript’s expressiveness and its ability to handle asynchronous code effortlessly, especially with the modern improvements to its specification.

  • Filesystem monitor/task runner — Node.js child-process module
  • Data store — MongoDB with Mongoose ODM

Combined with Node, MongoDB’s JSON-like records offer a seamless transition between data and JavaScript objects. The database is also easy to query using plain JavaScript. Using Mongoose ensures collection consistency and gives the ability to “join” data from different collections, similar to a relational database.

Design and Development

I had been working with web technologies for about two years before beginning the app, which was my first paid development project, but I had never implemented a system of this scale. Challenges included designing the client interface and implementing it while simultaneously learning Vue, but also architecting the entire back end — a true full-stack task!

I began with a rough UI sketch drawn by my advisor and was able to quickly implement it using Bootstrap. The stale Bootstrap components really made the app, just… blah… so I soon found myself iterating through other designs. I eventually settled on a custom, modern layout with lots of sliding transition effects. Thanks to Vue & CSS3, the page was blazing-fast even with these! ✨

An early design 🙀
The first iteration 😿
The sleek final design I settled on 😺

The back end required quite a bit of planning: how to implement authentication, which API routes to expose, which data to store and how, how to handle file uploads and automatically process them, and plenty of other technical and architectural challenges.

Drawing paths on top of a playing video was accomplished using the wonderful Fabric.js library, bound to a canvas overlaid on the video. Each path was serialized to the database as a list of fractional coordinates relative to the original video frame size, so that they could easily and accurately be redrawn in a window of any size.

I decided to implement separate API and processing servers to make potential future scaling to multiple processing servers much easier. The monitoring/processing server uses the npm watch module to detect a newly uploaded file and, if it’s a video format, spawns a child process to track objects in the video. After tracking, a call to the API server stores total counts for the video and the associated camera.

Results

Although the product has come a long way and has now entered the user testing phase, there is always room for improvement. Features to be added include filtering cameras based on uploader and other criteria, allowing favorite cameras, allowing more detailed path information and filtering, and the addition of onscreen tracking boxes for each detected object in a frame.

Soon I will be moving on to other opportunities. But the experience of building this app has helped me sharpen many skills and even learn completely new ones. In the course of its development, I…

  • Iterated on a basic design sketch to arrive at an engaging and modern user experience 🕶️
  • Gained familiarity with forging complex Vue.js and Node.js apps according to best practices 🛠️
  • Configured nginx to host parts of the project on separate servers while allowing them to communicate seamlessly 🛰️
  • Designed a data model to logically and efficiently organize the application’s various data 🗄️
  • Implemented token-based (JWT) authentication from the ground-up, on both server and client 🔑
  • Incorporated feedback from clients and my advisor to refine and turn out a professional-grade product 👔

This has been an incredible journey which has only grown my passion for developing useful and interactive full-stack web applications. I hope to work on many more projects like this in the future!

Thanks for reading!


If you’d like to learn more about this project or are looking for someone to develop your next big idea, please contact me on Twitter or drop me a line on my website!