Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/eroniki/build_daq
Browse files Browse the repository at this point in the history
  • Loading branch information
eroniki committed Jun 13, 2019
2 parents bd5fd9c + af8cd07 commit 6099628
Show file tree
Hide file tree
Showing 15 changed files with 762 additions and 14 deletions.
85 changes: 85 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# BUILD_DAQ: A data acquisition system for multi-room, multi camera setup
Maintainer: [Murat Ambarkutuk](http://murat.ambarkutuk.com)

Email: murata@vt.edu

VAST Lab, Mechanical Engineering Department,

Virginia Tech, Blacksburg, VA

# Summary:
This repository contains the necessary tools and packages needed for Steelcase funded project called BUILD.
This project involves with human pose detection in 3D with multiple cameras placed in different room located in Cheatham Hall, Virginia Tech.
In this repository, one can find a various python modules and classes to create a RESTful API to interact with the Image Acquisition system as well as processing the collected images.

# Installation
## Dependencies:
OpenPose is needed to extract poses from the collected images. Please make sure OpenPose is installed correctly (with Python bindings).
You can follow [this link](https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/doc/installation.md) to obtain a comprehensive guide to install Openpose.
## Obtaining the Repository
1. Open a new terminal window with _CTRL+ALT+T_
1. Run the commands sequentially:
Clone the repository:
```
git clone https://github.com/eroniki/build_daq.git
```
Enter to the repository folder:
```
cd build_daq
```
Install the dependencies:
```
sudo -H pip install -r requirements.txt
```
Reboot the system:
```
sudo reboot now
```
# Usage:
Upon completion of the installation, the system can be started directly with
```
python main.py
```
This script creates the REST API and starts serving a WEB-interface with which the system can be manipulated.

One can find the served with interface (locally):
```
http://0.0.0.0:5000
```

or if you'd like to access the system remotely, you can use a link similar to the one in below where _THE_IP_ADRESS_OF_THE_LOCAL_MACHINE_ is the global IP address of the computer serving the system.

```
http://THE_IP_ADRESS_OF_THE_LOCAL_MACHINE:5000
```


# Documentation
## Main Code
The main controller of the code lay in __main.py__ file. This python script creates and initializes all the classes needed in the project.

## Flask App
The basic User Interface is created by using Flask, a web development tool for Python.

All the necessary tools and classes were implemeted in this class, which reside in __app.py__ module.
The documentation of the computer_vision class is automatically generated from the docstrings of the classes and the functions in it.
The documentation is located [here](docs/app.md).
## Utility Class
The documentation of the utility class is automatically generated from the docstrings of the classes and the functions in it.
The documentation is located [here](docs/utils.md).
## Experiment Class
The documentation of the experiment class is automatically generated from the docstrings of the classes and the functions in it.
The documentation is located [here](docs/experiment.md).
## Computer Vision Class
The documentation of the computer_vision class is automatically generated from the docstrings of the classes and the functions in it.
The documentation is located [here](docs/computer_vision.md).
## Pose Detection Class

## Camera Class
The documentation of the camera module and its contents are automatically generated from the docstrings of the classes and the functions in it.
The documentation is located [here](docs/camera.md).

## Calibration Process
This calibration process is provided [here](docs/calibration_process.md)
# Contribution
If you would like to contribute to this project, please make sure you read and understand the contribution workflow.
1 change: 1 addition & 0 deletions _config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
theme: jekyll-theme-midnight
53 changes: 50 additions & 3 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
"""
This module contains a class to create the REST API.
The flask_app class contains all the functions and utilities needed to provide
the REST API.
"""
import numpy as np
import cv2
import json
Expand All @@ -21,7 +27,12 @@


class flask_app(object):
"""docstring for flask_app."""
"""
This module contains a class to create the REST API.
The flask_app class contains all the functions and utilities needed to provide
the REST API.
"""

def __init__(self, key):
super(flask_app, self).__init__()
Expand Down Expand Up @@ -52,14 +63,17 @@ def __init__(self, key):
self.create_endpoints()

def load_users(self):
"""Load users for authorization purposes from the json file."""
return self.um.read_json("users.json")

def load_rooms(self):
"""Load rooms for authorization purposes from the json file."""
devices_data = self.um.read_json("devices.json")
rooms = self.um.parse_rooms(devices_data)
return rooms

def create_endpoints(self):
"""Create API endpoints."""
self.app.add_url_rule("/",
"index",
self.index)
Expand Down Expand Up @@ -184,14 +198,17 @@ def create_endpoints(self):
self.app.view_functions['triangulate'] = self.triangulate

def index(self):
"""Render the homepage."""
return render_template('index.html')

@flask_login.login_required
def video(self, room_name):
"""Render the video page."""
return render_template('video.html', user=room_name)

@flask_login.login_required
def video_feed(self, room_name):
"""Run the cameras in a room."""
if room_name.lower() == "cears":
room_id = 1
elif room_name.lower() == "computer_lab":
Expand All @@ -206,6 +223,7 @@ def video_feed(self, room_name):

@flask_login.login_required
def test_camera(self, camera):
"""Test the camera and return the image."""
dev = list()
for room in self.rooms:
for device in room["devices"]:
Expand All @@ -214,6 +232,7 @@ def test_camera(self, camera):
mimetype='multipart/x-mixed-replace; boundary=frame')

def gen(self, camera):
"""Camera generator for the actual tests."""
img_id = 0
while True:
frame = camera.get_all_frames(img_id)
Expand All @@ -222,7 +241,7 @@ def gen(self, camera):
img_id += 1

def gen_testcamera(self, camera):
"""Video streaming generator function."""
"""Camera generator for the test_camera endpoint."""
cap = cv2.VideoCapture(camera)
retval, frame = cap.read()
cap.release()
Expand All @@ -235,6 +254,7 @@ def gen_testcamera(self, camera):

@flask_login.login_required
def label_experiment(self, exp_id):
"""Create/Update the label of an experiment."""
exp = experiment.experiment(new_experiment=False, ts=str(exp_id))
label = request.form.get('label')
exp.update_metadata(change_label=True, label=label)
Expand All @@ -243,6 +263,7 @@ def label_experiment(self, exp_id):

@flask_login.login_required
def check_experiment(self, id):
"""Provide details of an experiment."""
exp = experiment.experiment(new_experiment=False, ts=id)

start_time = time.time()
Expand Down Expand Up @@ -291,9 +312,9 @@ def check_experiment(self, id):
"pose_detection_processed_images": pd_images}
return render_template('experiment.html', user=user)

# TODO: Implement this
@flask_login.login_required
def clone_experiment(self, id):
"""Clone experiment to the cloud."""
archive_name = os.path.join(os.path.dirname(os.path.realpath(__file__)),
"backup", str(id)+".zip")
cmd = ["rclone", "copy", archive_name, "Team_BUILD:/backup"]
Expand All @@ -302,6 +323,7 @@ def clone_experiment(self, id):

@flask_login.login_required
def list_experiments(self):
"""List all the experiments."""
subfolders = self.um.list_subfolders("data/*/")
experiment_folders = self.um.list_experiments(subfolders)
experiments = list()
Expand All @@ -327,13 +349,15 @@ def list_experiments(self):

@flask_login.login_required
def delete_experiment(self, exp_id):
"""Delete an experiment with the given id."""
folder = self.um.experiment_path(exp_id)
self.um.delete_folder(folder)

return "OK"

@flask_login.login_required
def delete_archive(self, exp_id):
"""Delete the zip file."""
archive_name = os.path.join(os.path.dirname(os.path.realpath(__file__)),
"backup", str(exp_id)+".zip")
self.um.delete_file(archive_name)
Expand All @@ -342,6 +366,7 @@ def delete_archive(self, exp_id):

@flask_login.login_required
def compress_experiment(self, exp_id):
"""Compress the whole data corresponding to an experiment."""
exp_folder = self.um.experiment_path(str(exp_id))[:-1]
exp_folder = os.path.join(os.path.dirname(
os.path.realpath(__file__)), exp_folder)
Expand All @@ -357,6 +382,7 @@ def compress_experiment(self, exp_id):

@flask_login.login_required
def status_room(self, room_name):
"""Check the status of a room."""
if room_name.lower() == "cears":
room_id = 1
elif room_name.lower() == "computer_lab":
Expand All @@ -378,6 +404,7 @@ def status_room(self, room_name):

@flask_login.login_required
def status_all_rooms(self):
"""Check the status of all rooms."""
statements = str()
for room_id in range(2):
devices = self.rooms[room_id]["devices"]
Expand All @@ -396,6 +423,7 @@ def status_all_rooms(self):
return statements

def login(self):
"""Login to the system."""
if flask.request.method == 'GET':
return '''
<form action='login' method='POST'>
Expand Down Expand Up @@ -425,14 +453,17 @@ def login(self):
return 'Bad login'

def logout(self):
"""Logout from the system."""
flask_login.logout_user()
return 'Logged out'

@flask_login.login_required
def protected():
"""Show logged username."""
return 'Logged in as: ' + flask_login.current_user.id

def user_loader(self, email):
"""Check if the user in the user.json file."""
if email not in self.users:
return

Expand All @@ -441,6 +472,7 @@ def user_loader(self, email):
return user

def request_loader(self, request):
"""Handle each request."""
email = request.form.get('email')
if email not in self.users:
return
Expand All @@ -455,9 +487,11 @@ def request_loader(self, request):
return user

def unauthorized_handler(self):
"""If the user is unauthorized, direct him/her to the login page."""
return flask.redirect("/login")

def pose_img(self, exp_id, camera_id, img_id):
"""Employ pose detection on a single image."""
pd = pose_detection()
exp = experiment.experiment(new_experiment=False, ts=exp_id)
room_name = exp.metadata["room"]
Expand All @@ -482,6 +516,10 @@ def pose_img(self, exp_id, camera_id, img_id):
return response

def pose_cam(self, exp_id, camera_id):
"""
Employ pose_detection on the all images with a given experiment and
the camera id.
"""
pd = pose_detection()
exp = experiment.experiment(new_experiment=False, ts=exp_id)
room_name = exp.metadata["room"]
Expand Down Expand Up @@ -530,6 +568,10 @@ def pose_cam(self, exp_id, camera_id):
return "{n} number of images were processed!".format(n=n-1)

def pose_exp(self, exp_id):
"""
Given an experiment id to employ pose_detection on the whole images
collected from all the cameras.
"""
pd = pose_detection()
exp = experiment.experiment(new_experiment=False, ts=exp_id)
ncamera = exp.metadata["number_of_cameras"]
Expand All @@ -547,21 +589,25 @@ def pose_exp(self, exp_id):
return statement

def match_people(self, exp_id):
"""Match people based on feature matching algorithm."""
n = 99999

return "{n} number of images were processed!".format(n=n)

def make_thumbnails(self, exp_id):
"""Create a thumbnail from an image, which contains only one person."""
n = 99999

return "{n} number of images were processed!".format(n=n)

def triangulate(self, exp_id):
"""Triangulate people's locations."""
n = 99999

return "{n} number of images were processed!".format(n=n)

def log(self):
"""Return the system logs. 10 lines."""
lines = tailer.tail(open('logs/status.log'), 10)

statement = ""
Expand All @@ -571,6 +617,7 @@ def log(self):
return statement

def log_n(self, n):
"""Return n number of lines from the system logs."""
lines = tailer.tail(open('logs/status.log'), n)

statement = ""
Expand Down
7 changes: 7 additions & 0 deletions build_doc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pydocmd simple utils.utils.misc+ > docs/utils.md
pydocmd simple camera.VideoCamera++ > docs/camera.md
pydocmd simple experiment.experiment++ > docs/experiment.md
pydocmd simple computer_vision.computer_vision++ > docs/computer_vision.md
pydocmd simple app.flask_app++ > docs/app.md


0 comments on commit 6099628

Please sign in to comment.