Archive

Posts Tagged ‘Processing’

OpenCV - tutorial deteção de blobs e movimento - parte 3

May 24th, 2010

… Continuando dos posts anteriores …

Agora com a captação a imagem da câmera funcionando, e fazendo a leitura dos blobs, cabem algumas considerações sobre os resultados obtidos do sistema. A primeira coisa que se nota é que, a deteção de blobs ocorre em todos os frames da captação de vídeo. Isso não é, necessariamente, o ideal, dependendo do projeto. Afinal na minha idéia, só me interessa verificar o que se move. Com esse comportamento da deteção de blobs, repara-se que mesmo algumas variações de iluminação são o suficiente para o OpenCV ler novos blobs.

Lendo um pouco a documentação do OpenCV e vendo alguns exemplos, reparei na função absDiff(), que trabalha em conjunto com a função remember(). O que elas fazem é “lembrar” ( remember() ) o frame anterior, calcular a diferença ( absDiff() ) para o frame atual, e gerar uma imagem com essa diferença. Ótimo, esse seria um grande passo para facilitar a deteção, exclusiva, de movimentos.

Para estudar exclusivamente esse recurso, fiz o seguinte código:

//importar biblioteca OpenCV

import hypermedia.video.*;

//Instanciar um objeto OpenCV

OpenCV opencv;

//Imagem que captura o "Movimento"

PImage movement;

//Configurar a tela do nosso programa

void setup(){

size(640,480); //tamanho da tela

opencv = new OpenCV(this); //construir objeto OpenCV

opencv.capture(640,480); //inicia captura de vídeo

}

//Execução do software

void draw(){

opencvAction();

}

//Ações do OpenCV

void opencvAction(){

opencv.read();

opencv.absDiff();

movement = opencv.image();

image( movement, 0, 0 );

opencv.remember();

}

O resultado foi esse:

Só um comentário sobre o código em sí: Eu coloquei o trabalho do OpenCV em uma função, chamada opencvAction(), para organizar melhor o código, porque daqui em diante, o código vai crescer em tamanho, e já é bom fazer as coisas organizadinhas para facilitar correções futuras.

Mas o fato realmente “empolgante”, é que com o uso desses recursos obtemos uma imagem que possui apenas a informação de modificações entre o frame anterior e o atual! Vejamos a função opencvAction():

  • Na primeira linha da função: lemos o conteúdo da câmera.
  • Na segunda linha, chamamos a função absDiff(), para calcular a diferença entre os frames.
  • Na terceira linha, guardamos a imagem resultante da diferença no objeto “movement” - observar que esse é um objeto da classe PImage
  • Na quarta linha, desenhamos a imagem da diferença (movement) na tela.
  • Na quinta linha, chamamos a função remember(), para que no próximo frame, o OpenCV, tenha essa imagem para comparar com a próxima.

Com isso feito, fiz o próximo teste, que seria, fazer a deteção de blobs, apenas na imagem resultante da deteção de movimentos, veja o código abaixo: (Obs: apenas acrescentei a função detetarBlobs() )

//importar biblioteca OpenCV
import hypermedia.video.*;
//Instanciar um objeto OpenCV
OpenCV opencv;
//Imagem que captura o "Movimento"
PImage movement;
//Configurar a tela do nosso programa
void setup(){
    size(640,480); //tamanho da tela
    opencv = new OpenCV(this); //construir objeto OpenCV
    opencv.capture(640,480); //inicia captura de vídeo
}

//Execução do software
void draw(){
    opencvAction();
    detetarBlobs();
}

//Ações do OpenCV
void opencvAction(){
    opencv.read();
    //opencv.convert(OpenCV.GRAY);
    opencv.absDiff();
    movement = opencv.image();
    image( movement, 0, 0 );
    opencv.remember();
}

void detetarBlobs(){
    opencv.threshold(100); //tratamento da imagem
    Blob[] blobs = opencv.blobs(200, width*height/2, 10, false, OpenCV.MAX_VERTICES/4);
    //desenhar os blobs existentes
    for( int i=0; i<blobs.length; i++ ) {
        //desenho dos contronos dos blobs<
        beginShape();
        for( int j=0 ; j&lt;blobs[i].points.length ; j++){
            vertex( blobs[i].points[j].x, blobs[i].points[j].y );
        }
        endShape(CLOSE);
        //desenho dos centroids
        fill(200,50,10);
        ellipse(blobs[i].centroid.x, blobs[i].centroid.y, 5,5);
        fill(255);
    }
}

O resultado foi este:

Com essa base, já é possível fazer uma deteção de movimento bem melhor. Temos a imagem “resultante” do movimento; fazendo a deteção de blobs conseguimos isolar dessa imagem as “coisas” que se movem em frente a câmera; Com os blobs calculados, podemos gerar um ponto médio desse deslocamento, fazendo uma média aritmética simples dos pontos “centroids” de cada blob: soma-se os ‘centroid’ de cada blob, e divide-se pela quantidade de blobs.

Bem, é claro que essa última sugestão - na verdade todas as sugestões que dei aqui - dependem do seu projeto, da sua idéia.

Basicamente esse post meio tutorial, meio relato, acaba aqui. Vou escrever um próximo, falando da classe BlobDetection, que chamou muito minha atenção, pela qualidade da deteção de blobs que ela oferece. Ao menos para o meu projeto é melhor que a opção disponível padrão do OpenCV. Mas vale dizer que ambas fazem a mesma coisa, da mesma forma.

até mais.

Processing, Tutoriais , ,

OpenCV - tutorial deteção de blobs e movimento - parte 2

May 24th, 2010

Continuando o meu relato de pesquisa com o OpenCV e Processing…

Depois de testar e constatar que o OpenCV estava capturando corretamente a imagem da minha webcam, chagou a hora de ver como interpretar as imagens. Logo de início fui atrás de como capturar Blobs via OpenCV. Blobs? O que são blobs?… Bem, pelo que entendi, são chamados “blobs” áreas da imagem que se destacam pelo contraste de cores, geralmente contraste entre pontos claros, e escuros (brilho e sombra), mas também é possível fazer seleção por cores específicas.

Com uma rápida consultada na documentação da biblioteca OpenCV para o Processing (veja os itens na coluna à esquerda), há um bom exemplo de como os blobs funcionam. Pelo exemplo o que acontece é o seguinte; Quando chamada a função blobs(), do objeto opencv, o resultado é um array de objetos tipo Blob, que por sua vez, possuem lá seus recursos. Então eu fui xeretar; E a partir do último código comecei a fazer o seguinte (após a função image(), dentro da função draw()):

//Iniciar captura de blobs

opencv.threshold(50);

Blob[] blobs = opencv.blobs(20, width*height/2, 10, true, OpenCV.MAX_VERTICES);

println(blobs.length);

O que fiz foi pedir a detecção de Blobs, que ficaram armazenados no array ‘blobs’, e na seqüencia apenas imprimo no console a quantidade de blobs detetados ( detetados: nova forma de detectados, após o acordo ortográfico =P). Logo de cara, reparei que para a deteção de blobs é necessário um certo tratamento na imagem, no caso o “threshold”. Para quem não conhece tratamento de imagens, esse efeito reduz a quantidade de cores de uma imagem por aproximação, e com isso aumenta os contrastes, veja:

imagem sem aplicação de threshold imagem com aplicação de filtro threshold

Imagens sem, e com, aplicação de filtro “threshold”. Essa configuração é importante para adequar sua captação de blobs à iluminação da sua “cena”.

[…]

Sem a aplicação desse tratamento parece que a deteção de Blobs, não funciona. =P Não gostei disso.

Continuando, fui fazer como no exemplo da documentação e desenhar os blobs na tela para vê-los. E isso é possível se fazer com diferentes informações contidas nos blobs. Para começar mais simples, decidi desenhar na tela o centro do blob, veja na documentação que cada blob possui um ponto chamado ‘centroid’. Então vou usá-lo para desenhar uma elipse no centro de cada blob:

//Iniciar captura de blobs

opencv.threshold(100); //tratamento da imagem

Blob[] blobs = opencv.blobs(20, width*height/2, 10, true, OpenCV.MAX_VERTICES);

//desenhar os blobs existentes

for( int i=0; i&lt;blobs.length; i++ ) {

fill(200,50,10);

ellipse(blobs[i].centroid.x, blobs[i].centroid.y, 5,5);

fill(255);

}

Repare que, obviamente, temos que iterar (com o loop for) por cada blob que está na lista de “blobs”, para desenhar cada um dos “centroids”. Outra opção possível, é fazer como no exemplo, desenhar o contorno de cada blob. Veja abaixo, como fazer isso junto com o desenho dos “centroids”, apenas alterando o loop ‘for’:

for( int i=0; i&lt;blobs.length; i++ ) {

//desenho dos contronos dos blobs

beginShape();

for( int j=0 ; j&lt;blobs[i].points.length ; j++){

vertex( blobs[i].points[j].x, blobs[i].points[j].y );

}

endShape(CLOSE);

//desenho dos centroids

fill(200,50,10);

ellipse(blobs[i].centroid.x, blobs[i].centroid.y, 5,5);

fill(255);

}

Novamente na documentação há a descrição dos ‘points’, que é uma lista dos pontos de compõe o contorno do blob, assim podemos usar essa informação para criar um segundo loop onde desenhamos os pontos como um ’shape’ de fundo branco. Veja como deve ficar:

Além disso outros pontos devem ser observados, em especial as opções para a função blobs(). Naqueles parâmetros é onde se pode configurar melhor a captura desses blobs, lembre-se: SEMPRE OLHE E LEIA A DOCUMENTAÇÃO! Fazendo algumas alterações os resultados podem lhe ser mais interessantes.

Devo confessar que não fiquei muito feliz com a forma do OpenCV fazer a deteção de blobs, e me lembrei da biblioteca BlobDetection, que me trouxeram resultados melhores (em minha opinião). Logo, optei por utilizá-la para esse trabalho. Futuramente vamos falar sobre ela, mas antes vamos falar sobre deteção de movimentos via OpenCV. Mas fica para os próximos textos.

Até.

PS: O código completo é

//importar biblioteca OpenCV

import hypermedia.video.*;

//Instanciar um objeto OpenCV

OpenCV opencv;

//Configurar a tela do nosso programa

void setup(){

size(640,480); //tamanho da tela

opencv = new OpenCV(this); //construir objeto OpenCV

opencv.capture(640,480); //inicia captura de vídeo

}

void draw(){

opencv.read(); //faz a leitura das imagens da câmera

image(opencv.image(), 0,0);//desenha a imagem na tela

//Iniciar captura de blobs

opencv.threshold(100); //tratamento da imagem

Blob[] blobs = opencv.blobs(200, width*height/2, 10, false, OpenCV.MAX_VERTICES/4);

//desenhar os blobs existentes

for( int i=0; i&lt;blobs.length; i++ ) {

//desenho dos contronos dos blobs

beginShape();

for( int j=0 ; j&lt;blobs[i].points.length ; j++){

vertex( blobs[i].points[j].x, blobs[i].points[j].y );

}

endShape(CLOSE);

//desenho dos centroids

fill(200,50,10);

ellipse(blobs[i].centroid.x, blobs[i].centroid.y, 5,5);

fill(255);

}

}

Processing, Tutoriais , ,

OpenCV - tutorial detecção de blobs e movimento - parte 1

May 24th, 2010

Olá,

Recentemente me envolvi em um projeto de uma pequena instalação (quase) artística, que consiste basicamente em controlar a exibição de vídeos, e slideshows, de acordo com a movimentação de quem está vendo o material.

Para isso comecei a estudar conceitos de ‘computer vision’ , detecção de faces, blobs e movimentos em vídeos. Porquê? Porque quem vai detectar o movimento do espectador é uma câmera! Logo, é necessário interpretar, de alguma forma, as imagens captadas pela câmera.

Seguindo comprovações científicas sobre o processo de aprendizado, estou escrevendo esse tutorial, para me ajudar a fixar o que estou aprendendo. Logo, vale ressaltar que, eu não sou um especialista no assunto, estou aprendendo o mesmo. E se o relato desse processo lhe for tão útil quando será para mim, ótimo!

Para esses primeiros estudos vou usar o Processing, a biblioteca OpenCV, e uma biblioteca para o Processing chamada Blob Detection. Se até o final o resultado se mostrar bom o suficiente, vou ficar no Processing mesmo, caso contrário vou para um C++ ou ObjectiveC. Estou desenvolvendo esse projeto em Linux e Mac OSX. Caso você esteja no Windows, sei lhe dizer que tudo isso vai funcionar da mesma forma, porém caso ocorra algum problema, ou você tenha alguma dúvida, que esteja diretamente relacionada as especificidades do Windows, NÃO PODEREI TE AJUDAR! Faz muito tempo que não trabalho no Windows, e confessor que perdi completamente a transição para o Vista e para o 7. E nesse caso o melhor lugar para pedir ajuda é nos fóruns do Processing.

Preparação

Para começar a brincadeira são necessárias algumas instalações, que dependem da plataforma que vc está utilizando, além das instalações básicas (Processing, OpenCV, biblioteca OpenCV para o Processing):

Mac: Essa é a plataforma em que você terá menos trabalho, basta instalar a biblioteca BlobDetection, alem das instalações básicas (Processing, OpenCV, biblioteca OpenCV para o Processing).

Linux: Aqui vc terá mais trabalho. Mas nada sobre humano… Para o Linux você terá que instalar uma biblioteca para que o Processing leia e renderize as imagens da câmera: A GSVideo, que utilizará o Gstreamer para isso (No Mac e no Windows geralmente o Processing usa o Quicktime). E claro você precisará de um driver para que o GStreamer acesse a câmera, nesse caso usei o V4l (video4linux) e foi o suficiente. Além, claro, das instalações básicas (Processing, OpenCV, biblioteca OpenCV para o Processing).. ah… não se esqueça da biblioteca BlobDetection.

Windows: Além das instalações básicas (Processing, OpenCV, biblioteca OpenCV para o Processing), você precisará, assim como no Linux, de uma biblioteca para renderização de vídeo, você pode optar pelo QuickTime, ou pelo GStreamer. Eu recomendaria usar o Quicktime, porque o Processing já é tudo integrado com ele. E… não se esqueça da biblioteca BlobDetection.

Eu não vou explicar aqui os detalhes de instalação dos softwares e bibliotecas, porque nos sites de cada um dos projetos, e internet adentro, já existem tais informações.

Agora o próximo passo é abrir o Processing e fazer um teste. Vejamos.

Veja na imagem abaixo, o código básico para um primeiro teste:

programa de teste

Olha como isso deve funcionar:

Agora a próxima etapa é Começar a analizar as imagens e interpretá-las. Ainda bem que a biblioteca OpenCV faz bastante coisa para agente. :)

Abraço e até mais.

Processing, Tutoriais , ,

Aulas de Processing - Inteligência Artificial

March 26th, 2010

Nesta semana que passou, eu ministrei umas aulas no SESC Carmo sobre uma técnica de inteligência artificial chamada de “swarm behavior” ou flocking. As aulas que estão no Youtube não são exatamente para iniciantes absolutos, são necessários alguns conhecimentos prévios de programação e do Processing, porém toda a turma era de iniciantes… mas o curso já estava na sua terceira semana, quando essas aulas começaram a ser gravadas.

Caso você seja um iniciante completo, aconselho a dar uma olhada nos tutoriais que escrevi aqui. E assistir esses vídeos para ver no geral como a coisa funciona.

Nessa última semana tivemos cinco aulas, e os vídeos estão listados abaixo. Por algumas questões técnicas, os vídeos estão “fatiados”. Em cada “fatia” damos um passo em direção ao objetivo final.

Espero que seja de alguma ajuda.

abraços.

Aula 1 ———————————– Lista de reprodução do Youtube

Aula 2 ———————————– Lista de reprodução do Youtube

Aula 3 ———————————– Lista de reprodução do Youtube

Aula 4 ———————————– Lista de reprodução do Youtube

Aula 5 ———————————– Lista de reprodução do Youtube

Processing, Tutoriais , ,

Oficina Processing, Ex. 1, parte 2

December 10th, 2008

Esta é a continuação, do tutorial de Processing(www.processing.org).

No tutorial anterior, vimos a criação de um objeto, utilizando o método construtor, e uma método de “auto-exibição”, que consistiam em dois requisitos básicos do nosso objeto. Nesta segunda parte, iremos implementar um método de animação e colisão.

Conforme o objetivo desta aula, nós temos que implementar uma animação, para cada um de nossos objetos. O que vamos fazer é uma função dentro da classe Circulo, para mover cada um de nossos objetos.

Bem, a animação em questão, é algo semelhante a uma bola quicando. Então vamos pensar como fazer esta animação. Primeiramente, o nosso circulo deve ir para baixo, e ao tocar na base na tela, ele deve subir, e ao tocar o topo da tela, ele volta a ir para baixo, e assim infinitamente. Traduzindo esse pensamento para uma linha mais técnica, poderíamos dizer isso da seguinte maneira:

- O objeto inicia de deslocando no eixo y (vertical) no sentido “positivo”

- Toca na base da tela

- muda o deslocamento em sentido “negativo”

Espero que isso tenha ficado compreensível, caso contrário, acho que durante o andamento a coisa ficará mais clara. Então vamos lá, na classe Circulo, a primeira coisa que precisamos fazer é inserir duas novas propriedades, uma chamada ‘direcao’ e outra ‘velocidade’, afinal para qualquer movimento precisamos de uma direção e uma velocidade :)

codigo 1

Repare que na variável ‘direcao’, já estou atribuindo a ela o valor 1. Mantenha isto em mente, para mais adiante. A variável ‘velocidade’, não possui um valor previamente atribuído, isso porque eu quero atribuir valor a ela via método construtor, assim poderemos alterar valores para cada objeto que instanciaremos futuramente.

Agora no método construtor teremos mais um parâmetro para tratar:

cod 2

Com essas duas variáveis na mão, vamos fazer a função de movimentação. Vou chamar essa função de mover(). Primeira coisa que faremos, é programar que o objeto se mova para baixo infinitamente.

cod 3

O que essa função está fazendo é incrementar(”aumentar”), o valor do y, que é usado para o desenho da ellipse(observar função exibe()), com uma formulazinha onde a velocidade vezes a ‘direcao’, é somada ao valor do y, ou seja:

- no primeiro frame, y vale 100.

- quando utilizarmos a função mover(), o y receberá o incremento do valor de velocidade X ‘direcao’, ou seja passará a valer 103 (assumindo que a velocidade receba o valor 3).

Para que essa alteração seja visível, vamos atualizar o código da função setup() e da função draw():

cod 4

Repare que no método construtor do objeto circ, estou mandando um quarto parâmetro, 3, que será atribuído à velocidade. E na função draw(), repare que temos que chamar a função mover(), do circ. Ou seja, a cada vez que a função draw() é executada, primeiro será exibido o circulo, e então, o seu centro será deslocado(circ.mover()), e no próximo frame, esse deslocamento será percebido como uma animação. :)

Se você preferir, é possível fazer a chamada da função mover(), de dentro da função exibe() que está na classe Circulo, o resultado será o mesmo.

Finalmente vamos fazer as colisões com a base e o topo da tela.

Vamos adicionar uma estrutura de decisão( uma cláusula if ) na função mover(), para se a base do circulo for igual a base da tela, a direção( 1 ) será multiplicada por -1. Dessa forma, aquela continha que deslocava o centro (Y) do objeto para baixo, começará a deslocá-lo para cima.

cod 5

Você deve ter reparado que essa animação deixou um rastro, como uma trajetória do nosso circulo, para acabar com isso, coloque a ordem de background() na função draw():

cod 6

CLIQUE DO MOUSE

Agora vamos fazer o seguinte, criar uma simples efeito de “interação”, fazer o circulo clicável e ao ser clicado, modar de cor, para um tom aleatório.

No Processing, um click de mouse é entendido como um evento( não vou entrar em grandes detalhes do que é um evento, no momento basta compreender que um click de mouse, ou uma tecla do teclado pressionada são eventos do sistema operacional ), e para tratar alguns tipos de evento, o processing possui funções da linguagem, que são as funções de evento.

Para eventos do mouse nós temos as seguintes funções:

mouseClicked() = quando algum botão do mouse é pressionado

mousePressed()= quando algum botão do mouse é pressionado

mouseReleased()= quando algum botão do mouse deixa de ser pressionad

mouseDragged() = quando algum botão do mouse é pressionado, e o mouse movimentado

Essas funções são programadas junto com as funções draw() e setup(). Veja o exemplo abaixo:

cod 7

Sempre que o mouse é clicado, imprimimos no console de saída a frase “Evento do mouse”. Fassa o teste acima, usando ao invés de mouseClicked(), as outras possibilidades de funções de evento para o mouse.

Agora façamos o seguinte, vamos imprimir na saída de console as coordenadas x e y do mouse, daca vez que o mouse for clicado. Teremos que usar as variáveis mouseX e mouseY, a coisa vai ficar assim:

cod 8

E a saída de console será semelhante a isto:

cod 9

Cada uma dessas linhas no console, são as posições do mouse a cada clique. Essa informação vai ser crucial para fazermos com que nosso objeto reaja ao clique.

Agora que temos as coordenadas de cada clique do mouse, podemos criar uma função na nossa classe para verificar, se o clique aconteceu dentro da área do circulo. Isso é super fácil, basta compararmos a posição do clique, com as coordenadas do circulo. O que é necessário se testar, é se o clique aconteceu dentro da área de alcance do raio da ellipse, observe o desenho abaixo:

desenho de vetores

Esse desenho ilustra um cálculo para medir a distância entre dois pontos. Para fazer esse processo, o Processing nos fornece algumas ferramentas para facilitar a nossa vida, entre elas vamos ver o objeto PVector.

O objeto PVector, é na verdade um vetor. Muitas vezes um vetor e um ponto, são representados da mesma forma, e muitas vezes são utilizados da mesma forma, porém convém lembrar que um vetor deve ser entendido sempre como uma linha, mesmo que sua representação possua apenas duas coordenadas, ele ainda é uma linha com inicio na origem do desenho. Essa propriedade do vetor ser uma linha nos permite uma série de possibilidades, entre elas o cálculo rápido de distâncias.

Vamos então adicionar à classe Circulo, dois objetos do tipo PVector, o v_centro e o v_click, que serão dois vetores, um para o centro do circulo(v_centro) e outro para a coordenada do click(v_click):

objetos PVector

Esses objetos só entrarão em funcionamento quando o mouse clicar na tela. Agora é necessário criar uma função para verificar esse processo, a função click(). A função click() irá criar os dois vetores, e comparar a distância entre eles.

cod 12

O percurso da função é o seguinte:

- atribui x e y do circulo ao vetor v_centro

- atribui as coordenadas do mouse (mouseX e mouseY), ao vetor v_click

- compara a distância entre o v_centro e o v_click( v_centro.dist(v_click) ), e se for menor que o raio(diametro/2), imprime no console “O clique aconteceu dentro do círculo”.

Veja os resultados do console:

saída de console:

Agora que o clique está funcionando, que tal fazermos com que o círculo mude de cor a cada clique? Mas antes disso nós precisamos inserir alguma cor no nosso objeto, porque até agora ele está trabalhando com o padrão do Processing, ou seja, tons de cinza.

Então nós inserimos uma variável do tipo color, na nossa classe, que será então a cor do nosso objeto:

cod 14

Então lá na função exibe(), iremos colocar uma ordem para que o Processing desenhe nosso círculo com a cor que queremos:

cod 15

Agora sim, podemos mudar de cor porque temos uma cor inicial. Para fazer tal mudança criaremos a função mudaCor(), abaixo:

cod 16

tudo que esta função faz é escolher cores de forma aleatória, com valores entre 0 e 255 ( random(0,255) ) para cada um dos tons que compõe o sistema de cores RGB.

Agora tudo que precisamos fazer, é chamar esta função a partir da função click():

cod 17

Pronto, agora só restam alguns detalhes finais!

FINALIZANDO

Bem, agora que a nossa classe “Círculo” está completa, só faltam alguns toques finais para acabarmos o exercício. Abaixo você pode ver as alterações finais:

cod 18

A primeira coisa a se notar é que agora estamos trabalhando não mais com um único objeto circ, e sim com array de objetos circ, e neste array temos 8 objetos. Isto nos força a várias alterações no nosso código.

A primeira alteração está na primeira linha. Antes onde declarávamos apenas um objeto, agora declaramos um array:

Circulo[] circ = new Circulo[8];

Quando declaramos um array, declaramos de forma muito parecida a uma variável comum, com a diferença que colocamos um par de colchetes ao fim do tipo do objeto, Circulo[] circ .Nesta linha ainda completei dizendo a quantidade de objetos que este array irá abrigar, new Circulo[8], neste caso 8 objetos.

Com essa alteração agora temos que nos preocupar com a “chamada dos objetos”, ou seja, agora que estamos trabalhando com vários objetos dentro de um array, temos que construí-los um a um, e também chamar a função exibe(), mover() e click(), de cada um deles. Para facilitar nossa vida usamos loops for.

Observe na função setup(), que foi criado um loop, para construir cada um dos objetos do array. O mesmo acontece na função draw(), para chamar a função exibe() e mover() de cada um dos objetos.

Bem, encerro aqui esse exercício, qualquer dúvida é só postar uma mensagem.

Abras.

Processing, Tutoriais , , , , , , , , ,