Skip to content

Commit ee128fe

Browse files
committed
wip #63
1 parent 6d6ebc4 commit ee128fe

20 files changed

+269
-11
lines changed

audio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def say(self, what, locale='en'):
7171
if what and "$" in what:
7272
os.system ('omxplayer sounds/' + what[1:])
7373
elif what and len(what):
74-
os.system ('espeak -v' + locale + ' -p 90 -a 200 -s 150 -g 10 "' + what + '" 2>>/dev/null')
74+
os.system ('espeak --stdout -v' + locale + ' -p 90 -a 200 -s 150 -g 10 "' + what + '" 2>>/dev/null | aplay')
7575

7676
def normalize(self, snd_data):
7777
"Average the volume out"

camera.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import logging
2929

3030
from viz import camera, streamer, image, blob
31+
from cnn_classifier import CNNClassifier
3132
import config
3233

3334
MAX_IMAGE_AGE = 0.0
@@ -72,6 +73,8 @@ def __init__(self):
7273
for filename in filenames:
7374
if (PHOTO_PREFIX in filename or VIDEO_PREFIX in filename) and PHOTO_THUMB_SUFFIX not in filename:
7475
self._photos.append(filename)
76+
77+
self._cnn_classifier = CNNClassifier("models/applekiwi.pb", "models/applekiwi.txt", "input", "final_result", 128, 128, 0.0, 255.0)
7578

7679
super(Camera, self).__init__()
7780

@@ -337,6 +340,13 @@ def find_code(self):
337340
self._image_lock.release()
338341
return img.grayscale().find_code()
339342

343+
def find_class(self):
344+
self._image_lock.acquire()
345+
img = self.get_image(0)
346+
self._image_lock.release()
347+
classes = self._cnn_classifier.classify_image(img.mat())
348+
s_classes = sorted(classes.items(), key=lambda x: x[1])
349+
return s_classes[-1][0]
340350

341351
def sleep(self, elapse):
342352
logging.debug("sleep: " + str(elapse))

cnn_classifier.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ==============================================================================
15+
16+
from __future__ import absolute_import
17+
from __future__ import division
18+
from __future__ import print_function
19+
20+
import time
21+
import logging
22+
23+
import numpy as np
24+
import tensorflow as tf
25+
26+
class CNNClassifier:
27+
def __init__(self, model_file, label_file, input_layer="input", output_layer="final_output", input_height=128, input_width=128, input_mean=0.0, input_std=255.0):
28+
self._graph = self.load_graph(model_file)
29+
self._labels = self.load_labels(label_file)
30+
input_name = "import/" + input_layer
31+
output_name = "import/" + output_layer
32+
self._input_operation = self._graph.get_operation_by_name(input_name);
33+
self._output_operation = self._graph.get_operation_by_name(output_name);
34+
self._session = tf.Session(graph=self._graph)
35+
self._graph_norm = tf.Graph()
36+
with self._graph_norm.as_default():
37+
image_mat = tf.placeholder(tf.float32, None, name="image_rgb_in")
38+
float_caster = tf.cast(image_mat, tf.float32)
39+
dims_expander = tf.expand_dims(float_caster, 0);
40+
resized = tf.image.resize_bilinear(dims_expander, [input_height, input_width])
41+
normalized = tf.divide(tf.subtract(resized, [input_mean]), [input_std], name="image_norm_out")
42+
self._input_operation_norm = self._graph_norm.get_operation_by_name("image_rgb_in")
43+
self._output_operation_norm = self._graph_norm.get_operation_by_name("image_norm_out")
44+
self._sess_norm = tf.Session(graph=self._graph_norm)
45+
46+
def close(self):
47+
self._session.close()
48+
self._sess_norm.close()
49+
50+
def load_graph(self, model_file):
51+
graph = tf.Graph()
52+
graph_def = tf.GraphDef()
53+
54+
with open(model_file, "rb") as f:
55+
graph_def.ParseFromString(f.read())
56+
with graph.as_default():
57+
tf.import_graph_def(graph_def)
58+
59+
return graph
60+
61+
def read_tensor_from_image_file(self, file_name, input_height=299, input_width=299, input_mean=0, input_std=255):
62+
input_name = "file_reader"
63+
output_name = "normalized"
64+
65+
file_reader = tf.read_file(file_name, input_name)
66+
67+
if file_name.endswith(".png"):
68+
image_reader = tf.image.decode_png(file_reader, channels = 3,
69+
name='png_reader')
70+
elif file_name.endswith(".gif"):
71+
image_reader = tf.squeeze(tf.image.decode_gif(file_reader,
72+
name='gif_reader'))
73+
elif file_name.endswith(".bmp"):
74+
image_reader = tf.image.decode_bmp(file_reader, name='bmp_reader')
75+
else:
76+
image_reader = tf.image.decode_jpeg(file_reader, channels = 3,
77+
name='jpeg_reader')
78+
79+
float_caster = tf.cast(image_reader, tf.float32)
80+
dims_expander = tf.expand_dims(float_caster, 0);
81+
resized = tf.image.resize_bilinear(dims_expander, [input_height, input_width])
82+
normalized = tf.divide(tf.subtract(resized, [input_mean]), [input_std])
83+
sess = tf.Session()
84+
85+
result = sess.run(normalized)
86+
sess.close()
87+
88+
return result
89+
90+
def read_tensor_from_image_mat(self, image_mat, input_height=299, input_width=299, input_mean=0, input_std=255):
91+
result = self._sess_norm.run(self._output_operation_norm.outputs[0], {self._input_operation_norm.outputs[0]: image_mat})
92+
return result
93+
94+
def load_labels(self, label_file):
95+
label = []
96+
proto_as_ascii_lines = tf.gfile.GFile(label_file).readlines()
97+
for l in proto_as_ascii_lines:
98+
label.append(l.rstrip())
99+
return label
100+
101+
def classify_image(self,
102+
image_file_or_mat,
103+
input_height=128,
104+
input_width=128,
105+
input_mean=0,
106+
input_std=255):
107+
s_t = time.time()
108+
t = None
109+
if type(image_file_or_mat) == str:
110+
t = self.read_tensor_from_image_file(file_name=image_file_or_mat,
111+
input_height=input_height,
112+
input_width=input_width,
113+
input_mean=input_mean,
114+
input_std=input_std)
115+
else:
116+
t = self.read_tensor_from_image_mat(image_file_or_mat,
117+
input_height=input_height,
118+
input_width=input_width,
119+
input_mean=input_mean,
120+
input_std=input_std)
121+
122+
logging.info( "time.norm: " + str(time.time() - s_t))
123+
s_t = time.time()
124+
125+
results = self._session.run(self._output_operation.outputs[0],
126+
{self._input_operation.outputs[0]: t})
127+
128+
logging.info( "time.cls: " + str(time.time() - s_t))
129+
130+
results = np.squeeze(results)
131+
132+
pairs = {}
133+
for i in results.argsort():
134+
pairs[self._labels[i]] = results[i]
135+
136+
return pairs

cnn_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import config
2+
import camera
3+
import cnn_classifier
4+
import cv2 as cv
5+
6+
config = config.Config.read()
7+
cam = camera.Camera.get_instance()
8+
classifier = cnn_classifier.CNNClassifier("models/applekiwi.pb", "models/applekiwi.txt", "input", "final_result")
9+
10+
11+
while True:
12+
i = cam.get_image().resize(128, 128).mat()
13+
results = classifier.classify_image(i, 128, 128)
14+
print "results: " + str(results)
15+
16+

coderbot.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"move_tr_speed": "80", "move_fw_elapse": "1", "camera_color_object_size_min": "4000", "camera_path_object_size_min": "4000", "load_at_start": "", "move_tr_elapse": "0.5", "sound_stop": "$shutdown.mp3", "show_control_move_commands": "true", "prog_level": "adv", "prog_scrollbars": "true", "move_fw_speed": "100", "camera_color_object_size_max": "160000", "sound_shutter": "$shutter.mp3", "show_page_prefs": "true", "cv_image_factor": "4", "ctrl_hud_image": "", "button_func": "none", "ctrl_fw_elapse": "-1", "ctrl_tr_elapse": "-1", "move_power_angle_2": "60", "move_power_angle_3": "60", "move_power_angle_1": "45", "move_motor_trim": "1", "show_page_program": "true", "sound_start": "$startup.mp3", "camera_exposure_mode": "auto", "ctrl_tr_speed": "80", "prog_move_mpu": "yes", "ctrl_fw_speed": "100", "camera_refresh_timeout": "0.1", "camera_jpeg_quality": "20", "prog_maxblocks": "-1", "move_motor_mode": "dc", "camera_path_object_size_max": "160000", "show_page_control": "true"}
1+
{"move_tr_speed": "80", "move_fw_elapse": "1", "camera_color_object_size_min": "4000", "camera_path_object_size_min": "4000", "load_at_start": "", "move_tr_elapse": "0.5", "sound_stop": "$shutdown.mp3", "show_control_move_commands": "true", "prog_level": "adv", "prog_scrollbars": "true", "move_fw_speed": "100", "camera_color_object_size_max": "160000", "sound_shutter": "$shutter.mp3", "show_page_prefs": "true", "cv_image_factor": "4", "ctrl_hud_image": "", "button_func": "none", "ctrl_fw_elapse": "-1", "ctrl_tr_elapse": "-1", "move_power_angle_2": "60", "move_power_angle_3": "60", "move_power_angle_1": "45", "move_motor_trim": "1", "show_page_program": "true", "sound_start": "$startup.mp3", "camera_exposure_mode": "auto", "ctrl_tr_speed": "80", "prog_move_mpu": "yes", "ctrl_fw_speed": "100", "camera_refresh_timeout": "0.1", "camera_jpeg_quality": "20", "prog_maxblocks": "-1", "move_motor_mode": "dc", "camera_path_object_size_max": "160000", "show_page_control": "true"}

coderbot.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,17 @@ def get_instance(cls, servo=False, motor_trim_factor=1.0):
104104
cls.the_bot = CoderBot(servo, motor_trim_factor)
105105
return cls.the_bot
106106

107-
def move(self, speed=100, elapse=-1, steps_left=-1, steps_right=-1):
108-
self.motor_control(speed_left=min(100, max(-100, speed * self._motor_trim_factor)), speed_right=min(100, max(-100, speed / self._motor_trim_factor)), elapse=elapse, steps_left=steps_left, steps_right=steps_right)
107+
def move(self, speed=100, elapse=-1, steps=-1):
108+
speed_left = min(100, max(-100, speed * self._motor_trim_factor))
109+
speed_right = min(100, max(-100, speed / self._motor_trim_factor))
110+
self.motor_control(speed_left=speed_left, speed_right=speed_right, elapse=elapse, steps_left=steps, steps_right=steps)
109111

110112
def turn(self, speed=100, elapse=-1, steps=-1):
111113
steps_left = steps
112-
steps_right = -steps if steps > 0 else -1
113-
self.motor_control(speed_left=min(100, max(-100, speed / self._motor_trim_factor)), speed_right=-min(100, max(-100, speed * self._motor_trim_factor)), elapse=elapse, steps_left=steps_left, steps_right=steps_right)
114+
steps_right = -steps if steps >= 0 else -1
115+
speed_left = min(100, max(-100, speed * self._motor_trim_factor))
116+
speed_right = -min(100, max(-100, speed / self._motor_trim_factor))
117+
self.motor_control(speed_left=speed_left, speed_right=speed_right, elapse=elapse, steps_left=steps, steps_right=steps)
114118

115119
def turn_angle(self, speed=100, angle=0):
116120
z = self._ag.get_gyro_data()['z']
@@ -154,7 +158,7 @@ def _dc_motor(self, speed_left=100, speed_right=100, elapse=-1, steps_left=-1, s
154158
self._encoder_motor_stopping_right = False
155159
self._encoder_motor_stopped_left = False
156160
self._encoder_motor_stopped_right = False
157-
if steps_left > 0 or steps_right > 0:
161+
if steps_left >= 0 or steps_right >= 0:
158162
self._encoder_sem.acquire()
159163

160164
self._is_moving = True
@@ -179,7 +183,7 @@ def _dc_motor(self, speed_left=100, speed_right=100, elapse=-1, steps_left=-1, s
179183
time.sleep(elapse)
180184
self.stop()
181185

182-
if steps_left > 0 or steps_right > 0:
186+
if steps_left >= 0 or steps_right >= 0:
183187
self._encoder_sem.wait()
184188
self._encoder_sem.release()
185189

encoder_test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import coderbot
2+
import time
3+
4+
bot = coderbot.CoderBot.get_instance()
5+
6+
#print "bot.move(100, -1, 1000, 1000)"
7+
#bot.move(100, -1, 1000, 1000)
8+
9+
#print "bot.move(100, -1, -1, -1)"
10+
#bot.move(100, 1, -1000, -1000)
11+
"""
12+
bot.move(100, 0.5, -1)
13+
time.sleep(1.0)
14+
bot.move(-100, 0.5, -1)
15+
time.sleep(1.0)
16+
bot.move(100, -1, 500)
17+
time.sleep(1.0)
18+
bot.move(-100, -1, 500)
19+
time.sleep(1.0)
20+
21+
bot.turn(100, 0.5, 500)
22+
time.sleep(1.0)
23+
bot.turn(-100, 0.5, 500)
24+
time.sleep(1.0)
25+
"""
26+
bot.turn(80, -1, 450)
27+
time.sleep(1.0)
28+
bot.turn(-80, -1, 450)
29+
30+
bot.stop()
31+

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ def run_server():
324324

325325
bot.set_callback(PIN_PUSHBUTTON, button_pushed, 100)
326326
print "run"
327-
app.run(host="0.0.0.0", port=8080, debug=True, use_reloader=False, threaded=True)
327+
app.run(host="0.0.0.0", port=8080, debug=False, use_reloader=False, threaded=True)
328328
finally:
329329
if cam:
330330
cam.exit()

models/applekiwi.pb

932 KB
Binary file not shown.

models/applekiwi.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kiwi
2+
other
3+
apple

0 commit comments

Comments
 (0)