Skip navigation

Monthly Archives: Março 2009

bolasobstaculos5-01921

bolasobstaculos5-02119

pedrojesusratatui

pedrojesus_metropolis

bolasobstaculos5-03049

bolasobstaculos5-00671

 

bolasobstaculos5-00222

bolasobstaculos5-00045

 

Anúncios

hoje continuamos as arraylists e comunicação inter-objectos, para detecção de colisão e respostas, sejam elas de movimento ou gráficas; introduzimos o PVector, tipo de dados do processing que manipula vectores 2 e 3d; fomos ainda ver como ligar joysticks e interfaces usb ao computador, e alguns exemplos mais finalizados.

 

1. comunicação inter-objectos; diferentes respostas às colisões.

sendo os objectos armazenados em ArrayLists, e estas declaradas globalmente no sketch, as classes que definimos podem ler informação dos elementos contidos noutras ou na mesma arraylist. é assim que a class Bola acede às posições de cada obstáculo e cada outra bola para na função colide verificar se a distância a que está do outro objecto é inferior à soma dos raios, se for, já sabemos que está a colidir com esse objecto. (leiam as notas da sessão 9 se tiverem dúvidas nestes pontos acima referidos).

primeiro, no sketch bolas_e_obstaculos_arraylist6.pde, introduzimos uma class Tiro, esta será responsável por disparar linhas com duração máxima determinada, e se as linhas colidirem ou com bolas, ou com obstáculos, efectuamos respostas a essa colisão que não vão ser de movimento, vão ser gráficas e lógicas. 

 

a class Tiro vai ter como função principal a mesma que a Bola, ie, 

  void render(){

    colide();

    update();

    draw(); 

  }

toda a lógica das respostas será implementada na função colide. esta é igual ao encontrar das distâncias entre os objectos, e a parte relevante está aqui destacada:

    //colisão apenas com os obstáculos

      if (distance < minDist) { 

        energy=-1; // colocar a energia do tiro negativa para que ele seja removido da arraylist

      }

    //colisão com as outras bolas

      if (distance < minDist) { 

        b.live=false; // indicar à bola que ela vai ser removida da arraylist

        energy = -1; // colocar a energia do tiro negativa para que ele seja removido da arraylist

      }

bolasobstaculos6-00174

ou seja, nestas colisões não nos importa a resposta de movimento, vamos apenas eliminar os tiros no caso da colisão com os obstáculos, e eliminar os tiros e as bolas das respectivas arraylists no caso de colisão com bolas. facilmente os tiros podiam mover ou eliminar os obstáculos também. bastava que a detecção de colisão ao obstáculo implementasse como respostas acelerações ao movimento, e possível remoção do obstáculo.

bolasobstaculos6-00510

 

para tornar as coisas mais interessantes gráficamente, vamos extender ligeiramente o código, e introduzir umas partículas simples que desenham bitmaps nos locais das colisões, uma class de explosões, e umas imagens das explosões que vamos usar.

no sketch bolas_e_obstaculos_arraylist7.pde introduzimos um novo tab ao projecto que se chama explosoes, e além da class Explo que define o comportamento das partículas, vamos declarar a array de imagens, uma função para ler as imagens, uma função para fazer uma explosão com num elementos na posição xy.

 

/// as imagens

PImage explosoes[];

/// iniciar a array de imagens

void init_explosoes(){

  explosoes = new PImage[8];

  for(int i=0; i<8;i++){

    String f = “e16-“+i+”.png”;

    explosoes[i] = loadImage(f); 

  }

}

/// criar num elementos e adicioná-los à arraylist explosions

void explode(float x,float y, int num) {

  if(explosions.size()<500){

  for(int i=0; i<num;i++){

    Explo e = new Explo(x,y);

    explosions.add(e);

  }

  }

}

 

temos presente uma nova arraylist explosions que é renderizada como todos os outros objectos; cada elemento da class Explo acede a uma imagem da array de imagens explosoes[] que declaramos.

bolasobstaculos5-02615

modificamos ligeiramente as respostas de colisão que vimos no sketch 6, e adicionamos uma chamada à função explode( float x, float y, int num), que insere estes novos elementos gráficos em cena.

 

    //colisão apenas com os obstáculos

      if (distance < minDist) { 

        energy=-1; // colocar a energia do tiro negativa para que ele seja removido da arraylist

        explode(x,y,(int)random(2,5)); 

      }

 

    //colisão com as outras bolas

      if (distance < minDist) { 

        b.live=false; // indicar à bola que ela vai ser removida da arraylist

        energy = -1; // colocar a energia do tiro negativa para que ele seja removido da arraylist

        explode(x,y,(int)random(5,10)); 

      }

 

bolasobstaculos5-01430

 

 

2. colisão com vectores em 2 e 3d (PVector)

 

um PVector é um vector, ie, um tipo de dados que armazena componentes x, y e z de um ponto ou um vector. além desses campos, que podem ser manipulados tipo pos.x = 100; ou pos.x+=vel.x;  tem vários métodos que fazem operações com todos os elementos. o código é simplificado quando levamos as coisas para 3d, em vez de termos 3 variáveis para a posição, 3 para a velocidade e outras 3 para a acelaração, declaramos apenas 3 PVectors, um para a pos, outro vel e outro acc. além de que temos acesso a uma vasta gama de operações aos vectores (ver reference do PVector).

quando fazíamos :

x+=vx;

y+=vy;

vamos agora fazer :

pos.add(vel);

bolasvectormouse-001951

 

o core do código da bola em 3d e com vectores será idêntico ao que já vimos, com a extensão dos cálculos para a terceira dimensão

  void render(int i){

    colide(i);

    update();

    display();

  }

  void update(){

    vel.add(acc);

    vel.mult(friccao);

    vel.y+=grav;

    pos.add(vel);

    acc.set(0.,0.,0.);

    bounds();

  }

 

as modificações mais importantes são a detecção e resposta em 3d. no próximo sketch temos agora um conjunto de esferas em cena que colidem umas com as outras e com as paredes do mundo.

bolas_vector_3d-00123

bolas_vector_3d-03937

 

 

 

3. joysticks 

 

são dispositivos usb, com um ou mais eixo analógico, que enviam valores variáveis, e botões, que enviam on/off. através do processing e de outros ambientes de programação conseguimos aceder aos valores dos josticks, de qualquer botão, eixo que ele tenha. fomos usar a biblioteca procontroll.

primeiro, instalar a biblioteca na directoria  sketch book / libraries. depois de relançar o processing com o joystick ligado, podemos correr os sketches. no primeiro sketch listamos todos os eixos e butões de todos os dispositivos que conseguimos aceder. além do teclado, trackpack, aparecem outros dispositivos, neste caso, logitech dual action. na consola do processing aparecem todos os identificadores dos eixos (o que aparece do joystick:)

<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Logitech Dual Action has:

 4 sliders

 13 buttons

 2 sticks

<<< available Logitech Dual Action sliders: >>>

     0: x absolute

     1: y absolute

     2: z absolute

     3: rz absolute

<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<< available Logitech Dual Action buttons: >>>

     0: 0

     1: 1

     2: 2

     3: 3

     4: 4

     5: 5

     6: 6

     7: 7

     8: 8

     9: 9

     10: 10

     11: 11

     12: cooliehat: pov

<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<< available Logitech Dual Action sticks: >>>

     0: y x

     1: rz z

<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

 

 

no sketches seguintes, acedemos aos valores dos eixos, primeiro importar a library, declarar as variáveis, depois construí-las durante a setup, e durante a draw ler os valores dos eixos: 

 

import procontroll.*;

import net.java.games.input.*;

 

ControllIO controllIO;

ControllDevice joypad;

ControllStick stick1;

ControllStick stick2;

 

….setup….

  controllIO = ControllIO.getInstance(this);

  joypad = controllIO.getDevice(“Logitech Dual Action”);//Logitech RumblePad 2 USB”);

 

  stick1 = joypad.getStick(0);

  stick2 = joypad.getStick(1);

 

….draw….

  rotateX(stick2.getTotalY());

  rotateY(stick2.getTotalX());

 

depois implementamos um mini-jogo para 2 jogadores, duas ellipses que disparam tiros e inimigos lançados do centro. aqui as funções de update dos players são guiadas pelos valores que obtemos vindos da gamepad.

joystickgame-01058

joystickgame-01329

 

4. alguns exemplos mais finalizados

uma variação das bolas e obstaculos, um heroi que dispara tiros e cinde bolas em duas mais pequenas que vão colidindo com obstáculos em cena. aqui recriamos a lógica dos sketches anteriores de bolas e obstáculos, com outras regras, onde se o tiro colidir com bolas fazemos desaparecer a maior e reaparecerem duas mais pequenas nas mesma posição.

bolas_obstaculos-01438

bolas_obstaculos-00770

depois fomos ver uma variação do exemplo reflection2 do processing (file > examples > topics > motion ), aqui tinhamos as teclas a interferir no sketch, o w,a,s,d influenciam as velocidades da bola, e a colisão com um terreno multisegmentado.

 

bolas_ground-007291

bolas_ground-00915

e finalmente, como transformar um slitscan de video numa textura para um plano em 3d que pode ser rodado em torno do x e y.

slit3d-00191

slit3d-00686

 

nesta sessão finalizamos a introdução a vários temas de síntese, manipulação e interacção de imagens em 2 e 3d usando o processing. nas sessões seguintes vamos analisar síntese e manipulação sonora dentro do pure data, uma  linguagem de programação visual opensource, bem como comunicação inter-programas, e inter-computador, através de protocolos de rede, que hoje já vimos um curto exemplo que vem com o processing, um chat server. ligando o sketch começamos um servidor que escreve tudo o que recebe dentro da tela. precisamos de agora iniciar uma sessão de telnet, indo ao terminal do macosx, ou instalando o dave’s telnet para windows, por exemplo, e escrevemos:

 

telnet 127.0.0.1 10002

// se o sketch estiver a funcionar têm logo esta mensagem:

Trying 127.0.0.1…

Connected to localhost.

Escape character is ‘^]’.

// tudo o que agora escreverem surje na janela do sketch

hoje analisamos colecções dinâmicas de dados, classes em arraylists. derivação de subclasses, uso de várias classes dentro de uma arraylist; detecção e resposta de colisão entre objectos da mesma classe e de outras classes.  

 

 

1. arraylists


são colecções dinâmicas de dados, uma array que se inicia sem elementos, onde podemos adicionar elementos, aceder ao número e aos dados dos elementos na arraylist, e podemos ainda remover dinamicamente qualquer elemento. são sistemas dinâmicos muito parecidos ao uso das arrays. declaramos as variáveis:

/// arraylist como colecção dinâmica de elementos

ArrayList parts;

PFont f;

float friccao = 0.961;

construímos a arraylist assim:

  parts = new ArrayList(); //criar uma arraylist vazia  

e inserimos elementos para lá ao criarmos um elemento local, e posteriormente chamarmos a função add das arraylists com o elemento criado:

  Part novaPart = new Part(width/2,height/2);  

  parts.add(novaPart); // adicionar um elemento  

na função draw inserimos mais partículas se mousePressed:

  if(mousePressed){    

Part p = new Part(mouseX,mouseY);    

parts.add(p);  

}

e lemos o número actual de elementos: int num_elementos = parts.size();  cada elemento é do tipo de dados que inserimos dentro da arraylist, neste caso, Part. para renderizarmos todos o sistema lemos todos os objectos que fazem parte da arraylist, e ou o removemos da arraylist se ele já não estiver activo, ou o renderizamos, que faz funções de update de posições e emite o comando gráfico que desenha o elemento. tal como nas arrays, vamos usar um ciclo for para aceder a cada elemento:

  for (int i=0; i<parts.size();i++){    

Part p = (Part) parts.get(i);    

if(!p.active)       parts.remove(i);    

else       p.render();  

}

enquanto que nas arrays acedemos aos elementos com o índice dentro de parentisis rectos, nas arraylists lemos os elementos através da função get(i):

parts[i].active, parts[i].render() // aceder a elementos e funções de obj em arrays

Part p = (Part )parts.get(i); // aceder ao elemento i da arraylist

p.active, p.render() // aceder a elementos e funções de obj em arraylists  

estas são as funções principais das arraylists que mais vamos utilizar: inserir elementos para a arraylist, aceder a campos e métodos dele, e removê-lo da arraylist. parts.add(Part elemento), parts.get(int numero_do_elemento), parts.remove((int numero_do_elemento), int numero_de_elementos = parts.size();  

arraylist-00083

arraylist-00264

 

 

2. extensão de classes


todas as classes podem ser extendidas. ao extendermos, criamos uma nova classe que tem todos os campos e funções da classe base, e criamos um novo tipo de dados que extende o tipo de dados anterior. assim, temos a nossa classe Part:  

class Part{

  float x,y,vx,vy, energy;

  boolean active=true;

 

  Part(float _x, float _y){

    x = _x;

    y = _y;

    vx = random(-5,5);

    vy = random(-5,5);

    energy = 255.0f;    

  } 

 

  void render(){

    update();

    fill(255,energy);

    ellipse(x,y,20,20); 

  }

 

  void update(){

    x += vx;

    y += vy;

    vx *= friccao;

    vy *= friccao; 

    energy -= 1.5;

    if (energy<0.)

      active=false;    

  }

}

 

esta classe tem x,y,vx,vy,… como campos, e render(), update() como funções. definimos agora uma classe Part2 que extende e modifica o comportamento de funções:  

class Part2 extends Part{

 

  Part2(float _x, float _y){    

    super(_x,_y); // chamar o construtor de Part com parâmetros

    energy_dec = random(0.5,1.2); // re-escrever o valor de energy_dec, para ficarem mais tempo activas

  }

 

  void render(){ // um render de Part2, diferente de Part

    update(); // chamar a update de Part, não está aqui presente

    fill(255,energy);

    float amt = energy*0.005;

    ellipse(x+random(-amt,amt) , y+random(-amt,amt) , 50,50); // raio maior, posições random

  }

}

a classe Part2, além dos métodos de Part, tem agora estes novos construtor e função render. a função render substitui a render de Part, e desenha as coisas de maneira diferente, mas chama na mesma a função update que apenas está definida na class Part, e não aqui. como esta classe extende a Part, acedemos aos métodos da classe como se eles já estivessem declarados.   estas duas classes são agora inseridas na mesma arraylist, uma array que fica quer com elementos Part, quer com elementos Part2. como os elementos de Part2 são extendidos de Part, podemos tratá-los como se fossem Part na leitura dos elementos.  

  //adicionar 2 elementos de classes diferentes para 1 arraylist

  parts = new ArrayList(); //criar uma arraylist vazia

  Part novaPart = new Part(width/2,height/2);

  Part2 novaPart2 = new Part2(width/2,height/2);

  parts.add(novaPart); // adicionar um elemento

  parts.add(novaPart2); // adicionar um elemento

 

  // aceder aos elementos Part e Part2

  for (int i=0; i<parts.size();i++){

    Part p = (Part) parts.get(i);

    p.render();

    (if !p.active)

parts.remove(i);

arraylist-000821

 

fizemos a mesma coisa com uma classe Part3, que extende Part:  

class Part3 extends Part{

 

  Part3(float _x, float _y){    

    super(_x,_y);

    energy_dec = random(0.5,1.2);

  }

 

  void render(){

    update();

    fill(random(200),random(200),random(200),energy);  // cores aleatórias

    float amt = energy*0.005;

    ellipse(x+random(-amt,amt) , y+random(-amt,amt) , 50,50); 

  }

}

arraylist-00072

arraylist-00277

 

 

 

3. detecção e resposta de colisões entre objectos  

 

primeiro vimos os exemplos bounce e depois o bouncybubbles dos exemplos do processing (file>examples>topics>motion). no bounce vimos como é que se colide com a periferia da tela. se a posição x é menor que (0+raio), então está a colidir com a parede esquerda logo deve inverter a velocidade do eixo do x. e se a posição x é superior a (largura+raio), a mesma situação. isto está definido nos testes if. if xpos maior que largura-size ou xpos<0, então inverter direcção x, que multiplica por um valor de velocidade. o mesmo acontece no eixo dos y’s.  

  // Update the position of the shape

  xpos = xpos + ( xspeed * xdirection );

  ypos = ypos + ( yspeed * ydirection );

 

  // Test to see if the shape exceeds the boundaries of the screen

  // If it does, reverse its direction by multiplying by -1

  if (xpos > width-size || xpos < 0) {

    xdirection *= -1;

  }

  if (ypos > height-size || ypos < 0) {

    ydirection *= -1;

  }

bounce-00021

bounce-00067

 

depois analisamos o bouncybubbles, aí já há um óptimo método de detecção de colisão e resposta no caso colisão circulo-circulo. são colisões com um factor de elasticidade que pode ser ajustado para colisões ríspidas, ou colisões elásticas. a lógica é muito semelhante ao que já temos analisado. além do update e render, vamos ter um método que vai efectuar a colisão da bola actual com todas as restantes bolas. este método colide é executado a cada frame do programa, e nele testam-se as posições da bola actual contra todas as posições das restantes bolas que fazem parte da array Balls. neste sketch executamos as funções colide, move e display a cada bola.   

 

void draw() 

{

  background(0);

  for (int i = 0; i < numBalls; i++) {

    balls[i].collide();

    balls[i].move();

    balls[i].display();  

  }

}

a colide vai afectar as velocidades das partículas se a soma dos raios de cada elemento for inferior à distância entre os centros, a situação de colisão. nesse caso, calcula-se o ângulo da colisão, a posição xy óptima dessa partícula como resposta a colisão, andar na direcção do vector de colisão a distância da soma dos raios das partículas; esta posição xy target vai ser suavizada com um factor de spring, o tal factor de elasticidade que controla a suavidade da resposta à colisão. o resultado encontrado são acelerações que devemos acumular nas velocidades actuais das partículas. a nossa partícula (velocidades vx e vy) são diminuídas as acelerações, às velocidades do outro círculo, são adicionadas as acelerações. a seguir a move encarrega-se de adicionar as novas velocidades às posições actuais das bolas.  

 

  void collide() {

    for (int i = id + 1; i < numBalls; i++) {

      float dx = others[i].x – x;

      float dy = others[i].y – y;

      float distance = sqrt(dx*dx + dy*dy);

      float minDist = others[i].diameter/2 + diameter/2;

      if (distance < minDist) { 

        float angle = atan2(dy, dx);

        float targetX = x + cos(angle) * minDist;

        float targetY = y + sin(angle) * minDist;

        float ax = (targetX – others[i].x) * spring;

        float ay = (targetY – others[i].y) * spring;

        vx -= ax;

        vy -= ay;

        others[i].vx += ax;

        others[i].vy += ay;

      }

    }   

  }

bouncybubbles-000801

bouncybubbles-001281

de seguida, criamos uma modificação neste sketch, uma versão com arraylists, onde podemos adicionar as partículas que quisermos ao carregar no rato. 

  // iniciar a arraylist:

  for (int i = 0; i < numBalls; i++) {

    Ball b = new Ball(random(width), random(height), random(20, 40), i, balls);

    balls.add(b);

  }

e a função draw, onde além de gerirmos as partículas, adicionamos novos elementos na posição xy do rato:

void draw() {

  background(0);

  for (int i = 0; i <  balls.size(); i++) {

    Ball b = (Ball) balls.get(i);

    b.collide();

    b.move();

    b.display();  

  }

  if(mousePressed){

    if(frameCount%10==0){

       Ball b = new Ball(mouseX,mouseY, random(20, 40), balls.size(), balls); 

       balls.add(b);

    }

  }  

}

 

  bounce_array-008522

bounce_array-01060

 

 

 

4. colisões entre objectos de classes diferentes  

 

um motor mais elaborado terá diferentes classes de objectos que têm comportamentos distintos entre si, se actualizamos posições ou se estão estáticos, que dimensões ocupam, como os desenhamos de maneira diferente, etc. para isto, devemos criar várias classes de objectos, onde cada classe define o comportamento específico de cada objecto. mantemos uma array ou várias arraylists de objectos e dentro dos métodos de colide de cada elemento que pode colidir, temos de testar todas as posições actuais dos elementos que poderão colidir.   para simplificar fomos criar uma classe de bolas, e outra de obstáculos circulares. os obstáculos não se movem, são apenas posições, raio. as bolas é que têm posições, velocidades, raio, e como se deslocam, terão também uma função colide que implementará a colisão elástica que vimos anteriormente.  

class Obstaculo{

  float x,y,r;

  Obstaculo(){

    x = random(width);

    y = random(height);

    r = random(20,50);

  }

  void render(){

   draw(); 

  }

  void draw(){

    fill(100,50,0,250);

    ellipse (x,y,r*2,r*2);

  }

}

 

class Bola{

  float x,y,r, vx,vy;

  Bola(){

    x = random(width);

    y = random(height);

    r = random(10,20);

    vx = random(-5,5);

    vy = random(-5,5);

  }

  void render(){

    colide();

   update();

   draw(); 

  }

  void colide(){

  }

  void update(){

    x+=vx;

    y+=vy;

    //bounds

    if(x<0)  {x=0; vx = -vx;}

    if(x>width)  {x=width; vx = -vx;}

    if(y<0)  {y=0; vy = -vy;}

    if(y>height)  {y=height; vy = -vy;}

  }

  void draw(){

    fill(100,200);

    ellipse (x,y,r*2,r*2);

  }

tendo estas duas classes, fazemos duas arraylists globais onde vamos armazenar os vários elementos:  

ArrayList bolas = new ArrayList();

ArrayList obstaculos = new ArrayList();

 

a draw chama a render de cada classe:  

 

void draw(){

 background(0);

 for(int i=0; i<obstaculos.size(); i++){

  Obstaculo o = (Obstaculo) obstaculos.get(i);

  o.render();

 } 

 for(int i=0; i<bolas.size(); i++){

  Bola b = (Bola) bolas.get(i);

  b.render();

 } 

}

na render dos obstáculos, apenas gráficos, na render das bolas, chamamos a colide primeiro, depois a update e finalmente a draw. inicialmente não escrevemos nada na colide para apenas ver os elementos todos sem qualquer tipo de comunicação entre eles.

bolasobstaculos-00099

 

num segundo sketch bolas_e_obstaculos_arraylist fomos implementar colisão entre as bolas e os obstáculos. para tal, na função colide da classe Ball foi adicionado um loop for que detecta a colisão entre as coordenadas actuais da bola e de todos os obstáculos. se a distância dos centros for inferior à soma dos raios sabemos que colidem, logo afectamos apenas a velocidade da bola, que é posteriormente actualizada na update.

 

bolasobstaculos2-01166

 

aqui as bolas colidem com os obstáculos, mas não entre elas. para que isso aconteça, vamos num terceiro sketch introduzir colisão entre cada uma das bolas com as restantes da arraylist. aí a função colide, além de colidir com os obstáculos, vai ter um loop for que percorre todos os elementos das bolas, como já analisámos no ponto 3. deste post. acedemos aos elementos da arraylist de obstáculos, e acedemos aos restantes elementos da arraylist bolas. o comportamento do sistema físico agora é bem mais interessante.

 

bolasobstaculos3-02785

bolasobstaculos3-01604

  no quarto sketch, introduzimos uma bola que se controla com o rato, e com a qual podemos interagir com as testantes bolas do sistema.  

ArrayList bolas = new ArrayList();

ArrayList obstaculos = new ArrayList();

Bola ze;

void draw(){

 background(0);

 ze.x = mouseX;

 ze.y = mouseY;

 ze.vx = mouseX-pmouseX;

 ze.vy = mouseY-pmouseY;

 

 for(int i=0; i<obstaculos.size(); i++){

  Obstaculo o = (Obstaculo) obstaculos.get(i);

  o.render();

 } 

 

 for(int i=0; i<bolas.size(); i++){

  Bola b = (Bola) bolas.get(i);

  b.render(i);

  ze.colide(i);

 } 

 

  ze.draw();

 

}

 no quinto sketch adicionamos uma nova classe Destino, uma bola verde que é comparado na colisão das bolas, mais um elemento a colidir com, além dos obstáculos e das outras bolas, se a distância for menor, sabemos que colidem, e são removidos do sistema, e adicionados a um score que vai incrementando.

 

bolasobstaculos5-01263

  o sexto skecth introduz som, quando os elementos colidem com a bola verde ocorre um som de um banco de sons. ainda vimos alguns exemplos de sistemas de colisão física mais avançados, como é o caso do jbox2d e do jbullet. vejam os applets exemplo que eles têm. bom resto de semana.

hoje aprofundámos algumas noções em torno da análise de vídeo a partir de câmaras. na segunda parte, introduzimos o sistema esférico de coordenadas ao criar linhas e uma esfera, cujos vértices oscilam de acordo com uma análise fft.

 

1. análise de video

na introdução à análise de vídeo analisámos os programas que vêem com os exemplos do processing, os sketches background subtraction e frame differencing

nestes sketches fomos observar alguns aspectos essenciais: 

– como é que armazenamos uma única frame de vídeo na memória do computador, através de uma array de ints unidimensional, e como passamos de uma localização xy de pixels para a localização unidimensional da array que armazena os pixeis ( a fórmula pixelloc = x + y*video.width); 

– como armazenamos a informação rgba do pixel numa int, através de técnicas de bit shifting e masking (num único int de 32bit, armazenamos 4*8bits, 8bits por canal de cor, daí o intervalo de valores 0 a 255, porque cada cor rgb do pixel tem 8 bits de precisão, logo, 2^8=256, 0 a 255 valores); 

– como comparamos os pixeis da frame actual com o background, e como através desta comparação retiramos um valor, que corresponde à soma do número de pixeis distintos do background. 

estes passos correspondem ao início da análise de formas que se destacam dos pixeis de background, um valor que se associa à presença na imagem, e que poderá ser um indicador da quantidade de presença frente a uma cena, um pouco como o nível de intensidade sonora. se houver movimento distinto do fundo, o número de pixeis brancos sobe, a a sua contagem devolve a actividade ou presença. passos seguintes incluiem efectuar uma binarização da imagem, torná-la apenas com pixeis 0 ou 255, a partir de um algoritmo que analisa a quantidade da diferença rgb de cada pixel, e se essa diferença for superior a um valor, então marca-se o pixel a branco, senão, marcamos o pixel a preto. a análise da caixa onde esses pixeis brancos se inserem, ie, dos pontos na imagem que correspondem ao mínimo e máximo de x e y onde os pixeis brancos estão, e já temos informação suficiente para calcular o seu centróide, que corresponde ao ponto médio das coordenadas adquiridas. isto é uma direcção na análise de vídeo, há várias outras direcções que  incluem face tracking, delimitação da silhueta com um polígono, hands tracking, optical flow, haar cascades, brightness tracking, …..

o primeiro sketch de background subtraction compara a imagem que chega contra uma frame estática, ou que dá a presença. o segundo sketch de frame differencing é igual ao método de background subtraction, com um acrescento, no fim de analisar as diferenças entre os pixeis, copia logo o pixel actual para background da imagem, e temos como resultado uma imagem que apenas devolve o que se move na imagem, num ficamos com uma quantidade de presença, e no outro sketch uma noção do movimento.

bg-002944

framedif-001337

framedif-0015781

 

nos sketches seguintes criamos um programa que desenha à base do centroide principal da imagem.

 uma única coordenada a desenhar ellipses que se acumulam.

centroidvideodraw-000547

centroidvideodraw-000703

a seguir, essa única coordenada é ponto central para outras formas que circulam em torno dela.

centroidcircsvideodraw-0002151

centroidcircsvideodraw-001035

a seguir, este centro serve como centro de um sistema de partículas, copiando as classes que introduzimos há algumas sessões para dentro deste sketch,  as coordenadas do centróide análise de video servem como centro do sistema de partículas que está apenas activos quando e onde há movimento.

sysvideodraw-000514

e depois cada partícula desenha uma cópia da imagem da câmara, em vez de desenhar uma linha, e foi-vos proposto como exercío colocar o tamanho da imagem variável consoante a energia, e a rodar a imagem.

videosyspartdraw-000307

videosyspartdraw-000561

 

2. sistema esférico

na segunda parte da sessão de hoje, abordámos o sistema esférico. é igual ao polar, que já vimos na segunda sessão, só que agora introduzimos a terceira dimensão z, e passamos as coordenadas cartesianas (x,y,z) para coordenadas esféricas (raio, theta, phi). em vez de definirmos pontos como xyz, podemos defini-los como raio, theta, phi, e assim já conseguimos desenhar esferas interactivas ao som. primeiro vimos linhas a sairem para posições aleatórias nos eixos cartesianos, e como isso gera um volume quase esférico.

linhas3dfft-000188

depois aplicamos as formulas de conversão coordenadas cartesianas->esféricas, 

    x = raio*cos(theta)*sin(phi) ;

    y = raio*sin(theta)*sin(phi) ;

    z = raio*cos(phi) ;

e inscrevemos cada vértice na superficie de uma esfera, onde o raio de cada vértice está associado a uma banda da análise fft, e isso gera imagens como estas onde cada frequência atribui um raio cada vertíce, gerando uma superficie esférica formada pelo som. são conceitos avançados 3d que vos poderão ajudar. cada vértice é distribuido num ponto da superficie esférica mapeando valores xy para valores de 0 a 2π que correspondem ao theta e ao phi. 

esfera3dfftsmooth-000517

esfera3dfftsmooth-000280

 

esfera3dfft-000170