Changeset - 1f877950ad28
[Not reviewed]
default
0 2 3
Drew Perttula - 11 years ago 2014-06-04 08:30:45
drewp@bigasterisk.com
new picamserve for raspberry pi camera -> http, especially with crop control
Ignore-this: 38fc34a6eff577c05129df87d6133a95
5 files changed with 132 insertions and 1 deletions:
0 comments (0 inline, 0 general)
bin/picamserve
Show inline comments
 
new file 100644
 
#!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()
bin/run_local.py
Show inline comments
 
@@ -7,26 +7,30 @@ sys.path.insert(0,os.path.join(os.path.d
 

	
 
from twisted.python.failure import Failure
 

	
 
import Tkinter
 
def rce(self, exc, val, tb):
 
    sys.stderr.write("Exception in Tkinter callback\n")
 
    if True:
 
        sys.excepthook(exc, val, tb)
 
    else:
 
        Failure(val, exc, tb).printDetailedTraceback()
 
Tkinter.Tk.report_callback_exception = rce
 

	
 
import coloredlogs, logging, time, faulthandler
 
import coloredlogs, logging, time
 
try:
 
    import faulthandler
 
faulthandler.enable()
 
except ImportError:
 
    pass
 
log = logging.getLogger()
 

	
 
class CSH(coloredlogs.ColoredStreamHandler):
 
    def render_timestamp(self, created):
 
        return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(created)) + (
 
            "%.3f" % (created % 1)).lstrip('0')
 

	
 
    def render_name(self, name):
 
        return name
 

	
 
log.addHandler(CSH(show_hostname=False, show_name=True))
 

	
light9/vidref/gui.js
Show inline comments
 
new file 100644
 
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)
light9/vidref/index.html
Show inline comments
 
new file 100644
 
<!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>
makefile
Show inline comments
 
@@ -42,12 +42,20 @@ tkdnd_build:
 
	# then apply tkdnd-patch-on-r95 to that
 
	cd tkdnd/trunk
 
	./configure
 
	make
 

	
 
bin/ascoltami2: gst_packages link_to_sys_packages
 

	
 
gst_packages:
 
	sudo aptitude install python-gi gir1.2-gst-plugins-base-1.0 libgirepository-1.0-1 gir1.2-gstreamer-1.0 gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-pulseaudio gir1.2-goocanvas-2.0-9
 

	
 
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
0 comments (0 inline, 0 general)