[mousetrap/gnome3-wip: 56/240] Add gui, main, and vision. Lots of renames.



commit 07177f8964883f1176de6372255760a98c9a1311
Author: Stoney Jackson <dr stoney gmail com>
Date:   Wed Jun 4 20:11:18 2014 -0400

    Add gui, main, and vision. Lots of renames.

 src/mousetrap/Makefile.am                        |    6 +-
 src/mousetrap/camera.py                          |   32 -----------
 src/mousetrap/gui.py                             |   66 ++++++++++++++++++++++
 src/mousetrap/main.py                            |   34 +++++++++++
 src/mousetrap/{mouse.py => pointer.py}           |    2 +-
 src/mousetrap/test_camera.py                     |   24 --------
 src/mousetrap/{test_mouse.py => test_pointer.py} |   13 ++--
 src/mousetrap/test_vision.py                     |   25 ++++++++
 src/mousetrap/vision.py                          |   37 ++++++++++++
 9 files changed, 173 insertions(+), 66 deletions(-)
---
diff --git a/src/mousetrap/Makefile.am b/src/mousetrap/Makefile.am
index 78deb2d..9e4e8de 100644
--- a/src/mousetrap/Makefile.am
+++ b/src/mousetrap/Makefile.am
@@ -5,8 +5,10 @@ mousetrap_pathdir=$(pyexecdir)
 
 mousetrap_python_PYTHON = \
        __init__.py \
-       camera.py \
-       mouse.py
+       vision.py \
+       pointer.py \
+       main.py \
+       gui.py
 
 #SUBDIRS =
 
diff --git a/src/mousetrap/gui.py b/src/mousetrap/gui.py
new file mode 100644
index 0000000..7c6cde8
--- /dev/null
+++ b/src/mousetrap/gui.py
@@ -0,0 +1,66 @@
+from gi.repository import Gtk
+from gi.repository import GdkPixbuf
+
+
+_GDK_PIXBUF_BIT_PER_SAMPLE = 8
+
+
+class ImageWindow(object):
+    def __init__(self, message):
+        self._window = Gtk.Window(title=message)
+        self._canvas = Gtk.Image()
+        self._window.add(self._canvas)
+
+        # FIXME: Closing any window kills the application. Need a mechanism
+        # that allows windows to be openned and closed, and only kill the
+        # application when the last window is closed.
+        self._window.connect("delete-event", Gtk.main_quit)
+
+        self._window.show_all()
+
+    def draw(self, image):
+        '''Draw image to this window.
+        '''
+        image = _get_pixbuf_from_image(image)
+        self._canvas.set_from_pixbuf(image)
+        self._canvas.queue_draw()
+
+
+def _get_pixbuf_from_image(image):
+    if isinstance(image, GdkPixbuf.Pixbuf):
+        return image
+    return _cvimage_to_pixbuf(image)
+
+
+def _cvimage_to_pixbuf(cvimage):
+    data = cvimage.tostring()
+    colorspace = GdkPixbuf.Colorspace.RGB
+    has_alpha_channel = False
+    width = cvimage.shape[1]
+    height = cvimage.shape[0]
+    return GdkPixbuf.Pixbuf.new_from_data(
+            data,
+            colorspace, # FIXME: Need to handle grayscale.
+            has_alpha_channel,
+            _GDK_PIXBUF_BIT_PER_SAMPLE,
+            width,
+            height,
+            cvimage.strides[0], # FIXME: what is this parameter?
+            None, # FIXME: what is this parameter?
+            None  # FIXME: what is this parameter?
+            )
+
+
+_WINDOWS = {}
+def show_image(window_name, image):
+    '''Displays image in window named by window_name.
+       May reuse named windows.
+       '''
+    if window_name not in _WINDOWS:
+        _WINDOWS[window_name] = ImageWindow(window_name)
+    _WINDOWS[window_name].draw(image)
+
+
+def start():
+    '''Start handling events.'''
+    Gtk.main()
diff --git a/src/mousetrap/main.py b/src/mousetrap/main.py
new file mode 100644
index 0000000..4d78855
--- /dev/null
+++ b/src/mousetrap/main.py
@@ -0,0 +1,34 @@
+from gi.repository import GObject
+
+import mousetrap.vision as vision
+import mousetrap.gui as gui
+
+
+# OpenCV will automatically search for a working camera device if we use the
+# index -1.
+DEVICE_INDEX = -1
+IMAGE_MAX_WIDTH = 400
+IMAGE_MAX_HEIGHT = 300
+FPS = 5
+INTERVAL = int(round(1000.0 / FPS))
+
+
+class Main(object):
+    def __init__(self):
+        self.image = None
+        self.timeout_id = None
+        self.camera = vision.Camera(DEVICE_INDEX,
+                IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT)
+
+    def run(self):
+        self.timeout_id = GObject.timeout_add(INTERVAL, self.on_timeout, None)
+        gui.start()
+
+    def on_timeout(self, user_data):
+        self.image = self.camera.read_image()
+        gui.show_image('diff', self.image)
+        return True
+
+
+if __name__ == '__main__':
+    Main().run()
diff --git a/src/mousetrap/mouse.py b/src/mousetrap/pointer.py
similarity index 95%
rename from src/mousetrap/mouse.py
rename to src/mousetrap/pointer.py
index 1011ec5..060b865 100644
--- a/src/mousetrap/mouse.py
+++ b/src/mousetrap/pointer.py
@@ -1,7 +1,7 @@
 from gi.repository import Gdk
 
 
-class Mouse(object):
+class Pointer(object):
 
     def __init__(self):
         gdk_display = Gdk.Display.get_default()
diff --git a/src/mousetrap/test_mouse.py b/src/mousetrap/test_pointer.py
similarity index 59%
rename from src/mousetrap/test_mouse.py
rename to src/mousetrap/test_pointer.py
index 2bb215d..f02d11e 100644
--- a/src/mousetrap/test_mouse.py
+++ b/src/mousetrap/test_pointer.py
@@ -1,15 +1,14 @@
 import unittest
-from mousetrap.mouse import Mouse
+import mousetrap.pointer as pointer
 
 
-class test_mouse(unittest.TestCase):
+class test_pointer(unittest.TestCase):
 
     def setUp(self):
-        self.mouse = Mouse()
+        self.pointer = pointer.Pointer()
 
     def test_get_position(self):
-        x, y = self.mouse.get_position()
-
+        x, y = self.pointer.get_position()
         try:
             x += 1
             y += 1
@@ -17,8 +16,8 @@ class test_mouse(unittest.TestCase):
             self.assertTrue(False, msg='x or y is not a number')
 
     def test_set_position(self):
-        self.mouse.set_position((3, 4))
-        x, y = self.mouse.get_position()
+        self.pointer.set_position((3, 4))
+        x, y = self.pointer.get_position()
         self.assertEquals(3, x)
         self.assertEquals(4, y)
 
diff --git a/src/mousetrap/test_vision.py b/src/mousetrap/test_vision.py
new file mode 100644
index 0000000..f01528a
--- /dev/null
+++ b/src/mousetrap/test_vision.py
@@ -0,0 +1,25 @@
+import unittest
+import mousetrap.vision as vision
+
+# OpenCV will automatically search for a working camera device if we use the
+# index -1.
+DEVICE_INDEX = -1
+IMAGE_MAX_WIDTH = 400
+IMAGE_MAX_HEIGHT = 300
+
+class test_camera(unittest.TestCase):
+
+    def setUp(self):
+        self.camera = vision.Camera(DEVICE_INDEX,
+                IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT)
+
+    def test_get_image_imageReturned(self):
+        image = self.camera.read_image()
+        self.assertTrue(
+            image is not None,
+            msg="Error: Image not captured"
+        )
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/mousetrap/vision.py b/src/mousetrap/vision.py
new file mode 100644
index 0000000..23d9cfb
--- /dev/null
+++ b/src/mousetrap/vision.py
@@ -0,0 +1,37 @@
+'''
+All things computer vision. Isolates OpenCV from the rest of the system.
+If you see another file using OpenCV directly, it should probably be using
+this module instead.
+'''
+
+import cv2
+from cv2 import cv
+
+
+S_CAPTURE_OPEN_ERROR = 'Device #%s does not support video capture interface'
+S_CAPTURE_READ_ERROR = 'Error while capturing. Camera disconnected?'
+
+
+class Camera(object):
+    def __init__(self, device_index, width, height):
+        self.device = self._new_capture_device(device_index)
+        self._set_dimensions(width, height)
+
+    @staticmethod
+    def _new_capture_device(device_index):
+        capture = cv2.VideoCapture(device_index)
+        if not capture.isOpened():
+            capture.release()
+            raise IOError(S_CAPTURE_OPEN_ERROR % device_index)
+        return capture
+
+    def _set_dimensions(self, width, height):
+        self.device.set(cv.CV_CAP_PROP_FRAME_WIDTH, width)
+        self.device.set(cv.CV_CAP_PROP_FRAME_HEIGHT, height)
+
+    def read_image(self):
+        ret, image = self.device.read()
+        if not ret:
+            raise IOError(S_CAPTURE_READ_ERROR)
+        return image
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]