Starting as a fun Jonah Group project, the Snack Watcher is designed to watch the company's "Snack Table". If there are some new "Snacks" presented on the "Snack Table", it can be used to report the event onto chat channels, emails or messages saying "Snack Happened!", posting an image and trying to classify the snacks that it observed. It supports both as web site for interactive snack viewing and RESTful API for programmatic snack querying.
It is open source in hope of advancing the sharing spirit and snacking fun within your company!
Snack Watcher Team has a blog site hosted at
posting the latest development articles, interesting researches and on-going discussions on the Snack Watcher project.
Snack Classifier, which is an independent image classification Microservice, it can extend the functionality of Snack Watcher.
Before diving into the technical details, a brief overview of how Snack Watcher could benefit the use case of watching a "Snack Table". Also, much effort has been devoted to make it working well with a Raspberry Pi 2 or 3, such that the cost of setup will be minimal and elegant in the geekiest way. The term snack-web
as a synonym as "Snack Watcher Web" in here.
- Raspberry Pi setup on the "Snack Table"
- Webcam connected to watch at the "Snack Table"
snack-web
captured image sample with blob status (green means New, red means removed) and blob classification (they looks like "package" from classifier training)
snack-web
is a web application showing the result of snack watching, which has been designed to configure and run with Raspberry Pi 2 or 3.
snack-web
could be driven, either manually (via Web) or programmatically (via RESTful API) to take pictures and push the snapshots into the static/images
directory. The RESTful API approach to programmatically watch and return the images should be the key feature to integrate with a system, providing greater utilities to report the snack status.
Note: snack-web
will be served from http://localhost:8000 by default. If this is not the case, replace the hostname with the actual configured site location.
The following illustrated the front page of snack-web
, the front page menu items are listed:
- Links: display the last N snack captured image and it's processing stages
- Calibrate: take a background image for calibrating the background colour
- Snap: snap a snack image from the camera now
- Teach: (Require advanced setup) Currently still under heavy development, the teaching module is designed to interactively classify snack for future training. This required classifier setup to work.
For each snack image capture, it collects the set of processing stage images for debugging and understanding how the snacks are identified. For each blob that the system detected, it will be stored for displaying and training. The colour coded blobs represent, green is the new detected blob, yellow is the stationary blob, and red is the removed blob. By click on each image bar, a larger image will be shown for detail inspections.
snack-web
is built on the popular OpenCV and SimpleCV.
OpenCV is a C++ library of programming functions mainly aimed at real-time computer vision. SimpleCV provides the Python wrapper on top of OpenCV, simplified many image processing, classifying and displaying functions.
Learning from this Install Notes, it describes a super easy and fast way to setup your Raspberry Pi with OpenCV with SimpleCV module, avoiding many painful steps described by others blogs
Simply run the following shell commands to install the OpenCV and it's necessary dependencies:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python-setuptools
sudo apt-get install python-pip
sudo apt-get install ipython python-opencv python-scipy python-numpy python-pygame
After all OpenCV and dependencies are installed, we could proceed to install SimpleCV, a wrapper API that make computer vision really easy. It could be download from github and install from the source.
sudo pip install https://github.com/sightmachine/SimpleCV/zipball/master
sudo pip install svgwrite
Assumed that OpenCV and SimpleCV are installed, snack-web
Python requirements can be installed by,
sudo pip install -r requirements.txt
snack-web
is using mongodb
as the storage for image attributes. The instructions of installing Raspberry Pi mongodb binaries should be followed closely, which has been confirmed to work Raspberry Pi 2 & 3.
As a quick mongodb
service guide,
- starting up the
mongodb
service by
sudo service mongodb start
- checking the status by
sudo service mongodb status
- shutting down cleanly by
sudo service mongodb stop
The default configuration of the system located in configuration/environment.ini
(refer to the Configuration Keys table for their usage)
Keys: Debug is True, Use Web Camera is False
The system is set to DEBUG=True
after the first checkout. When DEBUG is true, instead of using a camera to capture images, the system will be a set of simulated cookie images to demonstrate the system behaviour. At this stage, you simply want to verify the system has been installed and configured properly with MongoDB. The default MongoDB is configured by DB_CONNECT_STRING
to run on localhost
.
Once the requirements are installed, mongodb has started and the system has been configured, snack-web
app is started with:
python manage.py runserver
Navigate to http://localhost:8000 to see the snack-web
front page.
Click Calibrate
to perform initialization
Click Snap
to capture an image (simulated image capture since DEBUG=True)
Click Links
to see the captured image list
Keys: Debug is False, Use Web Camera is True
After verifying the system has been installed and connected successfully with Step 1, the camera could be switch ON by USE_WEB_CAMERA=True
. You can use the Snap
menu function to force capture an image. You should see the latest captured image has been processed and shown on the Links
menu. Congratulation! the snack watcher web application is configured and operational.
Once the USB camera has been plugged-in, snack-web
app is started with:
python manage.py runserver
Navigate to http://localhost:8000 to see the snack-web
front page.
- Click
Calibrate
to perform initialization - Click
Snap
to capture a Camera image - Click
Links
to see the captured image list
The system is operational after the previous 2 steps. If you like to continue tuning the system behaviours. The following configuration keys are available:
Table: snack-web Configuration Keys
Section | Key | Default | Description |
---|---|---|---|
system | HOST | 0.0.0.0 | snack-web is serving from this IP address |
system | PORT | 8000 | snack-web is running from this port |
system | DEBUG | True | switch debugging mode |
system | HAS_FTP | False | switch ftp transfer mode |
system | PRE_INIT_CAMERA | False | switch if system should pre-initial the camera |
system | USE_WEB_CAMERA | False | switch if using USB web camera |
system | USE_MOTION_CAMERA | False | switch if using motion snapshot as the capture image |
system | MOTION_CAMERA_SNAPSHOT | lastsnap.jpg | location to find motion snapshot image |
system | CROP_IMAGE_BORDER | (25,25) | crop the captured image border by (X,Y) amount. The top left corner from (0,0) to (X,Y) will be used by auto background calibration if BACKGROUND_AUTO_CALIBRATE is True. |
system | SHOW_REMOVED_SNACKS | True | render the removed (disappeared) snacks with red boxes |
system | USE_COLOR_DISTANCE_FOR_BACKGROUND | True | calculate the background difference by color (R,G,B) distance metrics |
system | BACKGROUND_MASK_THRESHOLD | 100 | distance from the calibrated background color which the pixels are thresholded as background. |
system | BACKGROUND_AUTO_CALIBRATE | True | switch if using the top left corner defined by CROP_IMAGE_BORDER as background calibration sample. |
database | DB_CONNECT_STRING | {mongodb URL} | connect to the specified mongodb URL |
database | DB | {mongodb name} | connect to the specified mongodb name |
classifier | USE_CLASSIFIER | False | (Advanced) switch to use api-classifier RESTful service to classify a blob from the captured image |
classifier | CLASSIFIER_URL | {api-classifier URL} | (Advanced) connect to the specified api-classifier URL for classifying services |
ftp | FTP_HOST | {ftp host} | connect to the specified host for image upload |
ftp | FTP_PORT | {ftp port} | port for remote ftp connection |
ftp | HTTP_PORT | {http port} | port for remote http connection |
ftp | FTP_USER | {ftp username} | ftp username for login if needed |
ftp | FTP_PASS | {ftp password} | ftp password for login if needed |
http://snack-web:8000/api
(Replace snack-web
with your host location.)
The images and operations can also be accessed via RESTful API. The available URI resources are listed in this table.
Table: snack-web RESTful API
API | HTTP | Description |
---|---|---|
/snacks/ | GET | return all images, that could be a lot of images |
/snacks/snap | GET | take a snapshot and return the latest image. This call takes a snapshot and returns the processed image. |
/snacks/id/{id} | GET | return image {id}. This call gets an image by the database id. If it is not found, null is returned. |
/snacks/state/{class_state} | GET | Get all blobs matched the given class_state. This call gets a list of blobs filtered by c1ass_state. |
/snacks/state | PUT | Update blobs state info by _id. This call accepts a list of (id, c1ass, c1ass_state) objects, updates their associated blobs in the database. |
/snacks/class/names | GET | Get the list of class names. This call returns a list of the class names that a blob can be classified by. |
/snacks/last | GET | Get the last image. This call returns the latest image by date_created DESC. If none exist, null is returned. |
/snacks/last/{int:n} | GET | Get the last n images. This call returns a list of the latest n images by date_created DESC. |
/snacks/last/summary | GET | Get the latest summary. This call returns a summary of the latest processed images including the new, duplicate and removed blobs. If no images exist, it returns null. |
When a camera snapshot is taken, The images will be written into a creation folder according to the snapshot's date-time,
snack-{{year}_{month}_{day}}-{{hour}_{minute}_{second}}
e.g. snack-2015_06_17-13_14_58
is created at date 2015-06-17
and time 13:14:58
.
The result JSON for an image, for example, requests for the last image using curl
command.
curl http://snack-web:8000/api/snacks/last
For a list of images, for example, requests for all snack images using curl
command.
curl http://snack-web:8000/api/snacks/
Supervisor daemon is a host process, monitoring a running process and starting the monitored process if necessary. On the remote host, the supervisor configuration should be installed under /etc/supervisor/conf.d
directory.
We have prepared deployment/supervisor/snack-web.conf
for supervisor, just need to copy to the configuration directory.
sudo cp snack-web.conf /etc/supervisor/conf.d/.
After the snack-web.conf
has been installed, we can start the supervisor daemon to monitor the snack-web
process.
sudo supervisord -c /etc/supervisor/supervisord.conf
We can further control the supervisor daemon, to see it's status, to start and to stop monitored processes.
sudo supervisorctl status
sudo supervisorctl start
sudo supervisorctl stop