diff --git a/bin/effecteval b/bin/effecteval --- a/bin/effecteval +++ b/bin/effecteval @@ -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) diff --git a/bin/paintserver b/bin/paintserver --- a/bin/paintserver +++ b/bin/paintserver @@ -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): diff --git a/light9/paint/solve.py b/light9/paint/solve.py --- a/light9/paint/solve.py +++ b/light9/paint/solve.py @@ -64,33 +64,51 @@ 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 diff --git a/light9/web/paint/paint-elements.coffee b/light9/web/paint/paint-elements.coffee --- a/light9/web/paint/paint-elements.coffee +++ b/light9/web/paint/paint-elements.coffee @@ -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), - 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 @@ 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 diff --git a/light9/web/paint/paint-elements.html b/light9/web/paint/paint-elements.html --- a/light9/web/paint/paint-elements.html +++ b/light9/web/paint/paint-elements.html @@ -1,10 +1,14 @@ + - + - + - + - - - - - diff --git a/light9/web/paint/paint-report-elements.html b/light9/web/paint/paint-report-elements.html --- a/light9/web/paint/paint-report-elements.html +++ b/light9/web/paint/paint-report-elements.html @@ -20,7 +20,7 @@
Single pic best match:
- +
Error: 280844