Skip to content

Commit 0c35ae3

Browse files
committed
wip
1 parent 3a5cbca commit 0c35ae3

File tree

15 files changed

+311
-31
lines changed

15 files changed

+311
-31
lines changed

camera.py

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@
2222
import os
2323
import sys
2424
import math
25+
import json
2526
from PIL import Image as PILImage
2627
from StringIO import StringIO
2728
from threading import Thread, Lock
2829
import logging
2930

30-
from viz import camera, streamer, image, blob
31+
from cv import camera, streamer, image, blob
3132
from cnn_classifier import CNNClassifier
3233
import config
3334

3435
MAX_IMAGE_AGE = 0.0
3536
PHOTO_PATH = "./photos"
37+
PHOTO_METADATA_FILE = "./photos/metadata.json"
3638
PHOTO_PREFIX = "DSC"
3739
VIDEO_PREFIX = "VID"
3840
PHOTO_THUMB_SUFFIX = "_thumb"
@@ -68,13 +70,16 @@ def __init__(self):
6870
self._path_object_size_min = int(config.Config.get().get("camera_path_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
6971
self._path_object_size_max = int(config.Config.get().get("camera_path_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
7072
self._photos = []
71-
72-
for dirname, dirnames, filenames, in os.walk(PHOTO_PATH):
73-
for filename in filenames:
74-
if (PHOTO_PREFIX in filename or VIDEO_PREFIX in filename) and PHOTO_THUMB_SUFFIX not in filename:
75-
self._photos.append(filename)
76-
77-
self._cnn_classifier = CNNClassifier("cnn_models/applekiwi_1_128.pb", "cnn_models/applekiwi.txt", "input", "final_result", 128, 128, 0.0, 255.0)
73+
self.load_photo_metadata()
74+
if len(self._photos) == 0:
75+
self._photos = []
76+
for dirname, dirnames, filenames, in os.walk(PHOTO_PATH):
77+
for filename in filenames:
78+
if (PHOTO_PREFIX in filename or VIDEO_PREFIX in filename) and PHOTO_THUMB_SUFFIX not in filename:
79+
self._photos.append({'name': filename})
80+
self.save_photo_metadata()
81+
82+
self._cnn_classifier = CNNClassifier("cnn_models/applekiwi_0_5_128.pb", "cnn_models/applekiwi_0_5_128.txt", "input", "final_result", 128, 128, 0.0, 255.0)
7883

7984
super(Camera, self).__init__()
8085

@@ -118,6 +123,25 @@ def get_image_jpeg(self):
118123
def set_text(self, text):
119124
self._camera.set_overlay_text(str(text))
120125

126+
def load_photo_metadata(self):
127+
try:
128+
f = open(PHOTO_METADATA_FILE)
129+
self._photos = json.load(f)
130+
f.close()
131+
except IOError:
132+
logging.warning("no metadata file")
133+
134+
def save_photo_metadata(self):
135+
f = open(PHOTO_METADATA_FILE, "w")
136+
json.dump(self._photos, f)
137+
f.close()
138+
139+
def update_photo(self, photo):
140+
for p in self._photos:
141+
if p["name"] == photo["name"]:
142+
p["tag"] = photo["tag"]
143+
self.save_photo_metadata()
144+
121145
def get_next_photo_index(self):
122146
last_photo_index = 0
123147
for p in self._photos:
@@ -140,7 +164,8 @@ def photo_take(self):
140164
# thumb
141165
im_pil = PILImage.open(StringIO(im_str))
142166
im_pil.resize(PHOTO_THUMB_SIZE).save(oft)
143-
self._photos.append(filename)
167+
self._photos.append({"name":filename})
168+
self.save_photo_metadata()
144169

145170
def is_recording(self):
146171
return self.recording
@@ -160,15 +185,16 @@ def video_rec(self, video_name=None):
160185
try:
161186
#remove previous file and reference in album
162187
os.remove(PHOTO_PATH + "/" + filename)
163-
self._photos.remove(filename)
188+
self._photos.remove({"name":filename})
164189
except:
165190
pass
166191

167192
oft = open(PHOTO_PATH + "/" + filename_thumb, "w")
168193
im_str = self._camera.get_image_jpeg()
169194
im_pil = PILImage.open(StringIO(im_str))
170195
im_pil.resize(PHOTO_THUMB_SIZE).save(oft)
171-
self._photos.append(filename)
196+
self._photos.append({"name":filename})
197+
self.save_photo_metadata()
172198
self._camera.video_rec(PHOTO_PATH + "/" + filename)
173199
self.video_start_time = time.time()
174200

@@ -190,7 +216,10 @@ def delete_photo(self, filename):
190216
logging.info("delete photo: " + filename)
191217
os.remove(PHOTO_PATH + "/" + filename)
192218
os.remove(PHOTO_PATH + "/" + filename[:filename.rfind(".")] + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT)
193-
self._photos.remove(filename)
219+
for photo in self._photos:
220+
if photo["name"] == filename:
221+
self._photos.remove(photo)
222+
self.save_photo_metadata()
194223

195224
def exit(self):
196225
#self._streamer.server.shutdown()

cnn_manager.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import os
2+
import shutil
3+
import logging
4+
import json
5+
import threading
6+
7+
from cnn_train import CNNTrainer
8+
9+
MODEL_PATH = "./cnn_models"
10+
MODEL_TMP_PATH = "/tmp/images"
11+
MODEL_METADATA = "./cnn_models/models.json"
12+
PHOTO_PATH = "./photos"
13+
14+
class CNNManager:
15+
instance = None
16+
17+
@classmethod
18+
def get_instance(cls):
19+
if cls.instance is None:
20+
cls.instance = CNNManager()
21+
return cls.instance
22+
23+
24+
def __init__(self):
25+
try:
26+
f = open(MODEL_METADATA, "r")
27+
self._models = json.load(f)
28+
f.close
29+
except IOError:
30+
self._models = {}
31+
f = open(MODEL_METADATA, "w")
32+
json.dump(self._models, f)
33+
f.close
34+
self._trainers = {}
35+
36+
def get_models(self):
37+
return self._models
38+
39+
def get_model_status(self, model_name):
40+
return self._models[model_name]
41+
42+
def delete_model(self, model_name):
43+
if self._models.get(model_name):
44+
os.remove(MODEL_PATH + "/" + model_name + ".*")
45+
del self._models[model_name]
46+
47+
def train_new_model(self,
48+
model_name,
49+
architecture,
50+
image_tags,
51+
photos_meta,
52+
training_steps,
53+
learning_rate):
54+
55+
logging.info("starting")
56+
trainer = self.TrainThread(self, model_name, architecture, image_tags, photos_meta, training_steps, learning_rate)
57+
trainer.start()
58+
self._trainers[model_name] = trainer
59+
#trainer.join()
60+
61+
def save_model(self, model_name, architecture):
62+
model_info = architecture.split("_")
63+
self._models[model_name] = {"status": 1, "image_height": model_info[2], "image_width": model_info[2]}
64+
f = open(MODEL_METADATA, "w")
65+
json.dump(self._models, f)
66+
f.close()
67+
68+
class TrainThread(threading.Thread):
69+
70+
def __init__(self, manager, model_name, architecture, image_tags, photos_metadata, training_steps, learning_rate):
71+
super(CNNManager.TrainThread, self).__init__()
72+
self.manager = manager
73+
self.model_name = model_name
74+
self.architecture = architecture
75+
self.image_tags = image_tags
76+
self.photos_metadata = photos_metadata
77+
self.learning_rate = learning_rate
78+
self.training_steps = training_steps
79+
self.trainer = CNNTrainer(architecture)
80+
81+
def update_train_status(self, model_name, status):
82+
model = self.manager._models.get(model_name)
83+
model["status"] = status
84+
85+
def run(self):
86+
image_dir = self.prepare_images()
87+
logging.info("retrain")
88+
self.trainer.retrain(image_dir, MODEL_PATH + "/" + self.model_name, self.training_steps, self.learning_rate)
89+
self.manager.save_model(self.model_name, self.architecture)
90+
self.clear_filesystem()
91+
logging.info("finish")
92+
93+
def prepare_images(self):
94+
logging.info("prepare_images")
95+
photo_abs_path = os.path.abspath(PHOTO_PATH)
96+
model_image_path = MODEL_TMP_PATH + "/" + self.model_name
97+
os.makedirs(model_image_path)
98+
for t in self.image_tags:
99+
tag_path = model_image_path + "/" + t
100+
os.makedirs(tag_path)
101+
for p in self.photos_metadata:
102+
if p.get("tag", "---") == t:
103+
os.symlink(photo_abs_path + "/" + p["name"], tag_path + "/" + p["name"])
104+
105+
return model_image_path
106+
107+
def clear_filesystem(self):
108+
shutil.rmtree(MODEL_TMP_PATH + "/" + self.model_name)
109+

cnn_train.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def __init__(self, architecture):
149149
self.model_info = self.create_model_info(self.architecture)
150150
if not self.model_info:
151151
tf.logging.error('Did not recognize architecture flag')
152-
raise
152+
raise Exception("Did not recognize architecture flag'")
153153

154154
# Set up the pre-trained graph.
155155
self.maybe_download_and_extract(self.model_info['data_url'])
@@ -1167,9 +1167,9 @@ def add_jpeg_decoding(self, input_width, input_height, input_depth, input_mean,
11671167

11681168

11691169
if __name__ == '__main__':
1170-
cnn_trainer = CNNTrainer("mobilenet_1.0_128")
1170+
cnn_trainer = CNNTrainer("mobilenet_0.50_128")
11711171
cnn_trainer.retrain(
11721172
image_dir="/home/pi/tensorflow/data/applekiwi",
1173-
output_graph="./cnn_test_1",
1173+
output_graph="./cnn_models/applewiki_0_5_128.pb",
11741174
training_steps=10,
11751175
learning_rate=0.1)
File renamed without changes.

viz/blob.py renamed to cv/blob.py

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

main.py

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131
from audio import Audio
3232
from program import ProgramEngine, Program
3333
from config import Config
34+
from cnn_manager import CNNManager
3435

35-
from flask import Flask, render_template, request, send_file, redirect, Response
36+
from flask import Flask, render_template, request, send_file, redirect, Response, jsonify
3637
from flask_babel import Babel
3738
#from flask_sockets import Sockets
3839

@@ -47,6 +48,7 @@
4748
cam = None
4849
motion = None
4950
audio = None
51+
cnn = None
5052

5153
app = Flask(__name__,static_url_path="")
5254
#app.config.from_pyfile('coderbot.cfg')
@@ -201,7 +203,7 @@ def handle_photos():
201203
return json.dumps(cam.get_photo_list())
202204

203205
@app.route("/photos/<filename>", methods=["GET"])
204-
def handle_photo(filename):
206+
def handle_photo_get(filename):
205207
logging.info("photo")
206208
mimetype = {'jpeg': 'image/jpeg', 'h264': 'video/mp4'}
207209
video = None
@@ -212,7 +214,16 @@ def handle_photo(filename):
212214

213215
return send_file(video, mimetype.get(filename[:-3],'image'), cache_timeout=0)
214216

215-
@app.route("/photos/<filename>", methods=["POST"])
217+
@app.route("/photos/<filename>", methods=["PUT"])
218+
def handle_photo_put(filename):
219+
logging.info("photo update")
220+
data = request.get_data()
221+
logging.info(data);
222+
data = json.loads(data)
223+
cam.update_photo({"name": filename, "tag":data["tag"]});
224+
return jsonify({"res":"ok"})
225+
226+
@app.route("/photos/<filename>", methods=["DELETE"])
216227
def handle_photo_cmd(filename):
217228
logging.debug("photo delete")
218229
cam.delete_photo(filename)
@@ -276,9 +287,38 @@ def handle_program_status():
276287
prog = app.prog
277288
return json.dumps({'name': prog.name, "running": prog.is_running()})
278289

279-
@app.route("/tutorial")
280-
def handle_tutorial():
281-
return redirect("/blockly-tutorial/apps/index.html", code=302)
290+
@app.route("/cnnmodels", methods=["GET"])
291+
def handle_cnn_models_list():
292+
logging.info("cnn_models_list")
293+
return json.dumps(app.cnn.get_models())
294+
295+
@app.route("/cnnmodels", methods=["POST"])
296+
def handle_cnn_models_new():
297+
logging.info("cnn_models_new")
298+
data = json.loads(request.get_data())
299+
app.cnn.train_new_model(model_name=data["model_name"],
300+
architecture=data["architecture"],
301+
image_tags=data["image_tags"],
302+
photos_meta=cam.get_photo_list(),
303+
training_steps=data["training_steps"],
304+
learning_rate=data["training_rate"])
305+
306+
return json.dumps({"name": data["model_name"], "status": 0})
307+
308+
@app.route("/cnnmodels/<model_name>", methods=["GET"])
309+
def handle_cnn_models_status(model_name):
310+
logging.info("cnn_models_status")
311+
model_status = app.cnn.get_model(model_name=model_name)
312+
313+
return json.dumps(model_status)
314+
315+
@app.route("/cnnmodels/<model_name>", methods=["DELETE"])
316+
def handle_cnn_models_delete(model_name):
317+
logging.info("cnn_models_delete")
318+
model_status = app.cnn.delete_model(model_name=model_name)
319+
320+
return json.dumps(model_status)
321+
282322

283323
def execute(command):
284324
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
@@ -303,6 +343,7 @@ def run_server():
303343
global cam
304344
global motion
305345
global audio
346+
global cnn
306347
try:
307348
try:
308349
app.bot_config = Config.read()
@@ -314,7 +355,10 @@ def run_server():
314355
#motion = Motion.get_instance()
315356
except picamera.exc.PiCameraError:
316357
logging.error("Camera not present")
317-
358+
359+
cnn = CNNManager.get_instance()
360+
app.cnn = cnn
361+
318362
if app.bot_config.get('load_at_start') and len(app.bot_config.get('load_at_start')):
319363
app.prog = app.prog_engine.load(app.bot_config.get('load_at_start'))
320364
app.prog.execute()

motion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import numpy as np
2323
import logging
2424
from time import clock, time, sleep
25-
from viz import image, streamer
25+
from cv import image, streamer
2626

2727
from coderbot import CoderBot
2828
from camera import Camera

0 commit comments

Comments
 (0)