Skip to content

Commit

Permalink
initial update
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed May 17, 2023
1 parent f3b209a commit 8f7cfc9
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 435 deletions.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## Camera skill

[shared camera](https://github.com/NeonGeckoCom/shared_camera) for OpenVoiceOS


TODO

- PHAL plugin for the actual shared camera implementation
- skill becomes a VUI + UI specifically for taking pictures
- new ovos_workshop skill class for VisionSkill, exposing a live feed (numpy array) property

## Description

take pictures, share a camera stream across OpenVoiceOS

- local
- zmq
- redis

## Examples

* "take a picture"


## Using webcam in other skills

if you want to get a file path for the latest picture you can use the
messagebus to get a file path


def initialize(self):
self.add_event("webcam.picture", self.get_the_feed)
self.bus.emit(Message("webcam.request"))


def get_the_feed(self, message):
file_path = message.data.get("path")



202 changes: 24 additions & 178 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,31 @@
from mycroft.skills.core import MycroftSkill, intent_file_handler, Message
from mycroft.util.log import LOG
from mycroft.util import play_wav, play_mp3
from os.path import join
import time
from os.path import dirname, exists, expanduser
from os import makedirs
import json
from os.path import dirname, exists, expanduser, join

try:
import cv2
from imutils.video import VideoStream
from shared_camera import Camera
import yagmail
except ImportError:
# re-install yourself
from py_msm import MycroftSkillsManager
msm = MycroftSkillsManager()
msm.install_by_url("https://github.com/JarbasAl/skill-camera", True)
# trigger reload
msm.reload_skill("skill-camera")
import cv2
from ovos_utils.log import LOG
from ovos_workshop.decorators import intent_handler
from ovos_workshop.skills import OVOSSkill
from shared_camera import ZMQCamera


__author__ = 'jarbas'
class WebcamSkill(OVOSSkill):


class WebcamSkill(MycroftSkill):
def __init__(self):
self.create_settings_meta()
super(WebcamSkill, self).__init__()
platform = self.config_core.get("enclosure", {}) \
.get("platform", "unknown")
self.use_pi = platform.lower() in ["picroft", "mark_1", "mark1",
"raspbian", "raspberry", "pi"]
def initialize(self):
LOG.info("initializing videostream")

if "video_source" not in self.settings:
self.settings["video_source"] = 0
if "mail_picture" not in self.settings:
self.settings["mail_picture"] = False
if "play_sound" not in self.settings:
self.settings["play_sound"] = True
if "picture_path" not in self.settings:
self.settings["picture_path"] = expanduser("~/webcam")
if "camera_sound_path" not in self.settings:
self.settings["camera_sound_path"] = join(dirname(__file__),
"camera.wav")
self.settings["picture_path"] = "~/Photos"

if not exists(self.settings["picture_path"]):
makedirs(self.settings["picture_path"])
makedirs(self.settings["picture_path"], exist_ok=True)

# private email
if yagmail is not None:
mail_config = self.config_core.get("email", {})
self.email = mail_config.get("email")
self.password = mail_config.get("password")
self.target_mail = mail_config.get("destinatary", self.email)

self.camera = None
self.camera = ZMQCamera(camera_index=self.settings["video_source"])
self.last_timestamp = 0

def initialize(self):
LOG.info("initializing videostream")

def notify(text):
self.emitter.emit(Message(text))

self.camera = Camera(
VideoStream(src=self.settings["video_source"],
usePiCamera=self.use_pi), callback=notify)
self.last_timestamp = time.time()

def get_intro_message(self):
self.speak_dialog("priority")

def mail_picture(self, picture):
if self.settings["mail_picture"]:
title = "Mycroft Camera Skill"
body = ""
# try private sending
if yagmail is not None and self.email and self.password:
with yagmail.SMTP(self.email, self.password) as yag:
yag.send(self.target_email, title, [body, picture])
else:
self.speak_dialog("send.fail")
return False
self.speak_dialog("send")
return True
return False
self.add_event("webcam.request", self.handle_get_picture)

@property
def last_frame(self):
Expand All @@ -94,120 +34,26 @@ def last_frame(self):
return self.camera.get().copy()
return None

def create_settings_meta(self):
meta = {
"name": "Camera Skill",
"skillMetadata": {
"sections": [
{
"name": "video_source",
"fields": [
{
"type": "label",
"label": "video source for webcam, usually 0"
},
{
"name": "video_source",
"type": "number",
"label": "video_source",
"placeholder": "0",
"value": "0"
}
]
},
{
"name": "camera_sound_path",
"fields": [
{
"type": "label",
"label": "path to wav or mp3 sound file to play on picture taken"
},
{
"name": "camera_sound_path",
"type": "text",
"label": "camera_sound_path",
"placeholder": join(dirname(__file__),
"camera.wav"),
"value": join(dirname(__file__),
"camera.wav")
},
{
"type": "checkbox",
"name": "play_sound",
"label": "play sound on taking picture",
"value": "true"
}
]
},
{
"name": "mail_picture",
"fields": [
{
"type": "label",
"label": "want to email taken pictures? check the repository for "
"additional instructions"
},
{
"type": "checkbox",
"name": "mail_picture",
"label": "mail_picture",
"value": "false"
}
]
},
{
"name": "picture_path",
"fields": [
{
"type": "label",
"label": "where to save taken pictures"
},
{
"name": "picture_path",
"type": "text",
"label": "picture_path",
"placeholder": expanduser("~/webcam"),
"value": expanduser("~/webcam")
}
]
}
]
}
}
meta_path = join(dirname(__file__), 'settingsmeta.json')
if not exists(meta_path):
with open(meta_path, 'w') as fp:
json.dump(meta, fp)

def initialize(self):
self.add_event("webcam.request", self.handle_get_picture)

@intent_file_handler("take_picture.intent")
@intent_handler("take_picture.intent")
def handle_take_picture(self, message):
if exists(self.settings["camera_sound_path"]) and \
self.settings["play_sound"]:
if ".wav" in self.settings["camera_sound_path"]:
play_wav(self.settings["camera_sound_path"])
elif ".mp3" in self.settings["camera_sound_path"]:
play_mp3(self.settings["camera_sound_path"])

pic_path = join(self.settings["picture_path"], time.asctime() +
".jpg")
if self.settings["play_sound"]:
s = self.settings.get("camera_sound_path") or \
join(dirname(__file__), "camera.wav")
if exists(s):
self.play_audio(s)

pic_path = expanduser(join(self.settings["picture_path"], time.asctime() + ".jpg"))
cv2.imwrite(pic_path, self.last_frame)
self.mail_picture(pic_path)
self.speak_dialog("picture")

def handle_get_picture(self, message):
path = join(self.settings["picture_path"],
time.asctime() + ".jpg")
# TODO - skill_api
path = join(self.settings["picture_path"], time.asctime() + ".jpg")
cv2.imwrite(path, self.last_frame)
self.emitter.emit(message.reply("webcam.picture", {"path": path}))
self.bus.emit(message.reply("webcam.picture", {"path": path}))

def shutdown(self):
self.camera.stop_stream()
self.camera.shutdown()
super(WebcamSkill, self).shutdown()


def create_skill():
return WebcamSkill()
45 changes: 0 additions & 45 deletions install_opencv_pi_source.sh

This file was deleted.

30 changes: 0 additions & 30 deletions install_opencv_source.sh

This file was deleted.

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

0 comments on commit 8f7cfc9

Please sign in to comment.