Sunday 24 August 2014

Augmented Reality

It has been a long time i didn't update my blog. I've done some big and small project between this periods and i gonna post it here gradually :)


Today I'm gonna share about a image processing applications. This is one of my assignment during my diploma studies. I'm using Processing to write this application and most of the codes are referring from this website. I just do some modifications on the code, add more features, and implement it with the live camera view. You will need to download the NyArtoolkit and also GsVideo for Processing to perform this function.

The original code should display the cube on the markers detected in the live camera. I modified the program to recognized few markers and display different patterns on each of it at one time.  If you wish to displace more and different pattern you just need to Google for different pattern or shape code and put it into the Processing. Also, in this Augmented reality application, I added few rows of codes so that i can edit the scales of the pattern shown in the screen in the live camera. 

Below are the code i'm using for this application with the demo video:


// Processing + NyARToolkit + GSVideo = Argumeneted reality
 
import java.io.*; // for the loadPatternFilenames() function
import processing.opengl.*; // for OPENGL rendering
import jp.nyatla.nyar4psg.*; // the NyARToolkit Processing library
import codeanticode.gsvideo.*; // the GSVideo library
 
// the full path to the camera_para.dat file
String camPara = "C:/Users/kit/Documents/Processing/libraries/nyar4psg/data/camera_para.dat";
// the full path to the .patt pattern files
String patternPath = "C:/Users/kit/Documents/Processing/libraries/nyar4psg/patternMaker/examples/ARToolKit_Patterns";
// the dimensions at which the AR will take place.
int arWidth = 640;
int arHeight = 360;
// the number of pattern markers (from the complete list of .patt files) that will be detected, here the first 10 from the list.
int numMarkers = 10;
float scales = 1.0;
float mS = 0.2;
 
GSCapture cam;
MultiMarker nya;
float[] scaler = new float[numMarkers];
color[] colors = new color[numMarkers];
PVector rot, speed; 

void setup() {
  size(1280, 720, OPENGL); // the sketch size
  cam = new GSCapture(this, 1280, 720); // initializing the webcam capture at a specific resolution 
  cam.start(); // start capturing
  noStroke(); // turn off stroke for the rest of this sketch
  // create a new MultiMarker at a specific resolution (arWidth x arHeight), with the default camera calibration and coordinate system
  nya = new MultiMarker(this, arWidth, arHeight, camPara, NyAR4PsgConfig.CONFIG_DEFAULT);
  // set the delay after which a lost marker is no longer displayed. by default set to something higher, but here manually set to immediate.
  nya.setLostDelay(1);
  String[] patterns = loadPatternFilenames(patternPath);
  rot = new PVector(random(TWO_PI), random(TWO_PI), random(TWO_PI)); // random x, y, z rotation
  speed = new PVector(random(-mS, mS), random(-mS, mS), random(-mS, mS)); // random x, y, z speed (within maxSpeed boundaries)
  // for the selected number of markers, add the marker for detection
  for (int i=0; i<numMarkers; i++) {
    nya.addARMarker(patternPath + "/" + patterns[i], 80);
    scaler[i] = random(0.8, 1.9); // scaled a little smaller or bigger
    colors[i] = color(random(255), random(255), random(255), 160); // random color, always at a transparency of 160
   
  }
}
 
void draw() {
  if (cam.available()) {
    cam.read();
    background(cam); // a background call is needed for correct display of the marker results
    // create a copy of the cam image at the resolution of the AR detection to avoid error
    PImage cSmall = cam.get();
    cSmall.resize(arWidth, arHeight);
    nya.detect(cSmall); // detect markers in the image
    
   drawShapes();
   println("Scale : " + scales);
  }
}


 
// this function draws correctly placed 3D boxes on top of detected markers
void drawShapes() {
  // set the AR perspective uniformly, this general point-of-view is the same for all markers
  nya.setARPerspective();
  // set the text alignment (full centered) and size (big)
  textAlign(CENTER, CENTER);
  textSize(20);

  for (int i=0; i<numMarkers; i++) {
    // checking exist marker
    if ((!nya.isExistMarker(i))) { continue; }
    
    if(i==0) //MARKER NUMBER 0
    {
    // get the Matrix for this marker and use it (through setMatrix)
    setMatrix(nya.getMarkerMatrix(i));
    scale(1, -1); // turn things upside down, for text display
    scale(scales); //decide the size of the boxes
    translate(0, 0, 20); // translate the box by half (20, draw frm marker) of it's size (40,draw in air)
    //move up 20 from the base marker
    lights(); // turn on some lights,makes the box color nicer
    stroke(0); // give the box a black stroke/line
    fill(colors[i]); // fill color
    box(40); // the box
    noLights(); // turn off the lights
    translate(0, 0, 20.1); // translate to just slightly above the box (to prevent OPENGL uglyness)
    noStroke(); 
    fill(255, 50);
    rect(-20, -20, 40, 40); // display a transparent white rectangle right above the box
    translate(0, 0, 0.1); // translate to just slightly above the rectangle (to prevent OPENGL uglyness)
    fill(0);
    text("" + i, -20, -20, 40, 40); // display the ID of the box in black text centered in the rectangle
    }
    
    if (i == 3) //MARKER NUMBER 3
    {
     // get the Matrix for this marker and use it (through setMatrix)
    setMatrix(nya.getMarkerMatrix(i));
    scale(scales); //decide the size of the boxes
    translate(0, 0, 20); // translate the sphere by half (20, draw frm marker) of it's size (40,draw in air)
    //move up 20 from the base marker
    lights(); // turn on some lights,makes the box color nicer
    stroke(colors[i]); //no line needed
    fill(255,160); // fill color
    sphere(20); // the box
    //noStroke(); 
    }
    
     if (i == 5) //MARKER NUMBER 5
    { 
     colorMode(RGB, 1); //set color mode to 1 only for easy fill color for the matrix
     rot.add(speed); // always keep rotating
     // get the Matrix for this marker and use it (through setMatrix)
    setMatrix(nya.getMarkerMatrix(i));
    translate(0, 0, 30); // translate the sphere by half (20, draw frm marker) of it's size (40,draw in air)
    // rotate the cube in 3 dimensions
    rotateX(rot.x);
    rotateY(rot.y);
    rotateZ(rot.z);
    scale(scales*10);
 
    // a cube made out of 6 quads
    // the 1 range can be used for both the color and the coordinates as a result of color range and scale (see earlier)
    beginShape(QUADS);
 
    fill(0, 1, 1); vertex(-1,  1,  1);
    fill(1, 1, 1); vertex( 1,  1,  1);
    fill(1, 0, 1); vertex( 1, -1,  1);
    fill(0, 0, 1); vertex(-1, -1,  1);
  
    fill(1, 1, 1); vertex( 1,  1,  1);
    fill(1, 1, 0); vertex( 1,  1, -1);
    fill(1, 0, 0); vertex( 1, -1, -1);
    fill(1, 0, 1); vertex( 1, -1,  1);
 
    fill(1, 1, 0); vertex( 1,  1, -1);
    fill(0, 1, 0); vertex(-1,  1, -1);
    fill(0, 0, 0); vertex(-1, -1, -1);
    fill(1, 0, 0); vertex( 1, -1, -1);
 
    fill(0, 1, 0); vertex(-1,  1, -1);
    fill(0, 1, 1); vertex(-1,  1,  1);
    fill(0, 0, 1); vertex(-1, -1,  1);
    fill(0, 0, 0); vertex(-1, -1, -1);
 
    fill(0, 1, 0); vertex(-1,  1, -1);
    fill(1, 1, 0); vertex( 1,  1, -1);
    fill(1, 1, 1); vertex( 1,  1,  1);
    fill(0, 1, 1); vertex(-1,  1,  1);
 
    fill(0, 0, 0); vertex(-1, -1, -1);
    fill(1, 0, 0); vertex( 1, -1, -1);
    fill(1, 0, 1); vertex( 1, -1,  1);
    fill(0, 0, 1); vertex(-1, -1,  1);
 
    endShape();
    colorMode(RGB, 255);
    }
  }
  // reset to the default perspective
  perspective();
}
// this function loads .patt filenames into a list of Strings based on a full path to a directory (relies on java.io)
String[] loadPatternFilenames(String path) {
  File folder = new File(path);
  FilenameFilter pattFilter = new FilenameFilter() {
    public boolean accept(File dir, String name) {
      return name.toLowerCase().endsWith(".patt");
    }
  };
  return folder.list(pattFilter);
}


void keyPressed() {
  if (key == 'z' && scales < 2.0) {
   // scales = 1.5;
   scales = scales + 0.1;
  }
  else if(key == 'x' && scales > 0.7) {
    scales = scales -0.1;
    //scales = 0.8;
  }
}