ofxKinect + sistema de partículas
sábado, 28 de julio de 2012
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
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);
}
Suscribirse a:
Entradas (Atom)