Final README.
This should include a summary of all of the work leading up to the final version (which I am omitting in this example), so it should be longer than the other READMEs.
In my final version I have used a shifted grid layout with some jitter.
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/addons/p5.dom.js"></script>
<script src="z_clmtrackr.js"></script>
<script src="z_model_pca_20_svm.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.0/seedrandom.min.js"></script>
<script src="https://d3js.org/d3-random.v1.min.js"></script>
<script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
<script language="javascript" type="text/javascript" src=".focused_random.js"></script>
<script language="javascript" type="text/javascript" src="face.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<style>
body { padding: 0; margin: 0; }
.inner { position: absolute; }
#controls {
font: 300 12px "Helvetica Neue";
padding: 5;
margin: 5;
background: #f0f0f0;
opacity: 0.0;
-webkit-transition: opacity 0.2s ease;
-moz-transition: opacity 0.2s ease;
-o-transition: opacity 0.2s ease;
-ms-transition: opacity 0.2s ease;
}
#controls:hover { opacity: 0.9; }
</style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
<div class="inner" id="controls" height="500px">
<table>
<tr>
<td>Draw function</td>
<td id="selector1Container"></td>
</tr>
</table>
</div>
</div>
</table>
</body>
/*
* Face class - holds all informaiton about one face
*/
function Face() {
// these are state variables for a face
// (your variables may be different)
this.tilt_value = 0;
this.eye_value = 2;
this.mouth_value = 0;
// other variables can be in here too
// these control the colors used
this.bg_color = [225, 206, 187];
this.fg_color = [151, 102, 52];
this.stroke_color = [95, 52, 8];
/*
* Draw a face centered at x,y with an allowed
* width and height of w,h.
*/
this.draw1 = function(x, y, w, h) {
// Uncomment to see drawing area
// fill(255);
// stroke(0);
// rect(x-w/2, y-h/2, w, h);
// fill(0)
// ellipse(x, y, w, h);
push();
translate(x, y);
rotate(this.tilt_value);
var extent = 0;
if(h < w) {
extent = h / 2;
}
else {
extent = w / 2;
}
var scale = extent / 220.0;
// head
stroke(this.stroke_color);
fill(this.fg_color);
ellipse(0, 0, 300 * scale, 400 * scale);
noStroke();
// eyes
if (this.eye_value === 1 || this.eye_value == 3) {
fill(this.bg_color);
ellipse( 0, -80 * scale, 50 * scale, 30 * scale);
fill(this.fg_color);
ellipse(-10 * scale, -80 * scale, 20 * scale, 20 * scale);
}
if (this.eye_value >= 2) {
fill(this.bg_color);
ellipse(-50 * scale, -80 * scale, 50 * scale, 30 * scale);
ellipse( 50 * scale, -80 * scale, 50 * scale, 30 * scale);
fill(this.fg_color);
ellipse(-60 * scale, -80 * scale, 20 * scale, 20 * scale);
ellipse( 40 * scale, -80 * scale, 20 * scale, 20 * scale);
}
// mouth
fill(this.bg_color);
ellipse(0 * scale, 70 * scale, 150 * scale, this.mouth_value * scale);
pop();
}
/*
* Draw a face with position lists that include:
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow
* bottom_lip, top_lip, nose_tip, nose_bridge,
*/
this.draw2 = function(positions) {
var nose_pos = average_point(positions.nose_bridge);
var eye1_pos = average_point(positions.left_eye);
var eye2_pos = average_point(positions.right_eye);
var half_height = positions.chin[7][1] - nose_pos[1];
var face_width = positions.chin[positions.chin.length-1][0] - positions.chin[0][0];
var x = nose_pos[0];
var y = nose_pos[1];
var w = 2 * face_width;
var h = 2.5 * half_height;
var extent = 0;
if(h < w) {
extent = h / 2;
}
else {
extent = w / 2;
}
var scale = extent / 220.0;
// Uncomment to see drawing area
// fill(255);
// stroke(0);
// rect(x-w/2, y-h/2, w, h);
// fill(0)
// ellipse(x, y, w, h);
push();
translate(x, y);
rotate(this.tilt_value);
// head
stroke(this.stroke_color);
fill(this.fg_color);
ellipse(0, 0, 300 * scale, 400 * scale);
noStroke();
// mouth
fill(this.bg_color);
ellipse(0 * scale, 70 * scale, 150 * scale, this.mouth_value * scale);
pop();
noStroke();
fill(this.bg_color);
ellipse(eye1_pos[0], eye1_pos[1], 50 * scale, 30 * scale);
ellipse(eye2_pos[0], eye2_pos[1], 50 * scale, 30 * scale);
fill(this.fg_color);
ellipse(eye1_pos[0], eye1_pos[1], 20 * scale, 20 * scale);
ellipse(eye2_pos[0], eye2_pos[1], 20 * scale, 20 * scale);
}
/*
* Update internal state variables to a random state.
*/
this.randomize = function(values, size) {
this.eye_value = getRandomNumberOfEyes();
this.tilt_value = focusedRandom(-70, 90, 8);
this.mouth_value = focusedRandom(0, 50, 4, 1);
}
}
// global functions can also be in this file below
function getRandomNumberOfEyes() {
random_result = focusedRandom(0, 100);
if(random_result < 8) {
return 1;
}
else if(random_result < 12) {
return 3;
}
else {
return 2;
}
}
// given a point, return the average
function average_point(list) {
var sum_x = 0;
var sum_y = 0;
var num_points = 0;
for(var i=0; i<list.length; i++) {
sum_x += list[i][0];
sum_y += list[i][1];
num_points += 1;
}
return [sum_x / num_points, sum_y / num_points];
}
var canvasWidth = 960;
var canvasHeight = 500;
var button;
var curRandomSeed;
var mainFace;
var faceImages = [];
var curFaceIndex = 0;
var main_canvas;
var faceSelector;
var facelist = [];
var NUMFACES = 6*9;
var faceData = [
{
"url": "z_face1.jpg",
"embedding": [null],
"landmarks": [
{
"bottom_lip":
[[219, 206], [208, 221], [194, 226], [185, 227], [175, 227], [164, 221], [154, 208], [158, 209], [176, 218], [185, 219], [194, 218], [217, 207]],
"nose_tip":
[[169, 189], [176, 191], [184, 192], [191, 190], [200, 189]],
"nose_bridge":
[[183, 141], [183, 154], [183, 167], [183, 180]],
"top_lip":
[[154, 208], [165, 205], [176, 202], [185, 204], [193, 202], [207, 204], [219, 206], [217, 207], [193, 208], [185, 210], [176, 209], [158, 209]],
"right_eyebrow":
[[195, 125], [208, 120], [222, 119], [235, 122], [245, 131]],
"left_eye":
[[144, 143], [151, 139], [159, 139], [166, 146], [159, 147], [150, 146]],
"left_eyebrow":
[[131, 132], [138, 123], [149, 120], [161, 121], [172, 125]],
"chin":
[[122, 151], [121, 168], [123, 185], [127, 202], [133, 219], [143, 233], [154, 247], [167, 258], [185, 262], [203, 259], [221, 251], [237, 238], [250, 224], [256, 207], [259, 189], [261, 170], [261, 152]],
"right_eye":
[[205, 146], [212, 139], [221, 138], [228, 143], [221, 145], [212, 146]]
}
]
},
{
"url": "z_face2.jpg",
"embedding": [null],
"landmarks": [
{"nose_tip": [[258, 199], [266, 200], [274, 201], [282, 199], [289, 197]], "left_eye": [[216, 159], [226, 152], [239, 152], [250, 161], [239, 164], [225, 164]], "right_eyebrow": [[286, 130], [300, 123], [315, 121], [330, 125], [338, 137]], "right_eye": [[291, 159], [300, 148], [313, 147], [323, 154], [315, 160], [302, 161]], "left_eyebrow": [[197, 144], [206, 132], [221, 126], [237, 127], [253, 131]], "bottom_lip": [[310, 217], [297, 229], [286, 234], [277, 235], [268, 235], [255, 232], [239, 221], [245, 222], [268, 225], [276, 226], [285, 224], [304, 218]], "chin": [[185, 160], [189, 180], [194, 199], [200, 216], [209, 233], [222, 246], [238, 257], [256, 265], [276, 267], [295, 263], [311, 252], [325, 240], [336, 226], [343, 209], [345, 190], [346, 172], [347, 153]], "nose_bridge": [[271, 152], [272, 164], [273, 175], [274, 186]], "top_lip": [[239, 221], [255, 218], [268, 215], [276, 216], [284, 214], [296, 216], [310, 217], [304, 218], [284, 220], [276, 221], [268, 221], [245, 222]]}
]
},
{
"url": "z_face3.jpg",
"embedding": [null],
"landmarks": [
{"bottom_lip": [[253, 150], [244, 153], [237, 153], [232, 152], [228, 150], [224, 147], [221, 142], [224, 142], [230, 144], [234, 146], [238, 146], [250, 149]], "nose_tip": [[231, 128], [234, 131], [237, 133], [242, 133], [246, 132]], "top_lip": [[221, 142], [226, 139], [232, 139], [235, 141], [240, 141], [246, 145], [253, 150], [250, 149], [239, 146], [235, 145], [231, 144], [224, 142]], "left_eye": [[221, 97], [226, 95], [232, 96], [236, 102], [231, 102], [225, 101]], "right_eye": [[258, 107], [264, 104], [271, 105], [275, 110], [270, 111], [263, 110]], "right_eyebrow": [[255, 94], [264, 92], [272, 93], [281, 96], [287, 101]], "chin": [[209, 96], [206, 107], [205, 118], [204, 129], [205, 140], [208, 150], [214, 159], [220, 167], [231, 172], [243, 173], [257, 171], [270, 166], [281, 160], [288, 151], [293, 139], [297, 128], [300, 116]], "left_eyebrow": [[215, 86], [221, 84], [228, 85], [235, 87], [241, 92]], "nose_bridge": [[245, 102], [243, 109], [240, 117], [238, 124]]}
]
}
]
var faceMapping = null;
function preload () {
if (faceData == null) {
faceData = loadJSON('face_data.json');
}
}
function setup () {
// create the drawing canvas, save the canvas element
main_canvas = createCanvas(canvasWidth, canvasHeight);
main_canvas.parent('canvasContainer');
curRandomSeed = int(focusedRandom(0, 100));
for(var i=0; i<NUMFACES; i++) {
var face = new Face();
facelist.push(face);
}
mainFace = new Face();
for(var i=0; i<faceData.length; i++) {
var data = faceData[i];
data.image = loadImage(data.url)
}
faceSelector = createSelect();
faceSelector.option('draw1');
faceSelector.option('draw2');
faceSelector.value('draw1');
faceSelector.parent('selector1Container');
// rotation in degrees
angleMode(DEGREES);
}
// global variables for colors
var bg_color1 = [225, 206, 187];
var lastSwapTime = 0;
var millisPerSwap = 5000;
function changeRandomSeed() {
curRandomSeed = curRandomSeed + 1;
lastSwapTime = millis();
}
function mouseClicked() {
changeRandomSeed();
}
function draw () {
var data = faceData[curFaceIndex];
var mode = faceSelector.value();
if(millis() > lastSwapTime + millisPerSwap) {
lastSwapTime = millis();
// changeRandomSeed();
}
resetFocusedRandom(curRandomSeed);
noStroke();
background(bg_color1);
if (mode == 'draw1') {
var w = canvasWidth / 10;
var h = canvasHeight / 6;
var max_shift = 0.2 * w;
var cur_face = 0;
for(var i=0; i<6; i++) {
for(var j=0; j<9; j++) {
var face = facelist[cur_face];
cur_face = cur_face + 1;
var y = h/2 + h*i;
var x = w/2 + w*j;
// shift even rows over by half a face
if(i%2 == 0) {
x = x + w/2;
}
// noFill();
// stroke(255, 0, 0);
// rect(x-w/2, y-w/2, w, h);
face.randomize();
face.draw1(x, y, w, h);
// noStroke();
// fill(255, 0, 0);
// ellipse(x-2, y-2, 4, 4);
}
}
}
else {
// Displays the image at its actual size at point (0,0)
var img = data.image
var x1 = (width/4-400/2);
var x2 = (3*width/4-400/2);
var y1 = (height/2-400/2);
image(img, x1, y1);
image(img, x2, y1);
// get array of face marker positions [x, y] format
var positions = data.landmarks[0];
var shifted_positions = JSON.parse(JSON.stringify(positions))
noFill();
stroke(0);
Object.keys(positions).forEach(function(key) {
var curSection = positions[key];
var shiftedSection = shifted_positions[key];
for (var i=0; i<curSection.length; i++) {
ellipse(x1+curSection[i][0], y1+curSection[i][1], 4, 4);
// get ready for drawing the face
shiftedSection[i][0] = curSection[i][0] + x2;
shiftedSection[i][1] = curSection[i][1] + y1;
}
});
mainFace.randomize();
mainFace.draw2(shifted_positions);
}
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
}
function keyPressed() {
if (keyCode === LEFT_ARROW) {
curFaceIndex = (curFaceIndex + faceData.length - 1) % faceData.length;
} else if (keyCode === RIGHT_ARROW) {
curFaceIndex = (curFaceIndex + 1) % faceData.length;
}
}