class Voice(Elk): said = ElkAttribute(mode='rw', type=str) muted = ElkAttribute(mode='rw', type=bool, default=False) temp_path = ElkAttribute(mode='rw', type=str, builder='_temp_path', lazy=True) play_filename = ElkAttribute(mode='rw', type=str, default='pcvoice.mp3') def _temp_path(self): path = os.path.join(gettempdir(), '.{}'.format(hash(os.times()))) os.makedirs(path) return path def mute(self): self.muted = True def unmute(self): self.muted = False def play_file(self, music_file, volume=0.8): # set up the mixer # freq = 44100 # audio CD quality # bitsize = -16 # unsigned 16 bit # channels = 1 # 1 is mono, 2 is stereo # buffer = 2048 # number of samples (experiment to get best sound) # buffer = 4096 # number of samples (experiment to get best sound) # pg.mixer.init(freq, bitsize, channels, buffer) mp3 = mutagen.mp3.MP3(music_file) pg.mixer.init(frequency=mp3.info.sample_rate) # volume value 0.0 to 1.0 pg.mixer.music.set_volume(volume) clock = pg.time.Clock() try: pg.mixer.music.load(music_file) except pg.error: log.error("File {} not found! ({})".format(music_file, pg.get_error())) return pg.mixer.music.play() while pg.mixer.music.get_busy(): clock.tick(30) pg.mixer.music.stop() pg.mixer.quit() def say(self, text): self.said = text if not self.muted: tts = gTTS(text=text, lang='en') tts.save(self.play_filename) self.play_file(self.play_filename)
class RPICamera(Camera): stream = ElkAttribute(mode='rw', builder='_stream', lazy=True) def _camera(self): try: #from picamera.array import PiRGBArray #from picamera import PiCamera pass except ImportError: print("PI camera is not detected") return None camera = PiCamera() camera.resolution = (640, 480) #camera.framerate = 32 return camera def _stream(self): stream = PiRGBArray(self.camera, size=(640, 480)) # allow the camera to warmup time.sleep(1) return stream def capture(self): self.stream.truncate(0) self.camera.capture(self.stream, format="bgr", use_video_port=True) # grab the raw NumPy array representing the image, # then initialize the timestamp # and occupied/unoccupied text image = self.stream.array return image
class TestCamera(Camera): image = ElkAttribute(mode='rw') def _camera(self): return None def capture(self): return self.image
class Camera(Elk): camera = ElkAttribute(mode='ro', builder='_camera', lazy=True) def __del__(self): if self.camera is not None: self.camera.release() def _camera(self): return cv2.VideoCapture(0) def capture(self): ret, frame = self.camera.read() return frame
class Master(Elk): face_agent = ElkAttribute(mode='rw', type=FaceAgent, builder="_face_agent", lazy=True) voice = ElkAttribute(mode='rw', type=(Voice, NoneType), builder="_voice", lazy=True) saw = ElkAttribute(mode='rw', type=str, default='') face_recognition_threshold = ElkAttribute(mode='rw', type=int, default=150) camera = ElkAttribute(mode='rw', type=Camera, builder="_camera", lazy=True) memory = attr(mode='rw', type=Memory, builder="_memory", lazy=True) enable_video = ElkAttribute(mode='rw', type=bool, default=False) sleep_delay = ElkAttribute(mode='rw', type=float, default=1.0) interrupt = attr(mode='rw', type=bool, default=False) def _face_agent(self): agent = FaceAgent() agent.init() return agent def _voice(self): return Voice() def _camera(self): return RPICamera() def _memory(self): return Memory() def best_recognized_face(self, faces): best = None index = 0 for face in faces: print_confidence = face['confidence'] if print_confidence > 1000: print_confidence = 'uncertain' else: print_confidence = str(print_confidence) if self.enable_video: index += 1 cv2.imshow('Face' + str(index), face['image']) log.info('found face %s with %s confidence' % (face['predicted'], print_confidence)) if best is None or best['confidence'] < face['confidence']: best = face return best def biggest_face(self, faces): biggest = None biggest_size = 0 for face in faces: size = face['size'] size = (size[0] + size[1]) / 2 if size > biggest_size: biggest = face biggest_size = size return biggest def recognize(self, image): assert image is not None, 'image instance is mandatory' self.faces = self.face_agent.recognize(image) if self.enable_video: self.face_agent.show_faces(image, self.faces, 5000) pass saw = '' self.face = None self.biggest_face = None if not self.faces: #log.info("could not find any face") pass else: self.face = self.best_recognized_face(self.faces) if not self.face: #log.info("could not recognize any face") saw = 'FACE' else: if self.face['confidence'] < self.face_recognition_threshold: saw = self.face['predicted'] else: saw = 'FACE' if saw == 'FACE': self.biggest_face = self.biggest_face(faces) if self.biggest_face: log.info("found a new face") self.face_agent.new_face(self.biggest_face['image']) self.saw = saw def look(self): image = self.camera.capture() self.recognize(image) if self.saw == 'FACE': self.voice.say('hi, I do not know you') elif self.saw != '': if self.voice: self.voice.say('hi ' + self.saw) if self.memory: if self.memory.remember({ 'place': 'kitchen', 'noun': self.saw, 'verb': 'see' }): self.face_agent.remember_face(self.face) self.face_agent.remember_image(image, self.saw) def stop(self): self.interrupt = True def run(self): while not self.interrupt: self.look() if self.enable_video: if cv2.waitKey(200) & 0xFF == ord('q'): break else: if self.saw == '': if self.sleep_delay > 3.0: self.sleep_delay -= 0.1 else: self.sleep_delay = 3.0 else: self.sleep_delay = 5.0 time.sleep(self.sleep_delay) cv2.destroyAllWindows()
class FaceImage(Elk): image = ElkAttribute(mode='rw', type=(types.NoneType, np.ndarray), builder='_image', lazy=True) filename = ElkAttribute(mode='ro', type=str) def _image(self): if self.filename: image = self._load_from_file(self.filename) return image return Image() def _load_from_file(self, filename): log.info("reading: " + filename) image = Image.open(filename) image = image.convert('L') image = np.array(image, 'uint8') return image def gray(self): image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) return image def resize(self, size): h, w = self.image.shape[:2] log.info("resizing to (%d,%d)" % (h, w)) sh, sw = size if h > sh or w > sw: # shrinking interp = cv2.INTER_AREA else: interp = cv2.INTER_CUBIC aspect = w / h if aspect > 1: # horizontal image new_w = sw new_h = np.round(new_w / aspect).astype(int) pad_vert = (sh - new_h) / 2 pad_top, pad_bot = np.floor(pad_vert).astype(int), \ np.ceil(pad_vert).astype(int) pad_left, pad_right = 0, 0 elif aspect < 1: # vertical image new_h = sh new_w = np.round(new_h * aspect).astype(int) pad_horz = (sw - new_w) / 2 pad_left, pad_right = np.floor(pad_horz).astype(int), \ np.ceil(pad_horz).astype(int) pad_top, pad_bot = 0, 0 else: new_h, new_w = sh, sw pad_left, pad_right, pad_top, pad_bot = 0, 0, 0, 0 image = cv2.resize(self.image, (new_w, new_h), interpolation=interp) image = cv2.copyMakeBorder(image, pad_top, pad_bot, pad_left, pad_right, borderType=cv2.BORDER_CONSTANT, value=0) self.image = image return image def align_eyes(self, left, right, image=None): if image is None: image = self.image (ex, ey, ew, eh) = left eye_left = (ex, ey) (ex, ey, ew, eh) = right eye_right = (ex, ey) scale = (0.15, 0.10) size = (image.shape[0], image.shape[1]) dest_sz = (image.shape[0], image.shape[1]) #eye_left=(0,0), eye_right=(0,0), offset_pct=(0.25,0.25), dest_sz = (250,250)): # rotate eye_direction = (eye_right[0] - eye_left[0], eye_right[1] - eye_left[1]) rotation = math.atan2(float(eye_direction[1]), float(eye_direction[0])) rotation = rotation * 180 / math.pi dist = math.hypot(eye_left[0] - eye_right[0], eye_left[1] - eye_right[1]) sz = image.shape if len(sz) > 2: sz = sz[:2] mat = cv2.getRotationMatrix2D(eye_left, rotation, 1.0) result = cv2.warpAffine(image, mat, sz, flags=cv2.INTER_CUBIC) # cut # dest_h = math.floor(float(dest_scale[0])*dest_sz[0]) # dest_v = math.floor(float(dest_scale[1])*dest_sz[1]) # # reference = dest_sz[0] - 2.0*offset_h # reference = dest_sz[0] - 2.0*offset_h # scale = float(dist) / float(reference) # print( dist, reference ) # print( scale ) crop_xy = (size[0] * scale[0], size[1] * scale[1]) #crop_size = (dest_sz[0]*scale, dest_sz[1]*scale) crop_size = (size[0] * (1 - 2 * scale[0]), size[1] * (1 - 2 * scale[1])) result = result[int(crop_xy[1]):int(crop_xy[1] + crop_size[1]), int(crop_xy[0]):int(crop_xy[0] + crop_size[0])] self.image = result return result def normalize(self): #image = self.resize((100, 100)) image = self.image image = cv2.equalizeHist(image) #clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) #image = clahe.apply(image) #image = cv2.bilateralFilter(image, 5, 75, 75) self.image = image return image
class Memory(Elk): filename = ElkAttribute(mode='rw', type=str, builder='_filename', lazy=True) storage = ElkAttribute(mode='rw', builder='_storage', lazy=True) cache = attr(mode='rw', type=dict, builder='_cache', lazy=True) def _cache(self): return dict() def _filename(self): return os.path.dirname( os.path.abspath( inspect.getfile(inspect.currentframe()))) \ + '/../../../data/memory.db' def _storage(self): print(("loading '{}' memory file".format(self.filename))) c = sqlite3.connect(self.filename) c.execute('''CREATE TABLE IF NOT EXISTS memory ( date text, noun text, verb text, place text )''') c.commit() return c def create_cursor(self): return self.storage.cursor() def remember(self, fields): place = fields['place'] or "" noun = fields['noun'] or "" verb = fields['verb'] or "" t = datetime.now() if place in self.cache: if noun in self.cache[place]: if verb in self.cache[place][noun]: delay = (t - self.cache[place][noun][verb]).total_seconds() if delay < 60 * 5: # 5 minutes return False else: self.cache[place][noun] = dict() else: self.cache[place] = dict() self.cache[place][noun] = dict() self.cache[place][noun][verb] = t log.info("logging at {} {} {} {}".format( place, t.strftime("%d %b %Y %H:%M:%S"), noun, verb)) c = self.create_cursor() record = ("date('now')", place, noun, verb) c.execute( '''INSERT INTO memory(date,place,noun,verb) VALUES(?,?,?,?)''', record) self.storage.commit() return True def close(self): self.storage = None def query(self, fields, conditions, order=None, amount=0): c = self.create_cursor() select = "SELECT" select += " " if fields: select += ', '.join(fields) else: select += '*' select += ' FROM memory' if conditions: wheres = [] for name, value in list(conditions.items()): wheres.append(" %s == '%s'" % (name, value)) select += " WHERE " + " AND ".join(wheres) if order: select += " ORDER BY " + ", ".join(conditions) if amount: select += " LIMIT " + str(amount) log.debug("quering " + select) print(("quering " + select)) return c.execute(select) def query_one(self, field, conditions, order=None): result = self.query([field], conditions, order, 1) item = next(result) if item: return item[0] return None