Morph Mirror – Hall Of Possibilities

 

Screen Shot 2015-11-10 at 6.09.11 PMIdea: Imagine a place called the Hall of Possibilities with paintings you walk into to live the future you desire … if only for a small period of time.  Proposed By Joy Buolamwini October 6, 2015

FROM IDEA  —————————————————————————————-TO  COMPOSITE

HallofPossibilitiesTransformedScreen Shot 2015-11-10 at 6.03.36 PM

Still incomprehensible to me , I somehow came upon a painting from the Hall of Possibilities which will be constructed some time in the future.

The painting was unlike any other I have  encountered. I saw myself reflected in the scene portrayed. When I reached out to touch the canvas, my entire being was transformed. The possibilities depicted in the painting became my reality.

My cosmik ring shone, and my morph configured into a form that could navigate the environment depicted . I began to look like the person I directed my gaze toward in the painting. The longer I stared the more my appearance began to mirror the person in the painting. Soon I could no longer look away, and I became part of the painting. My only escape would be to catch the gaze of another viewer and trap them as I had been caught.

More Details

THE THING FROM THE FUTURE: The Hall of Possibilities

MORPH MIRROR MATERIALS

IMG_20151110_170328297

  • Half Silvered Mirror
  • Styrofoam Base
  • Standard Monitor (Stand Removed)

SOFTWARE AND CODE SAMPLES:

  • Beyond Reality Face NXT – Face Detection and Tracking
  • Vibrant.js – Color Extraction from photos
  • jQuery – Merge Animation

PHASE 1-  Create Morph Canvas

  • Download Beyond Reality Face
  • Move the canvas with id=”_stage” to make room for mirror canvas
    • <canvas id=”_stage” width=”600″ height=”500″ style=”position:absolute;left:0px;top:0px;”>Your browser does not seem to support canvas elements.</canvas>

  • Add Separate Canvas Element next to Video Feed
    • add canvas element in index.html
    • <canvas id=”_mirror” width=”600″ height=”480″ style=”position:absolute;left:600px;top:0px;background:url(‘bg.jpg’);background-size:cover;opacity:1;”>.</canvas>

  • Add images to use as masks in index.html
  • <div style=”display:none;”>
    <img id=”source0″ src=”img/masks/mask0.png”
    width=”300″ height=”300″><img id=”source1″ src=”img/masks/mask1.png”
    width=”300″ height=”300″><img id=”source2″ src=”img/masks/mask2.png”
    width=”300″ height=”300″><img id=”source3″ src=”img/masks/mask3.png”
    width=”300″ height=”300″><img id=”source4″ src=”img/masks/mask4.png”
    width=”300″ height=”300″><img id=”source5″ src=”img/masks/mask5.png”
    width=”300″ height=”300″><img id=”source6″ src=”img/masks/mask6.png”
    width=”300″ height=”300″></div>
  • Using the face position modify BRF to add an image to the canvas in the same position as face.
  • In js/examples/ExampleFaceTracking.js edit  the _this.updateGUI  function
    • //get canvas to draw onvar canvasg = document.getElementById(“_mirror”);
      var ctx = canvasg.getContext(‘2d’);var roundedX = Math.round(faceShape.bounds.x);
      var roundedY = Math.round(faceShape.bounds.y);
      var roundedW = Math.round(faceShape.bounds.width);
      var roundedH = Math.round(faceShape.bounds.height);//clear canvas
      ctx.clearRect(0,0,600,500);
      ctx.fillStyle = “#ffff00”;var image = document.getElementById(“source” + maskID);//scale y position (.75) and height (1.25) to better fit face
      ctx.globalAlpha = 1;
      ctx.globalCompositeOperation = “orginal”;
      ctx.drawImage(image,roundedX  , roundedY * .75, roundedW, roundedH * 1.25);
  • Integrated jQuery Mobile to superimpose canvas element on top of video feed at the press of a button
    • Add button bar in index.html
    • <div style=”padding:10px;position:absolute;left:43%;top:500px;”> <button id=”moveleft”>Merge</button>  <button id=”moveright”>Isolate</button> <button id=”reset”>Reset</button></div>
    • Add Script to animate canvases
    • <script type=”text/javascript”>
      $(document).ready(function() {
      $(‘#moveleft’).click(function() {
      $(‘#_mirror’).animate({
      ‘marginLeft’ : “-=300px” //moves left
      }).animate({
      ‘opacity’ : “-=.3” //moves left
      });$(‘#frame’).animate({
      ‘marginLeft’ : “-=300px” //moves left
      }).animate({
      ‘opacity’ : “-=.3” //moves left
      });$(‘#_stage’).animate({
      ‘marginLeft’ : “+=300px” //moves left
      }).animate({
      ‘opacity’ : “-=.1” //moves left
      });
      });
      $(‘#moveright’).click(function() {
      $(‘#_mirror’).animate({
      ‘marginLeft’ : “+=300px” //moves right
      }).animate({
      ‘opacity’ : “+=.3” //moves left
      });$(‘#frame’).animate({
      ‘marginLeft’ : “+=300px” //moves right
      }).animate({
      ‘opacity’ : “+=.3” //moves left
      });$(‘#_stage’).animate({
      ‘marginLeft’ : “-=300px” //moves right
      }).animate({
      ‘opacity’ : “+=.3” //moves left
      });
      });
      $(‘#reset’).click(function() {
      $(‘#_mirror’).animate({
      ‘marginLeft’ : “600px” //moves left
      }).animate({
      ‘opacity’ : “1” //moves left
      });$(‘#frame’).animate({
      ‘marginLeft’ : “600px” //moves left
      }).animate({
      ‘opacity’ : “1” //moves left
      });$(‘#_stage’).animate({
      ‘marginLeft’ : “0px” //moves left
      }).animate({
      ‘opacity’ : “1” //moves left
      });
      });
      $(‘#moveup’).click(function() {
      $(‘#textbox’).animate({
      ‘marginTop’ : “-=30px” //moves up
      });
      });
      });
      </script>

PHASE 2- Add Color Extraction

  • Add Vibrant.js  to index.html
  • Use sample code from Typanus to get started
    • http://tympanus.net/codrops/2015/06/04/color-extraction-effect/
    • in index.html add unique id to span tags containing the hex colors
    • I used #color1, #color2, #color3, etc
  • Save extracted colors in js/examples/ExampleFaceTracking.js
    • //Palette Colors
      var color1 = document.getElementById(“color” + 1);
      var color2 = document.getElementById(“color” + 2);
      var color3 = document.getElementById(“color” + 3);
      var color4 = document.getElementById(“color” + 4);
      var color5 = document.getElementById(“color” + 5);if(color1 != null && color1.innerHTML != “#######”){var fill1 = color1.innerHTML;
      var fill2 = color2.innerHTML;
      var fill3 = color3.innerHTML;
      var fill4 = color4.innerHTML;
      var fill5 = color5.innerHTML;}
      else{var fill1 = “#acfeff”;
      var fill2 = “#ffff00”;
      var fill3 = “#ff7900”;
      var fill4 = “#00f6ff”;
      var fill5 = “#00f6ff”;}
  • Modify BRF library to draw triangles with filled colors based on parameters passed in
  • Go to bin/js/brf/BRF_NXT_public_API.js
  • Add additional fill and alpha parameters and color based on multiples of 3 or 5
  • lib.DrawingUtils.drawTriangles = function(g, vertices, triangles, clear, lineThickness, lineColor, lineAlpha, fillColor, fillAlpha, fillColor2, fillAlpha2, fillColor3, fillAlpha3) {
    clear = lib.defaultValue(clear, false);
    lineThickness = lib.defaultValue(lineThickness, 0.5);
    lineColor = lib.defaultValue(lineColor, “rgba(0,246,255,1.0)”); // “#00f6ff”
    lineAlpha = lib.defaultValue(lineAlpha, 0.85);
    fillColor = lib.defaultValue(convertHex(fillColor, fillAlpha), “rgba(0,246,255,1.0)”); // “#00f6ff”
    fillColor2 = lib.defaultValue(convertHex(fillColor2, fillAlpha2), “rgba(0,246,255,1.0)”); // “#00f6ff”
    fillColor3 = lib.defaultValue(convertHex(fillColor3, fillAlpha3), “rgba(0,246,255,1.0)”); // “#00f6ff”clear && g.clear();var i = 0;
    var l = triangles.length;
    var count = 0;while(i < l) {
    var ti0 = triangles[i];
    var ti1 = triangles[i + 1];
    var ti2 = triangles[i + 2];var x0 = vertices[ti0 * 2];
    var y0 = vertices[ti0 * 2 + 1];
    var x1 = vertices[ti1 * 2];
    var y1 = vertices[ti1 * 2 + 1];
    var x2 = vertices[ti2 * 2];
    var y2 = vertices[ti2 * 2 + 1];g.setStrokeStyle(lineThickness);
    g.beginStroke(lineColor);if(count%3 ==0)
    {
    g.beginFill(fillColor);
    }
    else if(count%5 ==0)
    {
    g.beginFill(fillColor2);
    }
    else{
    g.beginFill(fillColor3);
    }g.moveTo(x0, y0);
    g.lineTo(x1, y1);
    g.lineTo(x2, y2);
    g.lineTo(x0, y0);g.endStroke();

    i+=3;
    count++;
    }

  • Helper function. To allow for opacity while still using hex add the following function to the library
  • //Added Convert To Hex Function
    function convertHex(hex,opacity){
    hex = hex.replace(‘#’,”);
    r = parseInt(hex.substring(0,2), 16);
    g = parseInt(hex.substring(2,4), 16);
    b = parseInt(hex.substring(4,6), 16);result = ‘rgba(‘+r+’,’+g+’,’+b+’,’+opacity+’)’;
    return result;
    }
  • Now when the draw triangle function is called, the colors extracted using Vibrant.js will appear on the faces of those who dare to stare.

 

PHASE 3: Creativity

With the basics in place, choose images and masks that match. You can use photoshop or any other editing tool to make your mask. For this exploration I used Fireworks.

 

Masks

mask0 mask1 mask2 mask3 mask4 mask5 mask6 maskbase

 

Inspiration Panels (Color is extracted from these photos)

0 1 2 3 4 5 6

Now that you know how to integrate BRF, VIbrant, and jQuery to create a virtual morph, it is time to move to integrate the half silvered mirror.

Connect to the monitor behind the half silvered mirror and open you index.html file in the firefox browser.

Other Explorations

  • I Attempted to integrate morph.js to have masks morph into the face of the user  based on duration of stare
  • Progress – While I didn’t get very far, I did obtain an api key from eye gaze start up , but may not go down this direction.