ICM: APIs, COFFEE, TAROT & ITP WINTER SHOW IDEAS

I was initially thinking of working with live data and played a bit with the NASA image API and my KOI-Sketch

Screen Shot 2017-10-25 at 5.05.02 AM.png

I then mapped out different possible or impossible connections of APIs.

IMG_2052.JPG

While making coffee in the morning I had the idea to use an image of the coffee ground to predict a horoscope. In the Corpora-Git I found a Tarot-JSON file that seemed perfect for that task: It had different ranks for each card with an integer value that I could map to the overall image brightness - and (not very seriously) "predict" a horoscope. I had a few issues with the JSON data, but finally managed to map all values to corresponding cards. The fortune-telling sentence then gets displayed on the screen.

Screen Shot 2017-10-25 at 1.19.22 AM.png

After finishing the code I worked on the graphics - I kept them minimal and dark to keep the "coffee feeling".

I didn't manage to automate the upload from file or getUserMedia into the browser directly. So far the images have to be placed in a folder on the server - something to work on this week.  

Screen Shot 2017-10-25 at 3.34.43 AM.png
Screen Shot 2017-10-25 at 4.42.52 AM.png

Here the code:

//not so serious coffee ground tarot engine to give you early morning joys :) 
// using these tarot explanations https://github.com/dariusk/corpora/blob/master/data/divination/tarot_interpretations.json

let myImage;
let pix;
let rank; // king: rank 25, queen: rank 24, knight: rank 23, page: rank 22;
let brightness;
let fortune_array = [];


function preload() {
  myImage = loadImage("pics/coffee.jpg");
  title = loadImage("etch.png");
  data = loadJSON("https://raw.githubusercontent.com/dariusk/corpora/master/data/divination/tarot_interpretations.json")
}

function setup() {
    createCanvas(windowWidth, windowHeight);
    push();
    imageMode(CENTER);
    translate(windowWidth / 2, windowHeight / 2);
    scale(0.8);
    image(title, 0, 0);
    pop();
    textAlign(CENTER);
    textSize(25);
    textFont("Cutive Mono");
    text("NY COFFEE GROUNDS TAROT", windowWidth/4, windowHeight/2 - myImage.height*0.1/2 - 45);
    imageMode(CENTER);
    translate(windowWidth / 2, windowHeight / 2);
    scale(0.1);
    myImage.loadPixels();
    image(myImage, 0, 0);
    //get average brightness of image and match it to card rank in tarot set;
    getImageLightness("pics/coffee.jpg",function(brightness){
        console.log("rank: " + rank); //can somehow not access "rank" as a global variable ...???
        // search as well for king, queen, knight and page ranks
        if (rank > 21){
            extra_ranks = ['page', 'knight', 'queen', 'knight'];
            rank = extra_ranks[rank - 22];
            console.log(rank);
            find_ranks(rank);
        }
        else{
            find_ranks(rank);
        }
        let fortunes = data.tarot_interpretations[rank].fortune_telling[round(random(data.tarot_interpretations[rank].fortune_telling.length -1),0)];
        console.log(fortunes);
        textAlign(CENTER);
        textSize(16);
        textFont("Cutive Mono")
        text(fortunes + ".", windowWidth/2 + 500, windowHeight/2 + myImage.height*0.1/2 + 50)
    });
    let fortunes = data.tarot_interpretations[0].fortune_telling[0];
}

// function taken from https://stackoverflow.com/questions/13762864/image-dark-light-detection-client-sided-script
// converts each color to gray scale and returns average of all pixels
// brightness: 0 (darkest) and 255 (brightest)
function getImageLightness(imageSrc,callback) {
    img = document.createElement("img");
    img.src = imageSrc;
    img.style.display = "none";
    document.body.appendChild(img);

    let colorSum = 0;

    img.onload = function() {
        // create canvas
        let canvas = document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        let ctx = canvas.getContext("2d");
        ctx.drawImage(this,0,0);

        let imageData = ctx.getImageData(0,0,canvas.width,canvas.height);
        let data = imageData.data;
        let r,g,b,avg;

        for(let x = 0, len = data.length; x < len; x+=4) {// noprotect.
            r = data[x];
            g = data[x+1];
            b = data[x+2];

            avg = Math.floor((r+g+b)/3);
            colorSum += avg;
        }

        brightness = Math.floor(colorSum / (this.width*this.height));
        // map & round brightness to 0 - 10 value of Tarot cards
        brightness = round(brightness.map(0, 255, 0, 25), 0);
        console.log(brightness)
        rank = brightness;
        callback(brightness, rank);

    }
}

// map 0 - 255 average brightness values to 0 - 10 Tarot card ranks
// (taken from https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers)
Number.prototype.map = function (in_min, in_max, out_min, out_max) {
  return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// round values
// (taken from http://www.jacklmoore.com/notes/rounding-in-javascript/)
function round(value, decimals) {
  return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}

// append all entries into array for ranks
// (not taken from anywhere ;) 
function find_ranks(key){
    for(i = 0; i < data.tarot_interpretations.length; i++) {
        if (data.tarot_interpretations[i].rank == key){
            console.log('found matching rank in array ' + i);
            fortune_array.push(i);
        }
    }
    console.log('found matching rank in arrays ' + fortune_array)
    rank = fortune_array[round((random(fortune_array.length -1)),0)];
    console.log('selected rank in array ' + rank)
}

// go fullscreen and resize if necessary
function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

For the winter show I would like to keep working on the KOI. I have two things in my mind: 

1. Users load the KOI sketch on their phones, the little fish is swimming on their phone. Then they put their phone on little floats in a little pond filled with water - the KOIs will all be "swimming" in their screens on the surface of the pond. A swarm of floating phone-KOIs. 

2. The KOIs can cross different screens, the more users align their phone screens on a table, the bigger the virtual pond of the KOI gets. It can cross between the aligned phones. 

IMG_2053.JPG
IMG_2054.JPG

So much for the initial rough ideas - let's see how these develop over the next two months.