changeset 1570:0480fc790527

paint now looks for best match Ignore-this: 5604a2a2181624a0612dddf1afa32985
author Drew Perttula <drewp@bigasterisk.com>
date Sat, 27 May 2017 12:22:28 +0000
parents 654c41ccf265
children 9bfd2303f011
files bin/effecteval bin/paintserver light9/paint/solve.py light9/web/paint/paint-elements.coffee light9/web/paint/paint-elements.html light9/web/paint/paint-report-elements.html
diffstat 6 files changed, 93 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/bin/effecteval	Thu May 25 07:01:42 2017 +0000
+++ b/bin/effecteval	Sat May 27 12:22:28 2017 +0000
@@ -69,7 +69,6 @@
             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)
--- a/bin/paintserver	Thu May 25 07:01:42 2017 +0000
+++ b/bin/paintserver	Sat May 27 12:22:28 2017 +0000
@@ -14,6 +14,7 @@
 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 @@
         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):
--- a/light9/paint/solve.py	Thu May 25 07:01:42 2017 +0000
+++ b/light9/paint/solve.py	Sat May 27 12:22:28 2017 +0000
@@ -64,33 +64,51 @@
 
     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 @@
         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 @@
         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
--- a/light9/web/paint/paint-elements.coffee	Thu May 25 07:01:42 2017 +0000
+++ b/light9/web/paint/paint-elements.coffee	Sat May 27 12:22:28 2017 +0000
@@ -9,9 +9,9 @@
     {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 @@
     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 @@
     @$.paint.addEventListener('touchend', @onUp.bind(@))
 
   evPos: (ev) ->
-    return (if ev.touches?.length? then [Math.round(ev.touches[0].clientX),
-                                         Math.round(ev.touches[0].clientY)] else [ev.x, ev.y]) 
+    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 @@
     @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 @@
   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
--- a/light9/web/paint/paint-elements.html	Thu May 25 07:01:42 2017 +0000
+++ b/light9/web/paint/paint-elements.html	Sat May 27 12:22:28 2017 +0000
@@ -1,10 +1,14 @@
 <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>
+    <light9-paint-canvas id="canvas" bg="bg2.jpg" painting="{{painting}}"></light9-paint-canvas>
 
-        <div>Error: 280844</div>
-        
-        <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>
-            
-          </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>
-
+    <iron-ajax id="solve" method="POST" url="../paintServer/solve" last-response="{{solve}}"></iron-ajax>
+    
+    <light9-simulation solution="{{solve}}" layers="{{layers}}"></light9-simulation>
   </template>
 </dom-module>
 
--- a/light9/web/paint/paint-report-elements.html	Thu May 25 07:01:42 2017 +0000
+++ b/light9/web/paint/paint-report-elements.html	Sat May 27 12:22:28 2017 +0000
@@ -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>