Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorWalter Bender <walter.bender@gmail.com>2012-10-10 19:37:51 (GMT)
committer Walter Bender <walter.bender@gmail.com>2012-10-10 19:37:51 (GMT)
commit1d6e73c2e7a9ab9bba0b028c5c567d2106d7f1cf (patch)
treec59929a412dbbe07344333c0d1a40f127c88c0a6 /plugins
parent41e008218ab8a20bc27463eb959100ea17239e0d (diff)
add support for USB camera (e.g., microscope)
Diffstat (limited to 'plugins')
-rw-r--r--plugins/camera_sensor/camera_sensor.py97
-rw-r--r--plugins/camera_sensor/images/camera1off.svg63
-rw-r--r--plugins/camera_sensor/images/camera1small.svg61
-rw-r--r--plugins/camera_sensor/tacamera.py26
4 files changed, 211 insertions, 36 deletions
diff --git a/plugins/camera_sensor/camera_sensor.py b/plugins/camera_sensor/camera_sensor.py
index ebbd5e8..6509a88 100644
--- a/plugins/camera_sensor/camera_sensor.py
+++ b/plugins/camera_sensor/camera_sensor.py
@@ -43,11 +43,17 @@ class Camera_sensor(Plugin):
self._parent = parent
self._status = False
self._ag_control = None
- self.camera = None
-
- v4l2src = gst.element_factory_make('v4l2src')
- if v4l2src.props.device_name is not None:
+ self.devices = []
+ self.cameras = []
+
+ if os.path.exists('/dev/video0'):
+ self.devices.append('/dev/video0')
+ if os.path.exists('/dev/video1'):
+ self.devices.append('/dev/video1')
+ if len(self.devices) > 0:
self._status = True
+ else:
+ self._status = False
def setup(self):
''' Set up the palettes '''
@@ -63,7 +69,8 @@ class Camera_sensor(Plugin):
# set up camera-specific blocks
primitive_dictionary['read_camera'] = self.prim_read_camera
- media_blocks_dictionary['camera'] = self.prim_take_picture
+ media_blocks_dictionary['camera'] = self.prim_take_picture0
+ media_blocks_dictionary['camera1'] = self.prim_take_picture1
SKIN_PATHS.append('plugins/camera_sensor/images')
@@ -98,6 +105,22 @@ is pushed to the stack'),
default='CAMERA',
help_string=_('camera output'),
content_block=True)
+ if len(self.devices) > 1:
+ media_palette.add_block('camera1',
+ style='box-style-media',
+ label=' ',
+ default='CAMERA',
+ help_string=_('camera output'),
+ content_block=True)
+ else:
+ media_palette.add_block('camera1',
+ hidden=True,
+ style='box-style-media',
+ label=' ',
+ default='CAMERA',
+ help_string=_('camera output'),
+ content_block=True)
+
else: # No camera, so blocks should do nothing
sensors_palette.add_block('luminance',
hidden=True,
@@ -132,17 +155,30 @@ is pushed to the stack'),
help_string=_('camera output'),
content_block=True)
+ media_palette.add_block('camera1',
+ hidden=True,
+ style='box-style-media',
+ label=' ',
+ default='CAMERA',
+ help_string=_('camera output'),
+ content_block=True)
+
NO_IMPORT.append('camera')
BLOCKS_WITH_SKIN.append('camera')
+ NO_IMPORT.append('camera1')
+ BLOCKS_WITH_SKIN.append('camera1')
MEDIA_SHAPES.append('camerasmall')
MEDIA_SHAPES.append('cameraoff')
+ MEDIA_SHAPES.append('camera1small')
+ MEDIA_SHAPES.append('camera1off')
def start(self):
''' Initialize the camera if there is an camera block in use '''
if len(self._parent.block_list.get_similar_blocks('block',
- ['camera', 'read_camera', 'luminance'])) > 0:
- if self._status and self.camera is None:
- self.camera = Camera()
+ ['camera', 'camera1', 'read_camera', 'luminance'])) > 0:
+ if self._status and len(self.cameras) == 0:
+ for device in self.devices:
+ self.cameras.append(Camera(device))
def quit(self):
''' This gets called when the activity quits '''
@@ -157,9 +193,10 @@ is pushed to the stack'),
self._reset_the_camera()
def _reset_the_camera(self):
- if self._status and self.camera is not None:
- self.camera.stop_camera_input()
- self._set_autogain(1) # enable AUTOGAIN
+ if self._status and len(self.cameras) > 0:
+ for i, camera in enumerate(self.cameras):
+ camera.stop_camera_input()
+ self._set_autogain(1, camera=i) # enable AUTOGAIN
def _status_report(self):
debug_output('Reporting camera status: %s' % (str(self._status)),
@@ -168,13 +205,19 @@ is pushed to the stack'),
# Block primitives used in talogo
- def prim_take_picture(self):
+ def prim_take_picture0(self):
+ self._take_picture(camera=0)
+
+ def prim_take_picture1(self):
+ self._take_picture(camera=1)
+
+ def _take_picture(self, camera=0):
''' method called by media block '''
- self._set_autogain(1) # enable AUTOGAIN
- self._get_pixbuf_from_camera()
- self._parent.lc.pixbuf = self.camera.pixbuf
+ self._set_autogain(1, camera) # enable AUTOGAIN
+ self._get_pixbuf_from_camera(camera)
+ self._parent.lc.pixbuf = self.cameras[camera].pixbuf
- def prim_read_camera(self, luminance_only=False):
+ def prim_read_camera(self, luminance_only=False, camera=0):
""" Read average pixel from camera and push b, g, r to the stack """
self.luminance_only = luminance_only
if not self._status:
@@ -187,9 +230,9 @@ is pushed to the stack'),
return
array = None
- self._set_autogain(0) # disable AUTOGAIN
- self._get_pixbuf_from_camera()
- self.calc_luminance()
+ self._set_autogain(0, camera=camera) # disable AUTOGAIN
+ self._get_pixbuf_from_camera(camera=camera)
+ self.calc_luminance(camera=camera)
if self.luminance_only:
self._parent.lc.update_label_value('luminance', self.luminance)
return self.luminance
@@ -198,10 +241,10 @@ is pushed to the stack'),
self._parent.lc.heap.append(self.g)
self._parent.lc.heap.append(self.r)
- def calc_luminance(self):
- array = self.camera.pixbuf.get_pixels()
- width = self.camera.pixbuf.get_width()
- height = self.camera.pixbuf.get_height()
+ def calc_luminance(self, camera=0):
+ array = self.cameras[camera].pixbuf.get_pixels()
+ width = self.cameras[camera].pixbuf.get_width()
+ height = self.cameras[camera].pixbuf.get_height()
if array is not None:
length = int(len(array) / 3)
@@ -238,12 +281,12 @@ is pushed to the stack'),
self.g = -1
self.b = -1
- def _set_autogain(self, state):
+ def _set_autogain(self, state, camera=0):
''' 0 is off; 1 is on '''
if self._ag_control is not None and self._ag_control.value == state:
return
try:
- video_capture_device = open('/dev/video0', 'rw')
+ video_capture_device = open(self.devices[camera], 'rw')
except:
video_capture_device = None
debug_output('video capture device not available',
@@ -258,8 +301,8 @@ is pushed to the stack'),
pass
video_capture_device.close()
- def _get_pixbuf_from_camera(self):
+ def _get_pixbuf_from_camera(self, camera):
''' Regardless of how we get it, we want to return a pixbuf '''
self._parent.lc.pixbuf = None
if self._status:
- self.camera.start_camera_input()
+ self.cameras[camera].start_camera_input()
diff --git a/plugins/camera_sensor/images/camera1off.svg b/plugins/camera_sensor/images/camera1off.svg
new file mode 100644
index 0000000..aa25260
--- /dev/null
+++ b/plugins/camera_sensor/images/camera1off.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="55"
+ height="55"
+ viewBox="0 0 55 55"
+ id="svg2"
+ xml:space="preserve"><metadata
+ id="metadata23"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs21" /><g
+ id="camera-external"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:block">
+ <g
+ id="g5"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline">
+ <g
+ id="g7"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none">
+ <polygon
+ points="34.904,9.862 18.783,9.862 15.155,14.52 6.29,14.52 6.29,38.973 48.209,38.973 48.209,14.52 38.532,14.52 "
+ id="polygon9"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <g
+ id="g11"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none">
+ <polygon
+ points="34.904,9.862 18.783,9.862 15.155,14.52 6.29,14.52 6.29,38.973 48.209,38.973 48.209,14.52 38.532,14.52 "
+ id="polygon13"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ </g>
+ <path
+ d="m 20.601,26.441 c 0,3.67 2.979,6.648 6.65,6.648 3.667,0 6.646,-2.979 6.646,-6.648 0,-3.668 -2.979,-6.652 -6.646,-6.652 -3.67,0 -6.65,2.986 -6.65,6.652 z"
+ id="path15"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ <rect
+ width="6.2870002"
+ height="4.1929998"
+ x="38.098999"
+ y="18.417999"
+ id="rect17"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+</g><text
+ x="45.716103"
+ y="51.309322"
+ id="text3000"
+ xml:space="preserve"
+ style="font-size:11px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
+ x="45.716103"
+ y="51.309322"
+ id="tspan3002"
+ style="font-weight:bold;-inkscape-font-specification:Sans Bold">2</tspan></text>
+</svg> \ No newline at end of file
diff --git a/plugins/camera_sensor/images/camera1small.svg b/plugins/camera_sensor/images/camera1small.svg
new file mode 100644
index 0000000..8b081f3
--- /dev/null
+++ b/plugins/camera_sensor/images/camera1small.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="26"
+ height="18.668091"
+ viewBox="0 0 26 18.668091"
+ id="svg2"
+ xml:space="preserve"><metadata
+ id="metadata29"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs27">
+
+
+
+
+
+
+
+
+
+ </defs><g
+ transform="matrix(0.57244766,0,0,0.57244766,-2.5989125,-4.6436954)"
+ id="camera-external"
+ style="display:block"><g
+ id="g5"
+ style="display:inline"><g
+ id="g7"><polygon
+ points="38.532,14.52 34.904,9.862 18.783,9.862 15.155,14.52 6.29,14.52 6.29,38.973 48.209,38.973 48.209,14.52 "
+ id="polygon9"
+ style="fill:#ffffff" /></g><g
+ id="g11"><polygon
+ points="38.532,14.52 34.904,9.862 18.783,9.862 15.155,14.52 6.29,14.52 6.29,38.973 48.209,38.973 48.209,14.52 "
+ id="polygon13"
+ style="fill:none;stroke:#010101;stroke-width:3.5" /></g></g><path
+ d="m 20.601,26.441 c 0,3.67 2.979,6.648 6.65,6.648 3.667,0 6.646,-2.979 6.646,-6.648 0,-3.668 -2.979,-6.652 -6.646,-6.652 -3.67,0 -6.65,2.986 -6.65,6.652 z"
+ id="path15"
+ style="fill:#ffffff;stroke:#010101;stroke-width:3.5;display:inline" /><rect
+ width="6.2870002"
+ height="4.1929998"
+ x="38.098999"
+ y="18.417999"
+ id="rect17"
+ style="fill:#010101;display:inline" /></g><text
+ x="18.149788"
+ y="15.630935"
+ id="text3000"
+ xml:space="preserve"
+ style="font-size:11px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
+ x="18.149788"
+ y="15.630935"
+ id="tspan3002"
+ style="font-size:8px;font-weight:bold;-inkscape-font-specification:Sans Bold">2</tspan></text>
+</svg> \ No newline at end of file
diff --git a/plugins/camera_sensor/tacamera.py b/plugins/camera_sensor/tacamera.py
index 5a6f506..fc0804d 100644
--- a/plugins/camera_sensor/tacamera.py
+++ b/plugins/camera_sensor/tacamera.py
@@ -25,24 +25,33 @@ import gobject
from TurtleArt.tautils import debug_output
-GST_PIPE = ['v4l2src', 'ffmpegcolorspace', 'gdkpixbufsink']
-
class Camera():
''' Sets up a pipe from the camera to a pixbuf and emits a signal
when the image is ready. '''
- def __init__(self):
+ def __init__(self, device='/dev/video0'):
''' Prepare camera pipeline to pixbuf and signal watch '''
- self.pipe = gst.parse_launch('!'.join(GST_PIPE))
- self.bus = self.pipe.get_bus()
- self.bus.add_signal_watch()
- self.bus.connect('message', self._on_message)
+ self.pipe = gst.Pipeline('pipeline')
+ v4l2src = gst.element_factory_make('v4l2src', None)
+ v4l2src.props.device = device
+ self.pipe.add(v4l2src)
+ ffmpegcolorspace = gst.element_factory_make('ffmpegcolorspace', None)
+ self.pipe.add(ffmpegcolorspace)
+ gdkpixbufsink = gst.element_factory_make('gdkpixbufsink', None)
+ self.pipe.add(gdkpixbufsink)
+ gst.element_link_many(v4l2src, ffmpegcolorspace, gdkpixbufsink)
+ if self.pipe is not None:
+ self.bus = self.pipe.get_bus()
+ self.bus.add_signal_watch()
+ self.bus.connect('message', self._on_message)
+ status = True
+ else:
+ status = False
def _on_message(self, bus, message):
''' We get a message if a pixbuf is available '''
if message.structure is not None:
- # debug_output(message.structure.get_name(), True)
if message.structure.get_name() == 'pixbuf':
self.pixbuf = message.structure['pixbuf']
self.image_ready = True
@@ -54,7 +63,6 @@ class Camera():
self.pipe.set_state(gst.STATE_PLAYING)
while not self.image_ready:
self.bus.poll(gst.MESSAGE_ANY, -1)
- # self.stop_camera_input()
def stop_camera_input(self):
''' Stop grabbing '''