Changeset - 0480fc790527
[Not reviewed]
default
0 6 0
Drew Perttula - 8 years ago 2017-05-27 12:22:28
drewp@bigasterisk.com
paint now looks for best match
Ignore-this: 5604a2a2181624a0612dddf1afa32985
6 files changed with 88 insertions and 173 deletions:
0 comments (0 inline, 0 general)
bin/effecteval
Show inline comments
 
@@ -69,7 +69,6 @@ class SongEffects(PrettyErrorHandler, cy
 
            note = URIRef(note)
 

	
 
        log.info("adding to %s", song)
 

	
 
        note, p = yield songNotePatch(self.settings.graph, dropped, song, event, ctx=song, note=note)
 
        
 
        self.settings.graph.patch(p)
bin/paintserver
Show inline comments
 
@@ -14,6 +14,7 @@ from rdflib import URIRef
 
from light9.rdfdb import clientsession
 
import light9.paint.solve
 
from lib.cycloneerr import PrettyErrorHandler
 
from light9.namespaces import RDF, L9, DEV
 

	
 

	
 
class Solve(PrettyErrorHandler, cyclone.web.RequestHandler):
 
@@ -23,9 +24,18 @@ class Solve(PrettyErrorHandler, cyclone.
 
        solver = light9.paint.solve.Solver(self.settings.graph)
 
        solver.loadSamples()
 
        with self.settings.stats.solve.time():
 
            out = solver.solve(painting)
 
            layers = solver.simulationLayers(out)
 
        self.write(json.dumps({'layers': layers, 'out': out}))
 
            img = solver.draw(painting)
 
            sample = solver.bestMatch(img)
 
            with self.settings.graph.currentState() as g:
 
                bestPath = 'show/dance2017/cam/test/%s' % g.value(sample, L9['path'])
 
            #out = solver.solve(painting)
 
            #layers = solver.simulationLayers(out)
 
            
 
        self.write(json.dumps({
 
            'bestMatch': {'uri': sample, 'path': bestPath},
 
        #    'layers': layers,
 
        #    'out': out,
 
        }))
 

	
 
class App(object):
 
    def __init__(self, show, session):
light9/paint/solve.py
Show inline comments
 
@@ -65,32 +65,50 @@ class Solver(object):
 
    def _blur(self, img):
 
        return scipy.ndimage.gaussian_filter(img, 10, 0, mode='nearest')
 
                
 
    def draw(self, painting, w, h):
 
    def draw(self, painting):
 
        return self._draw(painting, 100, 48)
 
        
 
    def _draw(self, painting, w, h):
 
        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
 
        ctx = cairo.Context(surface)
 
        ctx.rectangle(0, 0, w, h)
 
        ctx.fill()
 
        
 
        ctx.set_line_cap(cairo.LINE_CAP_ROUND)
 
        ctx.set_line_width(20)
 
        ctx.set_line_width(20) # ?
 
        for stroke in painting['strokes']:
 
            for pt in stroke['pts']:
 
                op = ctx.move_to if pt is stroke['pts'][0] else ctx.line_to
 
                op(pt[0] / 4, pt[1] / 4) # todo scale
 
                op(pt[0] * w, pt[1] * h)
 

	
 
            r,g,b = parseHex(stroke['color'])
 
            ctx.set_source_rgb(r / 255, g / 255, b / 255)
 
            ctx.stroke()
 
        
 
        #surface.write_to_png('/tmp/surf.png')
 
        surface.write_to_png('/tmp/surf.png')
 
        return numpyFromCairo(surface)
 
        
 

	
 
    def _imgDist(self, a, b):
 
        return numpy.sum(numpy.absolute(a - b), axis=None)
 
        
 
    def bestMatch(self, img):
 
        results = []
 
        for uri, img2 in self.samples.iteritems():
 
            results.append((self._imgDist(img, img2), uri, img2))
 
        results.sort()
 
        print 'results:'
 
        for r in results:
 
            print r
 
        saveNumpy('/tmp/bestsamp.png', results[-1][2])
 
        return results[-1][1]
 
        
 
    def solve(self, painting):
 
        """
 
        given strokes of colors on a photo of the stage, figure out the
 
        best light DeviceSettings to match the image
 
        """
 
        pic0 = self.draw(painting, 100, 48).astype(numpy.float)
 
        pic0 = self.draw(painting).astype(numpy.float)
 
        pic0Blur = self._blur(pic0)
 
        saveNumpy('/tmp/sample_paint_%s.png' % len(painting['strokes']),
 
                  pic0Blur)
 
@@ -98,7 +116,7 @@ class Solver(object):
 
        for sample, picSample in sorted(self.blurredSamples.items()):
 
            #saveNumpy('/tmp/sample_%s.png' % sample.split('/')[-1],
 
            #          f(picSample))
 
            dist = numpy.sum(numpy.absolute(pic0Blur - picSample), axis=None)
 
            dist = self._imgDist(pic0Blur, picSample)
 
            sampleDist[sample] = dist
 
        results = [(d, uri) for uri, d in sampleDist.items()]
 
        results.sort()
 
@@ -119,7 +137,7 @@ class Solver(object):
 
        return s
 

	
 
    def solveBrute(self, painting):
 
        pic0 = self.draw(painting, 100, 48).astype(numpy.float)
 
        pic0 = self.draw(painting).astype(numpy.float)
 

	
 
        colorSteps = 3
 
        colorStep = 1. / colorSteps
light9/web/paint/paint-elements.coffee
Show inline comments
 
@@ -9,9 +9,9 @@ class Painting
 
    {strokes: @strokes}
 

	
 
class Stroke
 
  constructor: (pos, @color) ->
 
  constructor: (pos, @color, @size) ->
 
    @path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
 
    @path.setAttributeNS(null, 'd', "M #{pos[0]} #{pos[1]}")
 
    @path.setAttributeNS(null, 'd', "M #{pos[0]*@size[0]} #{pos[1]*@size[1]}")
 
    @pts = [pos]
 
    @lastPos = pos
 

	
 
@@ -19,20 +19,22 @@ class Stroke
 
    parent.appendChild(@path)
 
    
 
  move: (pos) ->
 
    if Math.hypot(pos[0] - @lastPos[0], pos[1] - @lastPos[1]) < 30
 
    if Math.hypot(pos[0] - @lastPos[0], pos[1] - @lastPos[1]) < .02
 
      return
 
    @path.attributes.d.value += " L #{pos[0]} #{pos[1]}"
 
    @path.attributes.d.value += " L #{pos[0]*@size[0]} #{pos[1]*@size[1]}"
 
    @pts.push(pos)
 
    @lastPos = pos
 
  
 
Polymer
 
  is: "light9-paint"
 
  is: "light9-paint-canvas"
 
  behaviors: [ Polymer.IronResizableBehavior ]
 
  listeners: 'iron-resize': 'onResize'
 
  properties: {
 
    layers: { type: Object }
 
    bg: { type: String },
 
    painting: { type: Object } # output
 
  }
 
  ready: ->
 
    @onResize()
 
    @painting = new Painting()
 
    @$.paint.addEventListener('mousedown', @onDown.bind(@))
 
    @$.paint.addEventListener('mousemove', @onMove.bind(@))
 
@@ -42,12 +44,13 @@ Polymer
 
    @$.paint.addEventListener('touchend', @onUp.bind(@))
 

	
 
  evPos: (ev) ->
 
    return (if ev.touches?.length? then [Math.round(ev.touches[0].clientX),
 
    px = (if ev.touches?.length? then [Math.round(ev.touches[0].clientX),
 
                                         Math.round(ev.touches[0].clientY)] else [ev.x, ev.y]) 
 
    return [px[0] / @size[0], px[1] / @size[1]]
 

	
 
  onDown: (ev) ->
 
    # if it's on an existing one, do selection
 
    @stroke = new Stroke(@evPos(ev), '#aaaaaa')
 
    @stroke = new Stroke(@evPos(ev), '#aaaaaa', @size)
 
    @stroke.appendElem(@$.paint)
 
    @scopeSubtree(@$.paint)
 

	
 
@@ -57,19 +60,23 @@ Polymer
 
    @stroke.move(@evPos(ev))
 

	
 
  onUp: (ev) ->
 
    return unless @stroke
 
    @painting.addStroke(@stroke.pts, @stroke.color)
 
    @$.solve.body = JSON.stringify(@painting.getDoc())
 
    @$.solve.generateRequest()
 
    @stroke = null
 

	
 
    @notifyPath('painting.strokes.length') # not working
 
    @fire('paintingChanged', @painting)
 

	
 
  onResize: (ev) ->
 
    @$.paint.attributes.viewBox.value = "0 0 #{ev.target.offsetWidth} 500"
 
    @size = [@$.parent.offsetWidth, @$.parent.offsetHeight]
 
    @$.paint.attributes.viewBox.value = "0 0 #{@size[0]} #{@size[1]}"
 

	
 

	
 
Polymer
 
  is: "light9-simulation"
 
  properties: {
 
    layers: { type: Object }
 
    solution: { type: Object }
 
  }
 
  listeners: [
 
    "onLayers(layers)"
 
@@ -77,4 +84,24 @@ Polymer
 
  ready: ->
 
    null
 
  onLayers: (layers) ->
 
    log('upd', layers)
 
\ No newline at end of file
 
    log('upd', layers)
 

	
 
    
 
Polymer
 
  is: "light9-paint"
 
  properties: {
 
    painting: { type: Object }
 
  }
 

	
 
  ready: () ->
 
    # couldn't make it work to bind to painting's notifyPath events
 
    @$.canvas.addEventListener('paintingChanged', @paintingChanged.bind(@))
 
    @$.solve.addEventListener('response', @onSolve.bind(@))
 
    
 
  paintingChanged: (ev) ->
 
    @painting = ev.detail
 
    @$.solve.body = JSON.stringify(@painting.getDoc())
 
    @$.solve.generateRequest()
 

	
 
  onSolve: (response) ->
 
    console.log(response)
 
\ No newline at end of file
light9/web/paint/paint-elements.html
Show inline comments
 
<link rel="import" href="/lib/polymer/polymer.html">
 
<link rel="import" href="/lib/iron-resizable-behavior/iron-resizable-behavior.html">
 
<link rel="import" href="/lib/iron-ajax/iron-ajax.html">
 
<link rel="import" href="paint-report-elements.html">
 

	
 
<dom-module id="light9-paint">
 
<dom-module id="light9-paint-canvas">
 
  <template>
 
    <style>
 
     :host {
 
         display: block;
 
     }
 
     #parent {
 
         position: relative;
 
         height: 500px;
 
@@ -34,9 +38,8 @@
 
      - erase
 
    </div>
 
    
 
    <iron-ajax id="solve" method="POST" url="../paintServer/solve"></iron-ajax>
 
    <div id="parent">
 
      <img src="bg2.jpg">
 
      <img src="{{bg}}">
 
      <svg id="paint" viewBox="0 0 500 221">
 
        <defs id="defs12751">
 
          <filter
 
@@ -76,159 +79,17 @@
 
        </defs>
 
      </svg>
 
    </div>
 

	
 
    
 
    
 
    <light9-simulation layers="{{layers}}"></light9-simulation>
 
  </template>
 
</dom-module>
 

	
 
<!-- merge more with light9-collector-device -->
 
<dom-module id="light9-device-settings">
 
  <template>
 
    <style>
 
     :host {
 
         display: block;
 
         break-inside: avoid-column;
 
         border: 2px solid gray;
 
         padding: 8px;
 
     }
 
     td.nonzero {
 
         background: #310202;
 
         color: #e25757;
 
     }
 
     td.full {
 
         background: #2b0000;
 
         color: red;
 
         font-weight: bold;
 
     }
 
    </style>
 
    <h3>{{label}}</h3>
 
    <table class="borders">
 
      <tr>
 
        <th>device attr</th>
 
        <th>value</th>
 
      </tr>
 
      <template is="dom-repeat" items="{{attrs}}">
 
        <tr>
 
          <td>{{item.attr}}</td>
 
          <td class$="{{item.valClass}}">{{item.val}}</td>
 
        </tr>
 
      </template>
 

	
 
  </template>
 
  <script>
 
   HTMLImports.whenReady(function () {
 
       Polymer({
 
           is: "light9-device-settings",
 
           properties: {
 
               label: {type: String, notify: true},
 
               attrs: {type: Array, notify: true},
 

	
 
           },
 
           ready: function() {
 

	
 
               this.label = "aura2";
 
               this.attrs = [
 
                   {attr: 'rx', val: .03},
 
                   {attr: 'color', val: '#ffe897'},
 
               ];
 
                    
 
           }
 
       });
 
   });
 
  </script>
 
</dom-module>
 

	
 
<dom-module id="light9-capture-image">
 
<dom-module id="light9-paint">
 
  <template>
 
    <style>
 
     :host { display: block; }
 
    </style>
 
    <div>{{name}}</div>
 
    <div><img width="100" src="../{{path}}"></div>
 
  </template>
 
  <script>
 
   HTMLImports.whenReady(function () {
 
       Polymer({
 
           is: "light9-capture-image",
 
           properties: {
 
               name: { type: String },
 
               path: { type: String },
 
           }
 
       });
 
   });
 
  </script>
 
</dom-module>
 

	
 
<dom-module id="light9-simulation">
 
  <template>
 
    <style>
 
     #solutions { display: flex; margin: 20px; }
 
     #single-light { margin-right: 70px; }
 
     #multi-light {}
 
     #breakdown { position: relative; }
 
     #sources { display: flex; }
 
     #solution { display: flex; margin-top: 80px; }
 
     #connectors { position: absolute; width: 100%; height: 100%; }
 
     #connectors path { stroke: #615c54; stroke-width: 3px; }
 
    </style>
 

	
 
    <div id="solutions">
 
      <div id="single-light">
 
        <div>Single pic best match:</div>
 

	
 
        <light9-capture-image name="mac2" path="show/dance2017/capture/moving1/cap258592/pic1.jpg"></light9-capture-image>
 

	
 
        <div>Error: 280844</div>
 
    <light9-paint-canvas id="canvas" bg="bg2.jpg" painting="{{painting}}"></light9-paint-canvas>
 
        
 
        <div>DeviceSettings</div>
 
        <light9-device-settings></light9-device-settings>
 
      </div>
 

	
 
      <!-- existing effect best match? -->
 
      
 
      <div id="multi-light">
 
        Created from multiple lights:
 

	
 
        <div id="breakdown">
 
          <svg id="connectors">
 
            <g>
 
              <path d="M 112,241 L 150,280"></path>
 
              <path d="M 332,241 L 150,280"></path>
 
              <path d="M 532,241 L 150,280"></path>
 
              <path d="M 732,241 L 150,280"></path>
 
            </g>
 
    <iron-ajax id="solve" method="POST" url="../paintServer/solve" last-response="{{solve}}"></iron-ajax>
 
            
 
          </svg>
 
          <div id="sources">
 
            <div>
 
              <light9-capture-image name="aura1" path="show/dance2017/capture/moving1/cap258592/pic1.jpg"></light9-capture-image>
 
              <light9-device-settings></light9-device-settings>
 
            </div>
 
            <div>
 
              <light9-capture-image name="aura2" path="show/dance2017/capture/moving1/cap258592/pic1.jpg"></light9-capture-image>
 
              <light9-device-settings></light9-device-settings>
 
            </div>
 
            <div>
 
              <light9-capture-image name="aura3" path="show/dance2017/capture/moving1/cap258592/pic1.jpg"></light9-capture-image>
 
              <light9-device-settings></light9-device-settings>
 
            </div>
 
            <div>
 
              <light9-capture-image name="aura4" path="show/dance2017/capture/moving1/cap258592/pic1.jpg"></light9-capture-image>
 
              <light9-device-settings></light9-device-settings>
 
            </div>
 
          </div>
 
          
 
          <div id="solution">
 
            <div> <div>combined</div><div><img width="150" src="../show/dance2017/capture/moving1/cap258592/pic1.jpg"></div><div>error 9980</div></div>
 
            <div> <div>residual</div><div><img width="150" src="../show/dance2017/capture/moving1/cap258592/pic1.jpg"></div></div>
 
          </div>
 
        </div>
 

	
 
        Save as effect named <input> <button>Save</button>
 
      </div>
 

	
 
    <light9-simulation solution="{{solve}}" layers="{{layers}}"></light9-simulation>
 
  </template>
 
</dom-module>
 

	
light9/web/paint/paint-report-elements.html
Show inline comments
 
@@ -20,7 +20,7 @@
 
        <div>Single pic best match:</div>
 

	
 
        <!-- drag this img to make an effect out of just it -->
 
        <light9-capture-image name="mac2" path="show/dance2017/capture/moving1/cap258592/pic1.jpg"></light9-capture-image>
 
        <light9-capture-image name="mac2" path="{{solution.bestMatch.path}}"></light9-capture-image>
 

	
 
        <div>Error: 280844</div>
 
        
0 comments (0 inline, 0 general)