Skip to content

Commit

Permalink
Created top-level model in 'model' directory (__init__.py)
Browse files Browse the repository at this point in the history
  • Loading branch information
LewisCollum committed Aug 29, 2020
1 parent 25506e4 commit 441b0c7
Show file tree
Hide file tree
Showing 60 changed files with 155 additions and 105 deletions.
83 changes: 24 additions & 59 deletions server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import os
from flask import Flask, render_template, Response, request, jsonify
import cv2

import laneModel
import signModel
import vehicleModel
import frame as fm
from autonomy.sensing import Camera
import model
import frame
import stats
import ui_bridge as ui

Expand All @@ -15,79 +12,46 @@

application = Flask(__name__)

gamepadNode = fm.Node(
subject = None,
strategy = lambda package: package)

frameSubject = fm.Subject(0)
models = {}
models['lane'] = laneModel.generate(frameShape = frameSubject.frameShape)
models['sign'] = signModel.generate(frameShape = frameSubject.frameShape)
models['vehicle'] = vehicleModel.generate()

models['sign']("NMS", "interpreted").addObservers(models['vehicle']("signs", "storage"))
# models['lane']("Error", "interpreted").addObservers(
# models['vehicle']['driveController'],
# models['vehicle']['steeringController'])

frameSubject.addObserver('sign', models['sign'].head)
frameSubject.addObserver('lane', models['lane'].head)
models['lane']("TotalError", "interpreted").addObservers(models['vehicle']("controlPackager", "control"))

imager = fm.Imager(defaultSubject = frameSubject)
imageResponder = fm.ImageResponder(imager)

frameSubject.startThreadedCapture()

frostModels = model.generateForCamera(Camera(0))
imager = frame.Imager(defaultSubject = frostModels['sensing']("Camera", "framer"))
imageResponder = frame.ImageResponder(imager)
frostModels['sensing']("Camera", "framer").start()

@application.route('/')
def index(): return render_template('index.html')

@application.route('/gamepad', methods=['POST'])
def gamepad():
#gamepadNode(request.json)
models['vehicle']("controller", "control")(request.json)
frostModels['vehicle']("controller", "control")(request.json)
return ('', 204)

def modelToButtonCategories(model):
categories = ui.Categories()

category = ui.ButtonCategory("toggle")
category.addButtons(model.category("annotator").keys())
categories.addCategory("Annotation", category)

category = ui.ButtonCategory("radio")
category.addButtons(model.category("framer").keys())
categories.addCategory("Frame", category)

return categories


@application.route('/imageStreamChoices')
def imageStreamChoices():
categories = ui.Categories()
for model in models.values():
categories += modelToButtonCategories(model)
for frostModel in frostModels.values():
categories += model.toButtonCategories(frostModel)

print(categories.asDict())
categories["Frame"].addButtons(["Raw"])
categories["Frame"].addDefaults(["Raw"])
categories["Frame"].addDefaults(["Camera"])

return jsonify(categories.asDict())


@application.route('/updateImageStream', methods=['POST'])
def updateImageStream():
def nodeFromFrameKey(frameKey):
return frameSubject if frameKey == 'Raw' else models['lane'](frameKey, "framer")

imager.subject = nodeFromFrameKey(request.json['Frame'])

frameKey = request.json['Frame']
imager.annotatorNodes = []
for annotator in request.json['Annotation']:
for model in models.values():
if annotator in model.category("annotator"):
imager.annotatorNodes.append(model(annotator, "annotator"))
annotators = request.json['Annotation']

for frostModel in frostModels.values():
if frameKey in frostModel.category("framer"):
imager.subject = frostModel(frameKey, "framer")
break

for annotator in annotators:
for frostModel in frostModels.values():
if annotator in frostModel.category("annotator"):
imager.annotatorNodes.append(frostModel(annotator, "annotator"))

return ('', 204)

Expand Down Expand Up @@ -121,5 +85,6 @@ def current(): return Response(stats.psu.current(), 'text/plain')


if __name__ == '__main__':
import os
os.environ["FLASK_ENV"] = "development"
application.run(debug=True, use_reloader=False, host='0.0.0.0')
4 changes: 4 additions & 0 deletions server/autonomy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import lane
from . import sign
from . import vic
from . import sensing
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions server/autonomy/sensing/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .camera import Camera
17 changes: 17 additions & 0 deletions server/autonomy/sensing/camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import cv2

class Camera():
def __init__(self, source):
self.capture = cv2.VideoCapture(source)

@property
def frameShape(self):
height = int(self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
width = int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH))
channels = 3
return (height, width, channels)

def __call__(self):
hasFrame, frame = self.capture.read()
if hasFrame:
return frame
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 0 additions & 2 deletions server/frame/model.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from collections import defaultdict

from .switchable import Switchables

class Model:
def __init__(self):
self.model = defaultdict(dict)
Expand Down
103 changes: 64 additions & 39 deletions server/frame/subject.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,69 @@
import cv2
import sys
import threading
import time

class Subject:
def __init__(self, source):
self.capture = cv2.VideoCapture(source)
self.frameShape = (
int(self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT)),
int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH)),
3)
import time
import warnings

self.observers = {}
class Subject:
def __init__(self, strategy, delay = 0):
self.strategy = strategy
self.delay = delay
self.output = None

def addObserver(self, name, observer):
self.observers[name] = observer

def removeObserver(self, name):
del self.observers[name]

def startCapture(self):
while True:
hasFrame, frame = self.capture.read()
if hasFrame:
self.output = frame
time.sleep(0.05)

def startDistribution(self, observer):
print(f"Distribution started for {observer}...")
while True:
self.observers = {}

def addObservers(self, *observers):
for observer in observers:
self.observers[observer] = threading.Thread(target=self.observerLoop, args=(observer,))

def start(self):
self.isRunning = True
self.thread = threading.Thread(target=self.loop)
self.thread.start()
for observer in self.observers.keys():
self.observers[observer] = threading.Thread(target=self.observerLoop, args=(observer,))
self.observers[observer].start()

def stop(self):
self.isRunning = False
for observerThread in self.observers.values():
observerThread.join()
self.thread.join()

def removeObserver(self, observer):
if self.isRunning:
warnings.warn("Cannot remove observer while running", RuntimeWarning)
else:
del self.observers[observer]

def loop(self):
while self.isRunning:
self.output = self.strategy()
time.sleep(self.delay)

def observerLoop(self, observer):
while self.isRunning:
if self.output is not None:
observer(self.output)

def startThreadedCapture(self):
threading.Thread(target=self.startCapture).start()
for observer in self.observers.values():
threading.Thread(target=self.startDistribution, args=(observer,)).start()

def stop():
# self.captureThread.terminate()
# self.captureThread = None
self.capture.release()
time.sleep(self.delay)


if __name__ == '__main__':
subject = Subject(lambda: "test", delay = 0.05)

def a(output): print(output)
def b(output): print(output + " me")

subject.addObservers(a, b)
subject.start()
time.sleep(0.1)
# Does not remove observer
print("trying to remove observer a")
subject.removeObserver(a)
time.sleep(0.1)
subject.stop()
# Works without warning
print("trying to remove observer a")
subject.removeObserver(a)
subject.start()
time.sleep(0.3)
subject.stop()


40 changes: 40 additions & 0 deletions server/model/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from frame import Model, Subject
from . import lane
from . import sign
from . import vehicle
import ui_bridge as ui

def generateForCamera(camera):
model = {}

model['sensing'] = Model()
model['sensing'].addNode(
name = "Camera",
category = "framer",
node = Subject(
strategy = camera,
delay = 0))

model['lane'] = lane.generate(frameShape = camera.frameShape)
model['sign'] = sign.generate(frameShape = camera.frameShape)
model['vehicle'] = vehicle.generate()

model['sensing']("Camera", "framer").addObservers(model['lane'].head, model['sign'].head)
model['sign']("NMS", "interpreted").addObservers(model['vehicle']("signs", "storage"))
model['lane']("TotalError", "interpreted").addObservers(model['vehicle']("controlPackager", "control"))

return model


def toButtonCategories(model):
categories = ui.Categories()

category = ui.ButtonCategory("toggle")
category.addButtons(model.category("annotator").keys())
categories.addCategory("Annotation", category)

category = ui.ButtonCategory("radio")
category.addButtons(model.category("framer").keys())
categories.addCategory("Frame", category)

return categories
2 changes: 1 addition & 1 deletion server/laneModel.py → server/model/lane.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy
import time

import lane
from autonomy import lane
from frame import Node, Model, Annotator, Joiner, Packager


Expand Down
6 changes: 3 additions & 3 deletions server/signModel.py → server/model/sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy

from frame import Node, Switchable, Model, Annotator, Timer
import sign
from autonomy import sign

def generate(frameShape):
model = Model()
Expand Down Expand Up @@ -36,7 +36,7 @@ def generate(frameShape):
node = Node(
subject = model("Blob", "preprocessing"),
strategy = sign.Net(sign.makeCpuDarknet(
rootPath = 'sign/yolov3-tiny-prn'))))
rootPath = "autonomy/sign/yolov3-tiny-prn"))))

model("Net", "interpreted").addObservers(model("NetTimer", "logging"))

Expand Down Expand Up @@ -64,6 +64,6 @@ def generate(frameShape):
node = Annotator(
node = model("NMS", "interpreted"),
strategy = sign.DrawDetectionBoxes(
classes = sign.readClasses("sign/sign.names"))))
classes = sign.readClasses("autonomy/sign/sign.names"))))

return model
2 changes: 1 addition & 1 deletion server/vehicleModel.py → server/model/vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy

from frame import Node, Switchable, Model, Annotator
import vic
from autonomy import vic

from collections import deque
class Signs:
Expand Down

0 comments on commit 441b0c7

Please sign in to comment.