h.A.I.rstyling::::::::::::trust the machine



Final project for Learning bit by bit. Made with Cyrus von Hochstetter
We assemble data of great haircuts from the Internet and we used this data to create automated recommendations for customers according their sex, face shape, hair type, hair length, age and style.

On Sunday, 1st of May we went out to Washington Square Park and carried out the project. People were very curious about our artificial hairstyling system, and – surprisingly – they were excited about getting a free haircut.





We used the following processing code to generate the suitable hairstyle for the consumer:

import java.util.Collections;

PFont f;
PImage instructions;

PImage[] frizurs = new PImage[0];
PImage frizur;

Persona newCustomer;
ArrayList models = new ArrayList();
ArrayList suggestionArray = new ArrayList();

String typing="";
String typing2="";

boolean entered = false;
boolean entered2 = false;

boolean keyWasReleased = true;
boolean suggestionArrayCreated = false;
boolean modelsSelected = false;
boolean imgLoaded = false;
boolean state = false;
boolean finalState = false;

/////////////////////////////////// for fine tuning
int tolerance =1;

void setup() {

  size(1200,1200);
  smooth();
  instructions = loadImage("instructions.png");
  generateModels();
}

void draw() {
  if (!entered) {
    createNewCustomer();
  }

  else {
    if (modelsSelected == false) {
      compareSex();
      compareHairType();
      compareLength();
      compareHairThickness(tolerance);
      compareFaceShape(tolerance);
      compareAge(2*tolerance);
      modelsSelected = true;
    }

    if (suggestionArrayCreated == false) {
      createSuggestionArray();
    }

    if (imgLoaded == false) {
      loadImages();
      displayImages();
    }

    if (finalState == false){

      showFinalSelection();

    }
  }
}

void createNewCustomer() {

  int askedSex;
  int askedFaceShape;
  int askedHairType;
  int askedHairThickness;
  int askedAge;
  int askedLength;
  int[] userInput;

  background(255);
  fill(0);

  text("enter values seperated by commas:", 50,50);
  text(typing,50,100);

  image(instructions,200,300,800,150);

  if (keyPressed) {
    if (key  == '\n') {

      userInput = int(split(typing, ','));
      newCustomer = new Persona(userInput);

      String[] input = split(typing, ','); 

      if (!input[6].equals("test")){
        String[] toSave = loadReadyCustomers();
        toSave = (String[]) append(toSave, typing);
        saveStrings("data/customers.txt", toSave);
      }

      entered = true;
    }

    else if(key == '\b' && typing.length() > 0 && keyWasReleased) {
      typing = typing.substring(0, typing.length()-1);
      keyWasReleased = false;
    }
    else if (keyWasReleased) {
      typing = typing + key;
      keyWasReleased = false;
    }
  }
  //state++;
}

void keyReleased() {
  keyWasReleased = true;
}

void userSelect() {
  background(255);
  fill(120);
  textAlign(RIGHT);
  text("Sex:",120,140);
  text("Faceshape:",120,240);
  text("Hair Type:",120,340);
  text("Hair Texture:",120,440);
  text("Age:",120,540);
  text("Current Hair Length",120,640);
  rectMode(CENTER);
  rect(300,140,50,50);
  rect(300,140,50,50);
}

void createSuggestionArray() {
  //println("suggestionarray");
  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);
    if(m.removed == false) {
      suggestionArray.add(new Suggestions(m.id, m.sex, m.faceShape, m.hairType, m.hairThickness, m.age, m.hairLength, m.style));
      //println("no of model: " + m.id);
      //println("one added");
    }
  }

  /*
   for(int i=0; i<suggestionArray.size(); i++){
   Suggestions mm = (Suggestions) suggestionArray.get(i);
   println(mm.id);
   }
   */
  Collections.shuffle(suggestionArray);
  //println(suggestionArray.size());
  suggestionArrayCreated = true;
}

void loadImages() {
  int count;

  if (suggestionArray.size() > 3) {
    count = 3;
  }
  else {
    count = suggestionArray.size();
  }
  for (int i = 0; i<count; i++) {

    Suggestions m = (Suggestions) suggestionArray.get(i);

    String f = m.id + ".jpg";
    println(f);
    frizur = loadImage(f);

    frizurs = (PImage[]) append(frizurs, frizur);
  }
  // println("suggested ID is: " + f);

  println("frizur img array length: " + frizurs.length);
  imgLoaded = true;
  println("total # of suggestions: " + suggestionArray.size());
}

void displayImages() {
  background(255);
  for (int i = 0; i < frizurs.length; i++) {
    image(frizurs[i],300,100+300*i);
  }
}

void generateModels() {

  String[] modelLines = loadStrings("models.txt");
  int[] modelInput = new int[modelLines.length];

  for (int i = 0; i < modelLines.length; i++) {
    modelInput = int(split(modelLines[i], ','));

    models.add(new Model(modelInput));
  }
}

String[] loadReadyCustomers(){
    String[] readyCustomers = loadStrings("data/customers.txt");
    return readyCustomers;
}

void showFinalSelection(){
 imgLoaded = true;

  text("choose your final model:", 50,50);

  text(typing2,50,100);

  int finalChoise = 0;

  if (keyPressed) {
      if (key  == '\n') {

        finalChoise = int(typing2);

        entered2 = true;
      }

      else if(key == '\b' &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; typing.length() > 0 &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; keyWasReleased) {
        typing2 = typing2.substring(0, typing2.length()-1);
        keyWasReleased = false;
      }
      else if (keyWasReleased) {
        typing2 = typing2 + key;
        keyWasReleased = false;
      }
    }

    if (finalChoise < 4 &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; finalChoise > 0){
      image(frizurs[finalChoise-1],width/2-100, height/2-100);
      text("Thank you for choosing hA.I.rsytling. Please be patient until your hair is ready.", width/2-100,height/2+100);
    }
 }

class Persona {

  int sex;
  int faceShape;
  int hairType;
  int hairThickness;
  int age;
  int hairLength;
  int style;

  Persona(int[] input) {
    //id = input[0];
    sex = input[0];
    faceShape = input[1];
    hairType = input[2];
    hairThickness = input[3];
    age = input[4];
    hairLength = input[5];
  }

}

void compareSex() {
  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);

    if (m.sex != newCustomer.sex) {
      m.removed = true;
    }
  }
}

void compareHairType() {
  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);

    if (m.hairType != newCustomer.hairType) {
      m.removed = true;
    }
  }
}

void compareLength() {
  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);

    if (m.hairLength > newCustomer.hairLength) {
      m.removed = true;
    }
  }
}

void compareHairThickness(int interval) {
  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);

    if (m.hairThickness > newCustomer.hairThickness+interval || m.hairThickness < newCustomer.hairThickness-interval) {
      m.removed = true;
    }
  }
}

void compareFaceShape(int interval) {
  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);

    if (m.faceShape > newCustomer.faceShape+interval || m.faceShape < newCustomer.faceShape-interval) {
      m.removed = true;
    }
  }
}

void compareAge(int interval) {

  for (int i=0; i<models.size(); i++) {
    Model m = (Model) models.get(i);

    if (m.age > newCustomer.age+interval || m.age < newCustomer.age-interval) {
      m.removed = true;
    }
  }
}

void displayPerson() {
  int ypos = 100;
  int yposplus = 130;
  background(255);
  fill(255,0,0);
  text("cust:",10,10);
  text(newCustomer.sex,60,10);
  text(newCustomer.faceShape,110,10);
  text(newCustomer.hairType,160,10);
  text(newCustomer.hairThickness,210,10);
  text(newCustomer.age,260,10);
  text(newCustomer.hairLength,310,10);
  text(newCustomer.style,360,10);

  fill(0);
  text("#",10,50+ypos);
  text("sex:",60,50+ypos);
  text("fs",110,50+ypos);
  text("ht",160,50+ypos);
  text("hTh",210,50+ypos);
  text("age",260,50+ypos);
  text("length",310,50+ypos);
  text("style",360,50+ypos);

  for (int i=0; i<3; i++) {
    //println(i);
    Suggestions m = (Suggestions) suggestionArray.get(i);

    text(m.id,10,50+yposplus*i);
    text(m.sex,60,50+yposplus*i);
    text(m.faceShape,110,50+yposplus*i);
    text(m.hairType,160,50+yposplus*i);
    text(m.hairThickness,210,50+yposplus*i);
    text(m.age,260,50+yposplus*i);
    text(m.hairLength,310,50+yposplus*i);
    text(m.style,360,50+yposplus*i);
  }
}