terça-feira, 2 de fevereiro de 2016

Knob mudando as imagens

Na aula sobre chroma key, foi pedido que fosse produzido uma aplicação no Processing que simulasse o efeito de um knob, que é um aparelho que faz um efeito de dissolver uma imagem para outra apenas mexendo uma manivela de forma gradual.

Segue abaixo o código comentado com um gif no final demonstrando o efeito.

//variáveis das imagens
PImage img1;
PImage img2;
/*variáveis que irão armazenar o valor RGB de cada uma das imagens que o laço
percorrer*/
float r1, g1, b1, r2, g2, b2;
//variável que irá guardar a posição do pixel da imagem quando percorre o laço
int pos;
//modificadores que irão variar dependendo de mouseY
float a, d;

void setup(){
  size(320, 240);
  img1 = loadImage("original.jpg");
  img2 = loadImage("original2.png");
}

void draw(){
 
  loadPixels();
 
  /*primeira imagem, que terá o "a" como modificador, será uma fração de mouseY em
  relação o tamanho da tela*/
   a = float(mouseY)/height;
   d = 1 - a;
 
  //segunda imagem, o mesmo que foi comentado anteriormente
  d = float(mouseY)/height;
  a = 1 - d;
   /*o laço percorre ambas as imagens, guardando os valores dos respectivos pixels
   em suas variáveis para formar a imagem final*/
   for( int x=0; x<320; x++){
     for(int y=0; y <240; y++){
       pos = y*320 + x;
       //recebimento dos valores RGB da primeira imagem
       r1 = a*red(img1.pixels[pos]);
       g1 = a*green(img1.pixels[pos]);
       b1 = a*blue(img1.pixels[pos]);
     
       //recebimento dos valores RGB da segunda imagem
       r2 = red(img2.pixels[pos])*d;
       g2 = green(img2.pixels[pos])*d;
       b2 = blue(img2.pixels[pos])*d;
       //formação da imagem, dependendo da posição do mouse
       pixels[pos] = color(r1 + r2, g1 + g2, b1 + b2);
     }
   }
 
 
   updatePixels();
}


segunda-feira, 1 de fevereiro de 2016

Trabalho: Parte II

O olho do observador

Na aula de arco tangente, foi pedido para a sala de aula que produzisse uma aplicação no processing que simulasse um olho que seguiria o cursor do mouse.

Para isto, bastava calcular a inclinação que uma reta teria do centro até a posição que está o mouse, depois fazer duas circunferências: uma que represente a parte externa do olho e outra a pupila, que seguiria o cursor do mouse se limitando a ficar dentro da circunferência externa.

Durante a produção deste código, me lembrei do conhecido monstro de Dungeons and Dragons, o Beholder, e resolvi ilustrar o efeito colocando uma figura dele.

Segue o código abaixo comentado.

PImage beholder;
//variável que considera mouseX e o comprimento da tela
float a = 0;
//variável que considera mouseY e a altura da tela
float b = 0;
//variável que armazena o arco tangente
float arctan;



void setup(){
size(600,600);
beholder = loadImage("beholder.jpg");

}


void draw(){
  fill(255);
  background(255);
  //imagem do beholder
  image(beholder, 15, 50);
 
  //circunferência externa
 
  ellipse(width/2, height/2, 150,150);
  noStroke();
  fill(0);
  arctan = atan2(mouseY-height/2, mouseX-width/2);
  if(arctan<0){
    arctan += 2*PI;
  }
 
  a = mouseX - width/2;
  b = mouseY - height/2;
  //distância máxima que a "pupila" percorre
  a = 75*a/300*cos(arctan);
  b = 75*b/300*sin(arctan);
  //circunferência de dentro é feita considerando os quatro quadrantes dela
 
  //primeiro quadrante
 
 
  if(arctan>=0 && arctan<PI/2){
   
  ellipse(width/2 + a, height/2 + b, 25, 25);
 
  //segundo quadrante
  }else if(arctan>=PI/2 && arctan<PI){
   
  ellipse(width/2 - a, height/2 + b, 25, 25);
   //terceiro quadrante
  }else if(arctan>=PI && arctan<3*PI/2){
   
  ellipse(width/2 - a, height/2 - b, 25, 25);
  //quarto quadrante
  }else if(arctan>=3*PI/2 && arctan<2*PI){
   
  ellipse(width/2 + a, height/2 - b, 25, 25);
  }
 
}


Relógio de segundos

Na aula que foi apresentado o conceito de coordenadas polares, foi pedido como tarefa que os alunos produzissem no Processing uma aplicação que demonstrasse ser um relógio de segundos tendo seu ponteiro indicando o tempo correto utilizando a função millis(), a qual é uma função .

Considerando que o ponteiro irá ter sua extremidade percorrendo uma circunferência (o formato do relógio é redondo) e pra cada segundo o ângulo em radianos considerado é 2*PI/60 (referente aos sessenta segundos de um minuto), podemos chamar a função millis() e considerar que, dentro de um laço, enquanto millis (que será iniciado no primeiro frame da animação) dividido por 1000(resultando em um segundo no tempo que se passou) for diferente de 0, a linha será redesenhada em seguida.

Na coordenada X do fim da linha, será considerada o cosseno do ângulo (em radianos) multiplicado pelo tempo(uma variável que é incrementada a cada vez que o código é executado) menos PI/2 (isso é feito porque o ponteiro é iniciado no meio da parte superior da circunferência). Já a coordenada Y é considerado o seno do ângulo sob as mesmas condições já citadas.

Segue abaixo o código comentado.

float tempo = 0;
float ang = 2*PI/60;

void setup(){
size(600,600);
}

void draw(){
  background(255);
  //aqui é esperado um segundo antes do código continuar a ser lido
  while (millis()%1000 != 0){}
  //coloração da circunferência
  stroke(0);
  //circunferência que representa o relógio
  ellipse(width/2, height/2, 400, 400);
  //coloração do ponteiro
  stroke(125, 0, 0);
  //cálculo de onde a linha será desenhada a cada segundo
  line(width/2,height/2,width/2 + 180*cos(tempo*ang - PI/2),height/2 + 180*sin(tempo*ang - PI/2));
  tempo++;
}


Fazer um polígono com qualquer número de lados

Dentre as atividades passadas para serem feitas e postadas neste blog, foi pedido que fosse produzido uma função no Processing que recebesse um número e retornasse um polígono com o número de lados relativo ao número que foi recebido.

Para a produção deste polígono, consideramos como base uma circunferência. Na produção deste polígono, temos que considerar que cada ângulo em radianos formado entre os lados deste polígono é referente a divisão de 2*PI radianos e o número de lados deste polígono.

Em seguida, é feito um laço que produz linhas que conectam os vértices do polígono. Para a coordenada X é considerado o cosseno do ângulo e para a coordenada Y é considerado o seno do ângulo.

O código comentado pode ser visto abaixo.

//raio da circunferência
int raio = 200;
//número de lados do polígono
int lados = 6;

void setup(){
  size(600,600);
  //ângulo do lado interno do polígono
  float ang = 2*PI/lados;
  /*circunferência que serve de base, retire o comentário
  para ver a circunferência ao executar o código*/
  //ellipse(width/2,height/2,2*raio,2*raio);
  //cálculo do local que fica cada vértice do polígono
  for (int i =0;i<lados;i++){
    line(width/2+raio*cos(i*ang),height/2 + raio*sin(i*ang), width/2 + raio*cos((i+1)*ang),height/2 + raio*sin((i+1)*ang));
  }
}


terça-feira, 26 de janeiro de 2016

Média, Desvio Padrão e Eistein

Na aula sobre média e desvio padrão, analisamos a média dos tons de cinza da famosa imagem de Albert Eistein, também aplicando sobre a análise desta média os desvios padrões.

Na atividade passada para ser feita em casa, foi pedido que fossem analisadas essa mesma imagem com variações de brilho e contraste.

Primeiro, vou deixar aqui o código comentado utilizado para isso.

//variável que armazena a imagem
PImage img;
void setup(){
  size(640, 480);
  float t=0, mediaT, somaT=0;
  int pos;
  //carregamento da imagem
  img = loadImage("einstein.jpg");
  //a imagem é percorrida e são pegues os valores vermelhos dos pixels
  for (int x = 0; x < 640; x++){
    for (int y = 0 ; y < 480; y++){
      pos = y * 640 + x;
      t = red(img.pixels[pos]);
      //aqui, são deixados o valores totais somados destes pixels
      somaT = somaT + t;
  }
}

//aqui, é calculada a média destes valores
mediaT = somaT/(640*480);
println("Média de Tons é ", mediaT);

/*aqui, é calculado o desvio padrão a partir da raiz quadrada da variância (armazenada
na variável "v"*/
float v, SomaV = 0;
for (int x = 0; x < 640; x++){
  for (int y = 0; y < 480; y++){
    pos = y * 640 + x;
    t = red(img.pixels[pos]);
    v = pow(t - mediaT, 2);
    SomaV = SomaV + sqrt(v);
  }
}
//desvio padrão
float media = SomaV/(640*480);
println(media);

}

void draw(){
  image(img, 0, 0);
}

Nas imagens com níveis diferentes de brilho e contraste havia uma alteração significativa nos valores da média e desvio padrão. Quanto maior o brilho, maior o desvio padrão, o que é refletido pelo maior valor que um brilho maior dá para os pixels que compõem a imagem.

Barco Seno

A função seno consiste na projeção do deslocamento de um ponto no eixo y do gráfico, variando de -1 a 1. Um exemplo disso pode ser verificado no gif abaixo:


Na atividade relativa a essa aula, foi pedido a turma que fosse feita uma aplicação no processing que consistisse de um barco navegando no mar e seu movimento fosse correspondente a função seno.

Segue abaixo o código comentado com um gif ilustrando o resultado:

/*variáveis que armazenam as imagens do barco, do céu(metade de cima da imagem
e do mar(metade de baixo da imagem)*/
PImage barquinho, ceu, mar;

void setup(){
  size(800, 600);
  barquinho = loadImage("barquinho.png");
  ceu = loadImage("ceu.png");
  mar = loadImage("mar.png");
 
  noStroke();
}

float x = 0;
void draw(){
  background(255);
  //eixo y irá pegar o seno do eixo x, causando a variação na altura do barco
  float y = sin(x);
  //o eixo x será incrementado, para haver o deslocamento horizontal do barco
  x+= 0.1;
  //para ficar mais aparente, o eixo y tem seu valor multiplicado em 10 vezes
  y = y*10;
 
  image(ceu, 0, 0);
  /*o barco tem o deslocamento aumentado em 30 vezes no eixo horizontal para
  dar a impressão de ter uma navegação no mar de forma mais "realista", enquanto que
  o eixo y foi adicionado em 90 para que ele fique num ponto que seja mais coerente
  com a imagem*/
  image(barquinho, x*30, y+90);
  image(mar, 0, 300);
 

 
 
}