changeset 1087:1f877950ad28

new picamserve for raspberry pi camera -> http, especially with crop control Ignore-this: 38fc34a6eff577c05129df87d6133a95
author Drew Perttula <drewp@bigasterisk.com>
date Wed, 04 Jun 2014 08:30:45 +0000
parents c42b32853560
children bb92c50438ed
files bin/picamserve bin/run_local.py light9/vidref/gui.js light9/vidref/index.html makefile
diffstat 5 files changed, 133 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/picamserve	Wed Jun 04 08:30:45 2014 +0000
@@ -0,0 +1,71 @@
+#!env_pi/bin/python
+from __future__ import division
+from run_local import log
+import sys;sys.path.append('/usr/lib/python2.7/dist-packages/')
+import io, logging, traceback
+import cyclone.web
+from twisted.internet import reactor
+from light9 import prof
+
+try:
+    import picamera
+    cameraCls = picamera.PiCamera
+except ImportError:
+    class cameraCls(object):
+        def __enter__(self): return self
+        def __exit__(self): pass
+        def capture(self, out, *a, **kw):
+            out.write(open('yuv.demo').read())
+
+@prof.logTime
+def getFrame(c, arg):
+    res = int(arg('res', 480))
+    c.resolution = {
+        480: (640, 480),
+        1080: (1920, 1080),
+        1944: (2592, 1944),
+    }[res]
+    c.shutter_speed = int(arg('shutter', 50000))
+    c.exposure_mode = arg('exposure_mode', 'fixedfps')
+    c.awb_mode = arg('awb_mode', 'off')
+    c.brightness = int(arg('brightness', 50))
+    
+    c.awb_gains = (float(arg('redgain', 1)), float(arg('bluegain', 1)))
+    c.crop = (float(arg('x', 0)), float(arg('y', 0)),
+              float(arg('w', 1)), float(arg('h', 1)))
+    rw = rh = int(arg('resize', 100))
+    # width 1920, showing w=.3 of image, resize=100 -> scale is 100/.3*1920
+    # scl is [ output px / camera px ]
+    scl1 = rw / (c.crop[2] * c.resolution[0])
+    scl2 = rh / (c.crop[3] * c.resolution[1])
+    if scl1 < scl2:
+        # width is the constraint; reduce height to the same scale
+        rh = int(scl1 * c.crop[3] * c.resolution[1])
+    else:
+        # height is the constraint
+        rw = int(scl2 * c.crop[2] * c.resolution[0])
+    c.ISO = int(arg('iso', 250))
+    out = io.BytesIO('w')
+    prof.logTime(c.capture)(out, 'jpeg', use_video_port=True, resize=(rw, rh))
+    return out.getvalue()
+
+class Pic(cyclone.web.RequestHandler):
+    def get(self):
+        try:
+            self.set_header('Content-Type', 'image/jpeg')
+            self.write(getFrame(self.settings.camera, self.get_argument))
+        except Exception:
+            traceback.print_exc()
+        
+log.setLevel(logging.INFO)
+
+with cameraCls() as camera:
+    port = 8001
+    reactor.listenTCP(port, cyclone.web.Application(handlers=[
+        (r'/pic', Pic),
+        (r'/static/(.*)', cyclone.web.StaticFileHandler, {'path': 'static/'}),
+        (r'/(|gui.js)', cyclone.web.StaticFileHandler, {'path': 'light9/vidref/',
+                                                 'default_filename': 'index.html'}),
+        ], debug=True, camera=camera))
+    log.info("serving on %s" % port)
+    reactor.run()
--- a/bin/run_local.py	Wed Jun 04 08:27:34 2014 +0000
+++ b/bin/run_local.py	Wed Jun 04 08:30:45 2014 +0000
@@ -16,8 +16,12 @@
         Failure(val, exc, tb).printDetailedTraceback()
 Tkinter.Tk.report_callback_exception = rce
 
-import coloredlogs, logging, time, faulthandler
-faulthandler.enable()
+import coloredlogs, logging, time
+try:
+    import faulthandler
+    faulthandler.enable()
+except ImportError:
+    pass
 log = logging.getLogger()
 
 class CSH(coloredlogs.ColoredStreamHandler):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/vidref/gui.js	Wed Jun 04 08:30:45 2014 +0000
@@ -0,0 +1,11 @@
+var model = {
+    shutters: [],
+};
+for (var s=0; s < 1; s+=.04) {
+    var micro = Math.floor(Math.pow(s, 3) * 100000)
+    if (micro == 0) {
+        continue;
+    }
+    model.shutters.push(micro);
+}
+ko.applyBindings(model)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/vidref/index.html	Wed Jun 04 08:30:45 2014 +0000
@@ -0,0 +1,37 @@
+<!doctype html>
+<html>
+  <head>
+    <title>picamserve</title>
+    <meta charset="utf-8" />
+    <style>
+      .tile {
+        display: inline-block;
+       border: 1px solid gray;
+       margin: 3px;
+       padding: 2px;
+       }
+     .tile img {
+       }
+     
+    </style>
+  </head>
+  <body>
+    <section>
+      Whole view
+      <div class="tile">
+        <img src="pic?resize=500&awb_mode=auto&exposure_mode=auto&shutter=100000">
+      </div>
+    </section>
+  <section>
+    Shutters
+      <div data-bind="foreach: shutters">
+        <div class="tile">
+          <div><img data-bind="attr: {src: 'pic?res=480&resize=200&x=.5&y=.3&w=.5&h=.2&awb_mode=auto&exposure_mode=auto&shutter='+$data}"></div>
+          <span data-bind="text: ($data / 1000) + ' ms'"></span> 
+        </div>
+      </div>
+    </section>
+    <script src="static/knockout-3.1.0.js"></script>
+    <script src="gui.js"></script>
+  </body>
+</html>
--- a/makefile	Wed Jun 04 08:27:34 2014 +0000
+++ b/makefile	Wed Jun 04 08:30:45 2014 +0000
@@ -51,3 +51,11 @@
 
 packages:
 	sudo aptitude install coffeescript freemind normalize-audio audacity python-pygoocanvas python-pygame
+
+raspberry_pi_virtualenv:
+	mkdir -p env_pi
+	virtualenv --system-site-packages env_pi
+
+raspberry_pi_packages:
+	sudo apt-get install python-picamera python-twisted 
+	env_pi/bin/pip install cyclone coloredlogs