martes, 10 de julio de 2012

ofxKinect; profundidad hue


Este también es el resultado de varias investigaciones...
Líneas y hue en profundidad.
No es algo terminado sino también un escalón en donde me paro para alcanzar el próximo.

ofxKinect + sonidos


Reemplacé los puntos por círculos de diferentes radios y colores según el valor de profundidad.
También agregué líneas verticales.
Estoy trabajando en activar y desactivar zonas (cubos) para que al "entrar" en ellas disparen sonidos. WORK IN PROGRESS...

ofxKinect; distancia cerca y lejos


Para determinar el ancho de la profundidad que quiero que kinect lea utilizo
kinect.getDistanceAt(x, y): este es el valor de z
Esta función calcula la profundidad del pixel x, y

Si bien las distancias son aproximadas podemos decir que 1000 corresponde a 1mt.
En este ejemplo acoté la lectura de profundidad entre 1000 y 1500.

if((kinect.getDistanceAt(x, y) > 1000) && (kinect.getDistanceAt(x, y) < 1500){  }

ofxKinect + ofMesh


Estos ejemplos de kinect siempre utilizan el ofMesh.
"Mesh" significa malla, esto permite generar una malla y vincular de forma simple los vértices (ofVertex) que la componen.
En este caso uní con en líneas horizontales los vértices que kinect detecta.

mesh.setMode(OF_PRIMITIVE_LINE_STRIP);

También aplico la variación de color en hue.

ofxKinect + hue


En cada iteración los píxeles van cambiando de color según el aumento del valor en color hue

testApp :: setup
float hue = 0;

testApp :: draw
 hue += 0.1;
 col.setHsb(hue, 255, 255);
 ofSetColor(col);

ofxKinect + png


En este caso estoy "pintando" los pixeles en Z con un archivo .png
Cada pixel de este archivo reemplada a los colores de los pixeles de la webcam.
Los píxeles alfa se mantienen transparentes... interesante!
No debemos olvidar habilitar la función del canal alfa en el setup del testApp
ofEnableAlphaBlending();

ofxKinect + jpg


En este caso estoy "pintando" los pixeles en Z con un archivo .jpg
Cada pixel de este archivo reemplada a los colores de los pixeles de la webcam.

ofxKinect


Aquí tengo limitada la "visión" de la cámara infraroja de profundidad.
La aplicación solo lee entre 0.5mts y 2,3mts. Estos valores pueden modificarse según la necesidad.

Para construir la imagen final toma el color del pixel de la webcam y lo imprime en Z según la profundidad del mismo pixel correspondiente a la cámara infraroja.

ofEasyCam ayuda a completar la ilusión del 3D virtual

"Espacialidad del sonido - 03"


Aquí tenemos el proyecto terminado en acción.
La música es "El carnavalito del duende" (interpretación: Federico Bardotti Banda).

Nota: el rendimiento no es bueno porque estoy capturando las imágenes en la misma computadora que corre la aplicación.

Espacialidad del sonido - terminado


Aquí uní tres proyectos...
Los círculos y el sistema de partículas en 3D son agitados y generados por la interactividad en la amplitud del sonido através del micrófono en tiempo real.
La rotación de los ejes están programadas y también pueden alterarse con el mouse (ofEasyCam).

Nota: el rendimiento no es bueno porque estoy capturando las imágenes en la misma computadora que corre la aplicación.

ofSoundStream + fórmula del círculo + interactivo


Si pude dibujar un línea en el plano y disponemos también del eje Z...
¿por qué no hacerla un círculo en Z y en Y?

for (float i = 0; i < ((pi*2)*10); i+= 1.04){
     coseno=cos(i);
     seno=sin(i);
     ofPoint setVertex(coseno * radio, y -left[i]*180.0f, seno * radio);
     ofVertex( setVertex );
   }

((pi*2: para completar la circunferencia)*10): para que de 10 vueltas
 i+= 1.04: 1.04 es el resultado de 2pi/6 (para hacer el hexágono)
                                                   2pi/5 (para el pentágono)
                                                   2pi/4 (para el cuadrado)
                                                   2pi/3 (para el triángulo)
ofPoint: aplico los valores en x, y, z
left[i]: es el vector en donde voy guardando el audio que entra por el micrófono

ofSoundStream * y + interactivo


No tiene mucha diferencia con la entrada anterior, sólo que la línea está multiplicada en y dentro de un for salteando de a 50.
También tiene ofEasyCam para hacer el movimiento de cámara.

ofSoundStream + interactivo


ofSoundStream soundStream; // a la variable soundStream le aplico el formato de ofSoundStrem

soundStream.listDevices(); // hace una lista de todos los dispositivos que dispone la computadora

soundStream.setDeviceID(3); // en mi caso el micrófono es el n° 3.

soundStream.setup(this, 0, 2, 44100, 512, 4);
                              // 0: cantidad de canales de salida
                              // 2: cantidad de canales de entrada
                              // 44100: sample rate
                              // 512: buffer size
                              // 4: n buffer

La líneas está dibujada con ofVertex.

lunes, 9 de julio de 2012

3D Sistema de partículas



int cruz = 30; // largo de la mitad de los lados de la cruz
int x = ofGetWidth()/2;
int y = ofGetHeight()/2;

ofSetLineWidth(1);
ofSetColor(255, 0, 0); // color de la línea en x
ofLine(x - cruz, y, 0, x + cruz, y, 0); // línea en x
ofSetColor(0, 255, 0); // color de la línea en y
ofLine(x, y - cruz, 0, x, y + cruz, 0); // línea en y
ofSetColor(0, 0, 255);  // color de la línea en z
ofLine(x, y, - cruz, x, y, cruz); // línea en z


agregar los valores en z
 p.pos.z = 0;    // z del origen de la instancia en 0
 p.vel.z = ofRandom(-1.0, 1.0); // velocidad en z

para dibujar necesitamos una esfera y no un círculo
 ofSphere(pos.x, pos.y, pos.z, radio);


Sistema de partículas (más partículas)


En cada iteración se originan 10 instancias del objeto

SistemadeParticula ps;

for(int i = 0; i < 10; i++) {
  sp.addParticula(0, 0);
 }

sp es el padre de quien las instancias heredan sus características

void SistemadeParticulas :: addParticula (float x, float y){ // como en el ejemplo anterior
origen x, y
velocidad x, y
radio
vida
}

Sistema de partículas (color)


Sólo tripliqué la cantidad de instancias que en el ejemplo anterior

ofColor col; // col es la variable formateada por ofColor en donde voy a guardar el color


col.setHsb(ofRandom(0,255), 255, 255, 100);
       // hue: 0 ~ 255; saturación: 255; brillo: 255; alfa: 255 

Sistema de partículas




void SistemadeParticula :: addParticula{
Particula p; // Particula es el objeto; p es la instancia del objeto
 p.pos.x = ofGetMouseX();    // x del origen de la instancia en el x del mouse
 p.pos.y = ofGetMouseY();    // y del origen de la instancia en el y del mouse
 p.vel.y = ofRandom(-0.2, -2.0); // velocidad en x
 p.vel.x = ofRandom(-2.0, 2.0); // velocidad en y
 p.radio = ofRandom(1.0, 15.0); // radio entre 1 y 15
 p.vida = 100.0; // valor alfa de la partícula, se hace más transparente
 p.col.setHsb(ofRandom(0, 255), 255, 255, 100); // color pleno hue, saturación, brillo, alfa
}


Las ecuaciones de física son como los ejemplos anteriores pero sin los rebotes en y ni en x.
Solo hay que agregar que vaya disminuyendo el valor alfa:
vida -= 1;

Particula :: draw {
 ofFill(); // con relleno
 ofSetColor(col, vida); // el color combinado Hsb, vida
 ofCircle(pos.x ,pos.y, radio); // el dibujo de la instancia en la pantalla
}

domingo, 8 de julio de 2012

3D: Pelota, Pared, luz - terminado


Aquí llegué más o menos donde quería... aunque aún queda por resolver que cada instancia de Pelota se sean una con otra y reboten entre ellas.
Todo lo que utilicé aquí está explicado en los blogs anteriores.

3D: Pelota, Pared, luz


3D: 50 instancias de Pelota, 5 instancias de Pared, 1 luz ambiente al centro del cubo.
Este es el mismo ejemplo pero con 50 ball de Pelota.
También en wall de Pared, cada una de ellas cambia el color de cada ball y reproduce un sonido cuando ball  rebota en wall.

ofLight;


testApp.h
ofLight luz; // luz será un método con formato ofLight

testApp.cpp
void testApp :: setup
luz.setAmbientColor(ofColor(255,255,255)); // tipo de luz y color blanco

void testApp :: draw
 luz.enable(); // habilito la luz
 luz.setPosition(450, 0, 450); // le doy la posición con los 3 ejes: x, y, z

Es muy interesante el efecto de la luz sobre los dibujos, sobre todo en los cuerpos geométricos; luces y sombras.


X, Y, Z... rebotes con colores


Después de nuestra clase Pelotas, también armé una clase Pared.
En este caso el piso y las 4 paredes son una clase, todas son límite de las balls (cada instancia de Pelota) pero lo diferente es que cuando una ball toca una pared, esta cambia de color. Los colores están en las instancias (wall) de Pared; y cuando una ball toca a una wall, ball toma el color que le dio wall.
Aquí tampoco están corregidos los problemas y ajustes del rebote. WORK IN PROGRESS...

  Pelota ball[5];
  Pared wall[5]; // piso + 4 paredes

Eje z, 3D y ofEasyCam


Bienvenidos al 3D!
Para este ejemplo solo debemos agregar el eje z en todas las coordenadas que tengamos x, y.
Gracias a oF los ofPoint están preparados para esto porque guardan x, y, z. También los ofPoint se ocupan de calcular todo lo que necesitemos.

Un detalle: a la hora de dibujar un ofCircle deberíamos reemplazarlo por ofSphere(x, y, z, radio);
Si estamos trabajando con los 3 ejes y no lo consideramos, el círculo se dibujará en z = 0.

testApp.h
ofEasyCam cam; // la variable cam está formateada como una ofEasyCam

testApp.cpp
::draw{
    cam.begin(); // comienza EasyCam
    ofPushMatrix();
    ofTranslate(x, y, z); // voy a necesitar trasladar para encuadrar la cam con el dibujo
    ofRotateX(180); // voy a necesitar rotar 180° en X para que la cam no vea patas para arriba
    aquí lo que quiera dibujar
    ofPopMatrix();
    cam.end(); // cierro EasyCam

Objetos - class


Trabajar con class es un poco molesto, pero necesario... después de entenderlo uno comienza a disfrutarlo.
Voy a crear una clase Pelota. Iré paso a paso.


-- testApp.h
#define CANTIDAD 10   // cantidad de instancias de la classe

class testApp : public ofBaseApp{
Pelota ball[CANTIDAD]; //  la clase Pelota tiene 10 instancias que se llaman ball
}

-- testApp.cpp
testApp.cpp :: update
for (int i = 0; i < CANTIDAD; i++){
      ball[i].calcularFisica();  //  desde aquí calculo la física en Pelota para cada una de las instancias
}

testApp :: draw(){
for (int i = 0; i < CANTIDAD ; i++){
       ball[i].dibujar();         // desde aquí dibujo en Pelota cada una de las instancias
}


-- pelota.h
#ifndef PELOTA_H
#define PELOTA_H
#include "ofMain.h"
class Pelota{
public:
    Pelota();
    void    dibujar(); // defino la función dibujar en Pelota
    ofPoint pos; // defino el ofPoint pos para la posición de Pelota (pos.x, pos.y)
    ofPoint vel; // defino el ofPoint vel para la velocidad de Pelota (vel.x, vel.y)
    ofPoint acc; // defino el ofPoint acc para la aceleración de Pelota (acc.x, acc.y)
    ofColor color; // defino el ofColor color para el colorde Pelota
    int radio; // defino radio de Pelota que luego será el radio de cada una de las instancias
};


-- pelota.cpp
#include "Pelota.h"
Pelota::Pelota(){ // acá se dan los valores por default. para cada instancia los valores rnd varían
    color.set(ofRandom(100, 255), ofRandom(100, 255), ofRandom(100, 255));
    radio = ofRandom(1, 60);
    pos.set(ofRandom(450, 650),ofRandom(50, 300)); // posición en x, y
    acc.set(0, 0); // aceleración
    vel.set(ofRandom(-10, 10), ofRandom(-10, 10)); // velocidad en x, y
}

void Pelota::calcularFisica(){ // esto es lo interesante de hacer ecuaciones con los ofPoint
    vel += acc; // vel.x = vel.x + acc.x; vel.y = vel.y + acc.y;
    vel *= 0.98;  // vel.y = vel.y * 0.98; vel.y = vel.y *0.98;
    pos += vel; // pos.x = pos.x + vel.x; pos.y = pos.y + vel.y;
    acc *= 0; // acc.x = acc.x * 0; acc.y = acc.y * 0;
}

void Pelota::dibujar(){
    ofFill(); // relleno
    ofSetColor(color); // seteo el color
    ofCircle(pos.x, pos.y, radio); // dibujo un círculo en x, y con radio

    ofSetLineWidth(1); // ancho de línea 1
    ofNoFill(); // sin releno
    ofSetColor(0, 0, 0); // color negro
    ofCircle(pos.x, pos.y, radio);  // solo va a dibujar el contorno del círculo
}

no están desarrollados los rebotes porque ya están en videos anteriores

ofSoundPlayer;



ofSoundPlayer sonido[3]; // hago un array en sonido con 3 posiciones

sonido[0].loadSound("01.mp3"); // los cargo en su lugar
sonido[1].loadSound("02.mp3");
sonido[2].loadSound("03.mp3");

   if (pos.x <= 100+radio){ // pared izquierda
        vel.x *= -1; // que cambie de velocidad para el otro lado
        sonido[1].play(); // que suene el rebote en la pared
    }
    if (pos.x >= 1000-radio){ // pared derecha
        vel.x *= -1;
        sonido[2].play();
    }

   if (pos.y >= 500){ // piso
        vel.y *= -1;
        sonido[1];
  }

Cálculos de física: velocidad, posición y aceleración



Estos son los cálculos de física que empleamos para que los objetos imiten el desplazamiento y la gravedad en nuestro mundo programado.

velocidad = velocidad + aceleracion;
velocidad = velocidad * 0.98; // 0.9998 mas lento (como se ve en el ejemplo)
posicion = posición + velocidad;
aceleración = aceleración * 0;

Para el rebote, cuando la posición en Y llega hasta lo que considero piso (en mi caso 500px):
if (posicion.y >= 500){
            // también hay que considerar el tamaño del radio porque hay que sumarlo a y del círculos
        velocidad.y *= -1; // multiplico por -1 la velocidad para que cambie de dirección
}

Lo mismo para las paredes en X  
Como dejé claro en el video, debo corregir el drag. Mi intención es hacer que la pelota tome la velocidad de impulso que pueda darle el mouse. WORK IN PROGRESS!!!

ofxOpenCv


La librería ofxOpenCv es muy compleja. Aquí sólo estoy utilizando una pequeña parte de ella para el blob.
Es secreto aquí es capturar el "fondo", guardar esta imagen y restarla con la imagen que proviene desde la cámara. Esto es lo que se ve en las 3 formas de mostrar la cámara en la parte superior de la pantalla.
Una vez que tengo el blob, utilizo una función que calcula la posición del centro del blob en x, y. Después de esto utilizo esa posición para mostrar el círculo.

ofxCvColorImage        imgCv;
ofxCvGrayscaleImage  imgCvGrayScale;
ofxCvGrayscaleImage  imgCvGrayScaleBckGnd;
ofxCvContourFinder    contour;

imgCvGrayScale = imgCv; // Convierto la imagen de la webcam en escala de grises
imgCvGrayScaleBckGnd = imgCvGrayScale; // Guardo esta imagen para tener el "fondo".
imgCvGrayScale.absDiff(imgCvGrayScaleBckGnd); // resto las imágenes
contour.findContours(imgCvGrayScale, 50, (ofGetWidth()*ofGetWidth())/2, 1, false);
    // en el resultado de la resta busco: area mín del blob, area máx de blob, cant de blobs, sin agujeros.

int nuevoX = contour.blobs[0].centroid.x // este es el x del centro del blob 0
int nuevoY = contour.blobs[0].centroid.y // este es el y del centro del blob 0

apartir de estas coordenadas dibujo lo que quiero:
ofCircle(nuevoX, nuevoY, 20);

ofVideoGrabber;


ofVideoGrabber video; // para asignarle la webcam
ofImage imagen; // esta será la espajada de la derecha
ofImage imagenBlNe; // esta es en escala de grises
ofImage imagenRojo; // solo en R

video.initGrabber(320, 240); // pongo dentro de video lo que toma la webcam en 320x240
imagen.allocate(320, 240, OF_IMAGE_COLOR); // guardo en imagen imagenes de 320x240 con RGB
imagenBlNe.allocate(320, 240, OF_IMAGE_COLOR);
imagenRojo.allocate(320, 240, OF_IMAGE_COLOR);
video.update(); // fundamental refrescar la entrada de video

para recorrer la imagen que vienen de la webcam que está guardada en un vector
for (int y = 0; y < 240; y++){
      for (int x = 0; x < 320; x++){
            for (int rgb = 0; rgb < 3; rgb++){ // esto es fundamental si trabajo con RGB
                  int i = y * 320 + x; // con i recorro cada lugar del vector
                  int blNg = (i * 3);
                  pixelOutBlNe[blNg+rgb] = pixelIn[blNg]; // esto es sólo para la imagen en grises
           }
     }
}

imagenBlNe.setFromPixels(pixelOutBlNe,320,240,OF_IMAGE_COLOR);

imagenBlNe.draw(0,240); // dibujar esta imagen en la posición 0, 240

ofSoundPlayer; ofGetMouseX(); ofGetMouseY();


ofSoundPlayer sonido01, sonido02, sonido03  //  ... hasta 07
    sonido01.loadSound("01.wav");
    sonido02.loadSound("02.wav");
    sonido03.loadSound("03.wav"); //  ... hasta 07

para saber qué fader estoy tocando busco la posición de ofGetMouseX();
para la posición de Y utilizo lo siguiente:
valory = (ofMap(ofGetMouseY(), 500, 100, 0, 255)); // para el color del fader
volumen02 = ofMap(ofGetMouseY(), 500, 100, 0, 1); // para el volumen de la pista

ofSoundPlayer y ofImage


ofSoundPlayer sonido;
sonido.loadSound("meloadvertiste.mp3");
paneo = ofMap(ofGetMouseX(), 0, 1024, -1, 1);
                      // escalo el ancho de la pantalla para los valores de paneo (-1 a 1). -1 L; 0 C; 1 R.
volumen = ofMap(ofGetMouseY(), 0, 600, 1, 0);
                     // lo mismo con el volumen pero de 0 a 1 con el alto de la pantalla.
sonido.setVolume(volumen);
sonido.setPan(paneo);


ofImage
ofImage alfa;
ofEnableAlphaBlending(); // habitilo el canal alfa
alfa.loadImage("alfa.png");
ofEnableBlendMode(OF_BLENDMODE_SUBTRACT);
alfa.draw(ofGetMouseX()-45, ofGetMouseY-45);
ofDisableBlendMode();
ofSetColor(colx,0,coly); // colx, coly cambian de valor según la posición del mouse en x
ofCircle(ofGetMouseX()-45, ofGetMouseY,30,30);

Drag


float distancia = ofDist(posX, posY, ofGetMouseX(), ofGetMouseY());
if(distancia < radio){ // radio del circulo que está dibujado
        pincha = true;
        difx = x - posX;
        dify = y - posY;
    }


if (pincha){
         posX = x - difx;
         posY = y - dify;
    }

ofCircle(posX, posY, radio);

ofGetMouseX(); ofGetMouseY();




ofSetColor(255, 0, 0);
ofCircle(ofGetMouseX(), ofGetMouseY(), 100);
ofRect(int(ofGetWidth())-ofGetMouseX(), 300, 200, 200);
ofSetColor(0, 255, 0);
ofRect(400, int(ofGetHeight())-ofGetMouseY(), 200, 200);

    if (arrastro == true){
        ofSetColor(0, 0, 255, 100);
        ofRect(int(ofGetWidth())-ofGetMouseX(), int(ofGetHeight())-ofGetMouseY(), 200, 200);
        ofCircle(xm, ym, 100);
        } else {
        ofSetColor(0, 0, 255);
        ofRect(int(ofGetWidth())-ofGetMouseX(), int(ofGetHeight())-ofGetMouseY(), 200, 200);
        ofCircle(xm, ym, 100);
    }