Construção de interfaces on-demand baseadas em Realidade Aumentada Projetiva para Controle de...

Post on 25-Jul-2015

118 views 4 download

Transcript of Construção de interfaces on-demand baseadas em Realidade Aumentada Projetiva para Controle de...

RA on-demand Criando interfaces em tempo de execução.

08

:38

fb

.co

m/R

VA

.BR

2

Construção de interfaces on-demand baseadas em Realidade Aumentada Projetiva para Controle de Hardware (Arduino)

Drª. Ana Maria Ambrosio

MSc. Christopher Cerqueira

aluno doutorado

Dr. Claudio Kirner

Objetivo do Capítulo

SketchSynth

BackStage

08

:38

fb

.co

m/R

VA

.BR

4

Objetivo da Apresentação

08

:38

fb

.co

m/R

VA

.BR

5

Objetivo da apresentação

• Devido as restrições, vamos montar uma versão simplificada:

• Ausência de projetores para todos os alunos

• Ausência de ARDUINO para todos os alunos

• Mostrar um framework para construção de apps de RA / RC.

• openFrameworks

• Mostrar os recursos de controle de hardware (Arduino)

• Mostrar os recursos de CV (openCV): rastreio de contorno (infraestrutura e controles) e processamento de imagem (mão).

• Mostrar tipos comuns para criação de interface.

• openFrameworks

• Aplicações tipo interação em mesa. (Projeção)

08

:38

fb

.co

m/R

VA

.BR

6

Agenda:

• Conceito e openFramework

• Criando o primeiro programa em openFrameworks

• Conectando com o Arduino

• Estudos de caso / Construção do ambiente (exemplos):

• 1. Detectar infraestrutura (Apenas rastreio do papel)

• 2. Rastreio do atuador (rastreio da mão)

• 3. Interação com estrutura virtual

• 4. Detectar estrutura física on-demand (sem reprojeção)

• Wrap-Up

3 horas

1,5h

1,5h

08

:38

fb

.co

m/R

VA

.BR

7

Conteúdo está em

•http://www.4shared.com/folder/XkaUh0KM/Resources.html

• Link tá muito difícil??? Vai em

cscerqueira.com.br

08

:38

fb

.co

m/R

VA

.BR

8

CONCEITOS

Básico - Experiências

08

:38

fb

.co

m/R

VA

.BR

9

“The product is no longer the basis of value. The

experience is.”

Venkat Ramaswamy

The Future of Competition

08

:38

fb

.co

m/R

VA

.BR

10

Valor de uma boa experiência

08

:38

fb

.co

m/R

VA

.BR

11

Interação

Texto, som, cores, visual, mecânico ou

físico.

Interface

Mensagens

Usuário Sistema 08

:38

fb

.co

m/R

VA

.BR

12

Usabilidade

08

:38

fb

.co

m/R

VA

.BR

13

Exemplo:

• Usabilidade:

1. Facilidade de aprendizado

2. Eficiência

3. Facilidade de memorização

4. Erros

5. Satisfação subjetiva

Meta-Mensagens

Usuário Sistema

08

:38

fb

.co

m/R

VA

.BR

14

3 níveis

Lógico: Resolvem, solucionam, facilitam.

Emocional: Satisfazem necessidades e desejos afetivos.

Visceral: resolvem questões fundamentais, sem consciência. Impulso.

08

:38

fb

.co

m/R

VA

.BR

15

Espera.... Visceral?

08

:38

fb

.co

m/R

VA

.BR

16

08

:38

fb

.co

m/R

VA

.BR

17

Realidades – Realidade Virtual

interface que permite ao

usuário interagir, em tempo real,

com um mundo tridimensional gerado por

computador, usando seus

sentidos através de

equipamentos especiais.

SOURCE: NASA (2013a)

08

:38

18

fb.c

om

/RV

A.B

R

Billinghurst Vision

08

:38

fb

.co

m/R

VA

.BR

19

Realidades – Realidade Aumentada

uma interface baseada na

sobreposição de informações virtuais geradas por computador (envolvendo imagens estáticas e dinâmicas, sons

espaciais e sensações hápticas) com o ambiente físico do usuário, percebida através de dispositivos tecnológicos e

usando as interações naturais do usuário, no mundo físico.

Claudio Kirner

SOURCE: Adapted from ESA (2009) and Capua (2008)

08

:38

20

fb.c

om

/RV

A.B

R

Christopher Vision

Informação virtual

Interação Natural

dispositivos tecnológicos

08

:38

21

fb.c

om

/RV

A.B

R

Realidades – Realidade Cruzada

é um ambiente de realidade misturada ubíqua, que vem da fusão de uma rede de sensores e atuadores

(que coletam e enviam dados relacionados ao mundo real) com mundos virtuais compartilhados,

usando a interface da realidade aumentada.

Claudio Kirner

Intr

od

uçã

o

08

:38

fb

.co

m/R

VA

.BR

22

Kirner’s Diagram – elementos

Source: (KIRNER et al., 2012)

Lego

Cave

08

:38

fb

.co

m/R

VA

.BR

23

Realidade Cruzada

Objetos reais

Sensores e Atuadores

Realidade Aumentada

OC

R

NO

CR

NO

CR

Intr

od

uçã

o

08

:38

fb

.co

m/R

VA

.BR

24

HIT - ROADMAP

CR AI

HI

AR

IoT HR

KMatsuda

08

:38

fb

.co

m/R

VA

.BR

25

[ ] Hololens

• Talvez o primeiro hardware de RA, com sobreposição, que entra com força no mercado.

• Google Glass tentou, mas na maioria dos apps não tinha sobreposição intrínseca.

• Vídeo 1

08

:38

fb

.co

m/R

VA

.BR

26

Qual o motivo de RA ainda não ter pego em atividades de engenharia?

HWs de interação?

HWs de visualização?

Frameworks de rastreio

SWs

Frameworks geo-localizados

Frameworks de interação

08

:38

fb

.co

m/R

VA

.BR

27

Um dos motivos ao nosso ver é:

• Dificuldade de criação e manipulação de uma interface

de RA a medida que é utilizada.

• Poderíamos então pensar em uma estratégia, de criação

de uma interface física e indicar sua camada virtual a medida que é necessário (on-demand) e a função desejada.

• Esses minicurso essencialmente é para mostrar uma opção de criação de interface em RA on demand.

• “Solução simplificada: openFrameworks + visão computacional.”

08

:38

fb

.co

m/R

VA

.BR

28

OPENFRAMEWORKS

08

:38

fb

.co

m/R

VA

.BR

29

Processing

Adobe Flash

Unity

Cinder

openFrameworks

08

:38

fb

.co

m/R

VA

.BR

30

oF

• Criado para artistas e designers • Desenvolvido por: Zach Liberman, Theo Watson, Artuno

Castro e Chris O’Shea

•Proposta: Arrumar a falta de comunicação entre

diversas bibliotecas em C++, e permitir portabilidade.

• Escrita em C++

• Licença: MIT (educacional e venda)

• Usar quando:

• O projeto renderiza muitos gráficos 3D, e/ou;

• Utilizar muita visão computacional, e/ou;

• Controlar equipamentos, como, por exemplo:

• o ARDUINO.

08

:38

fb

.co

m/R

VA

.BR

32

33

08

:38

fb

.co

m/R

VA

.BR

C++ Portável!!!!

34

08

:38

fb

.co

m/R

VA

.BR

Página Principal – openframeworks.cc

08

:38

fb

.co

m/R

VA

.BR

35

Libs no pacote padrão

• OpenGL, GLEW, GLUT, libtess2 e cairo para gráficos.

• rtAudio, PortAudio ou FMOD e Kiss FFT para entrada, saída e análise de áudio.

• FreeType para fontes.

• FreeImage para salvar e carregar imagens.

• Quicktime e videoInput para playback e aquisição de vídeo.

• Poco, que contém uma variedade de utilidades.

08

:38

fb

.co

m/R

VA

.BR

36

Addons da comunidade: ofxaddons.com

08

:38

fb

.co

m/R

VA

.BR

37

OSX, Linux, Windows, iOS, Android, Linux ARM

08

:38

fb

.co

m/R

VA

.BR

38

ERA TROGLODITA (C++)

• Graduação (2010): • ARToolKit

• PTAMM

• Bolsista DTI (2011): • basAR

ERA DO FOGO (C++/oF)

• Mestrado (2012):

• Doutorado (2014):

08

:38

fb

.co

m/R

VA

.BR

39

MDE (Model Driven Engineering) MBSE (Model Based System Engineering)

• MDE é um conjunto de práticas de engenharia, baseadas em ferramentas que utilizam ao mesmo tempo meta-modelagem e transformações de modelos para atingirem automaticamente objetivos em produção, manutenção ou operação de sistemas intensivos em software.

40

Motivador - Matlab

08

:38

fb

.co

m/R

VA

.BR

Três tipos principais de aplicações MDE

MDE

Geração automática Descoberta do Modelo Interoperabilidade de sistemas

41

Um modelo pode ser transformado em outro modelo.

Um meta-modelo é um conjunto de conceitos e relações que o modelo pode realizar. “Filtro” de possibilidade.

Uma representação gera um conjunto de elementos.

08

:38

fb

.co

m/R

VA

.BR

MDE Natural Env.

08

:38

fb

.co

m/R

VA

.BR

42

• Introdução à utilização de openFrameworks para o desenvolvimento de aplicações de RVA

Link

• Construção de aplicações de Realidade Cruzada Projetiva utilizando openFrameworks e ARDUINO

Link

• Utilização de Realidade Aumentada, com marcadores(ARToolKitPlus) e outros (utilizando openCV), para controle e inspeção de hardware, utilizando a interface ARDUINO.

Link

08

:38

fb

.co

m/R

VA

.BR

43

SVR2013 - Resultados

44

08

:38

fb

.co

m/R

VA

.BR

SVR2014 - Resultados

08

:38

45

fb.c

om

/RV

A.B

R

WRVA2014 - Resultados

08

:38

fb

.co

m/R

VA

.BR

46

PRIMEIRO PROGRAMA EM OF

Vou pular, coloquei aqui para ficar + completo

08

:38

fb

.co

m/R

VA

.BR

47

Onde encontrar?

08

:38

fb

.co

m/R

VA

.BR

48

Level Easy: Gerador Automático

49

08

:38

fb

.co

m/R

VA

.BR

Escolhendo expansões

50

Do

co

re o

F

Da

com

un

idad

e

08

:38

fb

.co

m/R

VA

.BR

Estrutura do projeto

08

:38

fb

.co

m/R

VA

.BR

51

Exemplo básico

08

:38

fb

.co

m/R

VA

.BR

52

// ofApp.cpp

void ofApp::setup(){

mensagem = "Hello SVR2015!!!";

raio = 0;

}

void ofApp::draw(){

ofEnableAlphaBlending(); ofSetColor(ofColor::blue,128);

ofCircle(x_i,y_i,raio);

ofSetColor(ofColor::red);

ofDrawBitmapString(mensagem,mouseX,mouseY);

}

// ofApp.cpp

void ofApp::mouseDragged(int x, int y, int button){

raio = ofDist(x_i,y_i,x,y);

}

void ofApp::mousePressed(int x, int y, int button){

x_i = x;

y_i = y;

}

void ofApp::mouseReleased(int x, int y, int button){

raio = ofDist(x_i,y_i,x,y);

}

// ofApp.h

...

string mensagem;

int x_i,y_i;

float raio;

...

ARDUINO

O que é? Onde vivem?

Existe? Hoje no Glob..

Fritzing, Arduino 1.0, Firmata, exemplo openFrameworks

08

:38

fb

.co

m/R

VA

.BR

53

O que tem no ARDUINO?

08

:38

54

fb.c

om

/RV

A.B

R

Outras versões

08

:38

55

fb.c

om

/RV

A.B

R

Shields

08

:38

56

fb.c

om

/RV

A.B

R

FIRMATA

Literatura indica FIRMATA: http://firmata.org/wiki/Download

08

:38

57

fb.c

om

/RV

A.B

R

O que a FIRMATA faz!?

• Transforma o ARDUINO numa interface de controle, podendo ser modificado por um host.

• Quais as vantagens?

• O host controla a execução!

• O host tem mais memória.

• O host resolve as lógicas de controle muito mais rápido.

• Desvantagens?!

• Tem que ficar atrelado ao host!

08

:38

58

fb.c

om

/RV

A.B

R

Obs.: Mudança da nomenclatura dos pinos após Firmata 2.3 (Arduino 1.0) Tomar cuidado na hora de desenvolver!!!!!!!!!!

08

:38

fb

.co

m/R

VA

.BR

59

Instalando a Firmata no Arduino • Faça download do

Arduino 1.0.6 http://arduino.cc/en/Main/Software

• Abra o sketch do Firmata Standard.

• Transfira para a board.

08

:38

fb

.co

m/R

VA

.BR

60

http://arduino.cc/en/reference/firmata

“esquemático”

08

:38

61

fb.c

om

/RV

A.B

R

• #crashcourse fritzing

• http://fritzing.org/home/

Arduino e openFrameworks

08

:38

fb

.co

m/R

VA

.BR

62

Métodos para conectar com o ARDUINO connect()

disconnect()

getAnalog()

getAnalogPinReporting()

getDigital()

getDigitalPinMode()

getPwm()

getString()

isArduinoReady()

isInitialized()

sendAnalogPinReporting()

sendByte()

sendDigital()

sendDigitalPinMode()

sendPwm()

sendReset()

sendString()

setUseDelay()

update()

08

:38

63

fb.c

om

/RV

A.B

R

Código no openFrameworks

• Exploração do exemplo: communicationfirmataExample

08

:38

fb

.co

m/R

VA

.BR

64

Fluxograma básico

08

:38

fb

.co

m/R

VA

.BR

65

SETUP Habilita callback de Arduino Alive

Arduino Responde Evento

Alive

Configura Arduino

Loop de execução – sem Arduino

Enviar comandos pro Arduino

Recebeu um evento Digital

Recebeu um evento Analógico

Loop de execução – Arduino Update

Código

08

:38

fb

.co

m/R

VA

.BR

66

//ofApp.h #pragma once #include "ofMain.h" class ofApp : public ofBaseApp{ public: … ofArduino ard; bool bSetupArduino; private: void setupArduino(const int & version); void digitalPinChanged(const int & pinNum); void analogPinChanged(const int & pinNum); void updateArduino(); };

//ofApp.cpp void ofApp::setup(){ ... ard.connect("COM3", 57600); //conecta com arduino ofAddListener(ard.EInitialized, this, &ofApp::setupArduino); bSetupArduino= false;// flag arduino ok }

void ofApp::setupArduino(const int & version) { ofRemoveListener(ard.EInitialized, this, &ofApp::setupArduino); bSetupArduino = true; // agora pode usar o arduino. ard.sendDigitalPinMode(2, ARD_INPUT); //pino entrada digital ard.sendAnalogPinReporting(0, ARD_ANALOG); // pino entrada analógica ard.sendDigitalPinMode(13, ARD_OUTPUT); // configura pino saída digital ard.sendDigitalPinMode(11, ARD_PWM); // configura pino saída PWM ard.sendServoAttach(9); // diz que o pino tem um servo. ofAddListener(ard.EDigitalPinChanged, this, &ofApp::digitalPinChanged); //callback para eventos de pino digital. ofAddListener(ard.EAnalogPinChanged, this, &ofApp::analogPinChanged); //callback para eventos de pino analógico }

void ofApp::updateArduino(){ ard.update(); // verifica se algo mudou no Arduino - obrigatório if (bSetupArduino) { //envia o que for para o Arduino. ard.sendPwm(11, (int)(128 + 128 * sin(ofGetElapsedTimef()))); // pwm... } }

//ofApp.cpp void ofApp::digitalPinChanged(const int & pinNum) { // trata o pino digital - ard.getDigital(pinNum) } void ofApp::analogPinChanged(const int & pinNum) { // trata o pino analógico - ard.getAnalog(pinNum) }

//outros comandos ard.sendServo(9, 180, false); ard.sendDigital(8, ARD_HIGH);

ESTUDO DE CASOS:

08

:38

fb

.co

m/R

VA

.BR

67

Casos

• 0.a. O que vamos fazer:

• 1. Detecção de infraestrutura (contornos)

• 2. Detecção de atuador (diferença de imagens)

• 3. Interação mão / virtual / Arduino

• 4. Rastreio dos controles. (contornos)

• Real (Drawn) e Virtual Matching

08

:38

fb

.co

m/R

VA

.BR

68

0.a. O que vamos fazer:

Ambiente reativo à altura da areia

Ambiente reativo ao comportamento dos

pontos (soldados)

08

:38

fb

.co

m/R

VA

.BR

70

Conceito de ambiente dividido em pontos e camadas

08

:38

fb

.co

m/R

VA

.BR

71

Diagrama de etapas

08

:38

fb

.co

m/R

VA

.BR

72

O que vamos usar para o exemplo

08

:38

fb

.co

m/R

VA

.BR

73

Só use mais hardware quando realmente precisar.

08

:38

fb

.co

m/R

VA

.BR

74

DETECTING INFRASTRUCTURE

Encontrando uma folha de papel para servir de referência

para a montagem dos elementos de

interação.

08

:38

fb

.co

m/R

VA

.BR

75

Detectar a infraestrutura

Capturar Imagem

Procurar “coisas” brancas

Identificar polígono

• Maior de todos?

é um retângulo?

Encontrei a infraestrutura

Retirar a imagem da área

ide interação

08

:38

fb

.co

m/R

VA

.BR

76

Exemplo: Rastreio de Marcador

08

:38

fb

.co

m/R

VA

.BR

77

USANDO O OPENCV

Cores, blobs e exemplos

08

:38

fb

.co

m/R

VA

.BR

78

Cores

RGB-A (red, green, blue)-alfa HSV (hue (cor), saturation, value)

08

:38

79

fb.c

om

/RV

A.B

R

Blobs

• Método de busca de características.

• Blobs compartilham propriedades constantes que podem ser “percebidas” na imagem.

08

:38

80

fb.c

om

/RV

A.B

R

Construção dos artefatos : Rastreio Cores

08

:38

81

fb.c

om

/RV

A.B

R

Bonus: Projection Mapping

08

:38

fb

.co

m/R

VA

.BR

82

PM

PM

Usos

• Table-tops

• Projeções em paredes

08

:38

83

fb.c

om

/RV

A.B

R

Sensetable

L.A.S.E.R. Tag

Climbing

OASIS

Continuando ....

Usando o addon: ofxCv de Kyle McDonald https://github.com/kylemcdonald/ofxCv

08

:38

fb

.co

m/R

VA

.BR

84

Tipo: ofxCv::ContourFinder

• Tipo/função que procura blobs numa imagem.

• Retorna os blobs e características:

• Posição

• Contorno

• Centroide, média centro, pontos das bordas, menor retângulo contornável, menor elipse, etc etc etc...

08

:38

fb

.co

m/R

VA

.BR

85

Project Generator addons

08

:38

fb

.co

m/R

VA

.BR

86

// Camera:

ofVideoGrabber cam; // Video Tracking source

int camHeight;

int camWidth;

ofImage unwarped; // RAW image from camera

// Descobridor de papel

ofxCv::ContourFinder contourFinder;

int thresholdCV;

ofPolyline contour;

ofImage warpedPaper;

bool foundInfra;

// ## Função para retornar tipo de forma geométrica

private:

string findForm(const ofPolyline &poly);

template <class T>

string findForm(const T &poly){

return findForm(ofxCv::toOf(poly)); }

};

Câmera

Procurador de papel

08

:38

fb

.co

m/R

VA

.BR

87

Identificar Formas Convexas

• Entrada: número de vértices

• 3 vértices = TRIANGULO

• 4 vértices e cos +/- 0 = RETÂNGULO

• 5 vértices e cos +/- 0.3 = PENTÁGONO

• 6 vértices e cos +/- 0.5 = HEXÁGONO

• > 6 Círculo

• http://opencv-code.com/tutorials/detecting-simple-shapes-in-an-image/ • https://github.com/bsdnoobz/opencv-code/blob/master/shape-detect.cpp

08

:38

fb

.co

m/R

VA

.BR

88

string ofApp::findForm(const ofPolyline &poly){

vector<ofPoint> corners = poly.getVertices(); // pega todos os vértices

if ( corners.size() == 3) return "TRIANGLE";

if ( corners.size() >= 4 && corners.size() <= 6){ // de 4 a 6 vertices

int vtc = corners.size();

vector<double> cos;

for( int j = 2; j < vtc+1; j++) // mandrakaria para organizar cosenos

cos.push_back(angle(corners[j%vtc], corners[j-2], corners[j-1]));

sort(cos.begin(),cos.end());

double minCos = cos.front();

double maxCos = cos.back();

if( vtc == 4 && minCos >= -0.1 && maxCos <= 0.3) {

cv::Rect r = cv::boundingRect(toCv(poly));

double ratio = std::abs(1 - (double)r.width / r.height);

return (ratio <= 0.02) ? "SQUARE" : "RECTANGLE"; }

if( vtc == 5 && minCos >= -0.34 && maxCos <= -0.27) return "PENTAGON";

if( vtc == 6 && minCos >= -0.55 && maxCos <= 0.45) return "HEXAGON";

} else { // testar se circulo }

return "NO_MATCH";}

08

:38

fb

.co

m/R

VA

.BR

89

static double angle(ofPoint pt1, ofPoint pt2, ofPoint pt0)

{

double dx1 = pt1.x - pt0.x;

double dy1 = pt1.y - pt0.y;

double dx2 = pt2.x - pt0.x;

double dy2 = pt2.y - pt0.y;

return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 +

dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);

}

08

:38

fb

.co

m/R

VA

.BR

90

void ofApp::setup(){ // Parte 2 - Código do Exemplo ofLogNotice("[PAPER DETECTOR]") << " Configure CV "; contourFinder.setMinAreaRadius(10); // configura menor área . contourFinder.setMaxAreaRadius(200); // configura maior área thresholdCV = 100; // inicializa o nível da camera. //contourFinder.setTargetColor(targetColor, trackingColorMode); // configura cor / padrão contourFinder.setThreshold(thresholdCV); // configura nível ofLogNotice("[PAPER DETECTOR]") << " Configure Camera "; camWidth = 640; camHeight = 480; cam.initGrabber(camWidth,camHeight); cam.listDevices(); unwarped.allocate(camWidth, camHeight, OF_IMAGE_COLOR); // // ALLOCATE RAW IMAGE warpedPaper.allocate(camWidth,camHeight,OF_IMAGE_COLOR); }

08

:38

fb

.co

m/R

VA

.BR

91

void ofApp::update(){ cam.update(); float area; if(cam.isFrameNew()){ //ofLogNotice("[PAPER DETECTOR]") << "New Frame"; vector<cv::Point> maxQuad;//maior quadrado na imagem = folha de papel. float maxArea = -numeric_limits<float>::infinity();//escolhe pela maior área. contourFinder.findContours(cam); // realiza a procura por folhas brancas em um fundo preto int n = contourFinder.size(); for(int i = 0; i < n; i++){ //ofLogNotice("[PAPER DETECTOR]") << "update: " + ofToString(i); ofPolyline minAreRect = toOf(contourFinder.getMinAreaRect(i)); vector<cv::Point> quad = contourFinder.getFitQuad(i); area = contourFinder.getContourArea(i); //encontrar o maior quadrado na imagem = folha de papel. if (area > maxArea) { //ofLogNotice("[PAPER DETECTOR]") << "1. " + ofToString(area) + " - " + ofToString(maxArea); maxArea = area; maxQuad = quad; } }

08

:38

fb

.co

m/R

VA

.BR

92

// teste se foi encontrado algo parecido com um retângulo. this->foundInfra = false; if ( this->findForm(maxQuad) == "RECTANGLE"){ this->foundInfra = true; // warp paper vector<Point2f> warpPoints; warpPoints.push_back(maxQuad[3]); // para organizar a ordem dos pontos. warpPoints.push_back(maxQuad[0]); warpPoints.push_back(maxQuad[1]); warpPoints.push_back(maxQuad[2]); //copy(maxQuad.begin(), maxQuad.end(), back_inserter(warpPoints)); unwarpPerspective(cam, unwarped, warpPoints); unwarped.update(); } //ofLogNotice("[PAPER DETECTOR]") << "2. " + ofToString(area) + " - " + ofToString(maxArea) + " - " + ofToString(this->foundInfra); } }

08

:38

fb

.co

m/R

VA

.BR

93

void ofApp::draw(){ ofSetColor(ofColor::white); cam.draw(0,0); ofNoFill(); int n = contourFinder.size(); for(int i = 0; i < n; i++) { ofSetColor(ofColor::red); // smallest rectangle that fits the contour ofPolyline minAreRect = toOf(contourFinder.getMinAreaRect(i)); minAreRect.draw(); ofSetColor(yellowPrint); // convex hull of the contour ofPolyline convexHull = toOf(contourFinder.getConvexHull(i)); convexHull.draw(); ofSetColor(cyanPrint); vector<cv::Point> quad = contourFinder.getFitQuad(i); vector<cv::Point>::iterator it; for (it = quad.begin(); it != quad.end(); it++) ofCircle(toOf(*it),3); } ofSetColor(255); unwarped.draw(640, 0); if(this->foundInfra){ ofDrawBitmapStringHighlight("Found infra",10,ofGetHeight() - 80);} ofDrawBitmapStringHighlight(ofToString(this->thresholdCV),10,ofGetHeight() - 100); }

08

:38

fb

.co

m/R

VA

.BR

94

Resultado Esperado

08

:38

fb

.co

m/R

VA

.BR

95

WHERE IS MY HAND? DETECTING THE ACTUATOR

Detectando a mão, caneta, ou qualquer outra coisa (medo) que você queira

usar para fazer interação.

08

:38

fb

.co

m/R

VA

.BR

96

Rastrear mão (apontador 2D)

• Restrições (para facilitar)

Fundo homogêneo

Longe das quinas

Uma mão só

• Pseudo-código

• Fazer diferença entra o fundo e o frame atual para encontrar a mão.

• Com a diferença rastreia o blob.

• Do blob calcula as quinas

• Das quinas pega a mais distante do centroide e que não seja próximo das quinas ( braço).

08

:38

fb

.co

m/R

VA

.BR

97

Lets code.... Babe!!!! #include "ofMain.h"

#include "ofxOpenCv.h" //Cabeçalho do OpenCV

#include "ofxCv.h"

class ofApp : public ofBaseApp{

...

int width, height, threshold;

ofVideoGrabber vidGrabber; // Componente do oF que pega a câmera.

ofxCvColorImage colorImage; // imagem capturada pela câmera

ofxCvGrayscaleImage grayBg, grayImage, grayDiff;// bg, cinza, diferença

bool bLearnBackground;

ofxCv::TrackingColorMode trackingColorMode;

ofxCv::ContourFinder contourFinder;

ofColor targetColor;

ofPoint apontador;

ofPoint encontraPontoMaisDistante();

};

08

:38

fb

.co

m/R

VA

.BR

98

Tipo: ofPoint

• ofPoint é um tipo muito utilizado no openFrameworks que

faz as vezes de um ponto na área da janela.

• Com ele podemos posicionar pontos na área da janela.

• Essencialmente é um vetor X,Y,Z. Herda de ofVec3f

• Possui propriedades sobrecarregadas de operação de vetores.

08

:38

fb

.co

m/R

VA

.BR

99

Setup void ofApp::setup(){

width = 320; height = 240;

vidGrabber.initGrabber(width, height); //abre câmera

colorImage.allocate(width,height); //aloca memória para as imagens

grayBg.allocate(width,height);

grayImage.allocate(width,height);

grayDiff.allocate(width,height);

contourFinder.setMinAreaRadius(10); //configura rastreador

contourFinder.setMaxAreaRadius(150);

contourFinder.setTargetColor(ofColor::white, TRACK_COLOR_RGB);

threshold = 50;

bLearnBakground = true;

}

08

:38

fb

.co

m/R

VA

.BR

100

Comparando imagens

08

:38

fb

.co

m/R

VA

.BR

101

Update void ofApp::update(){

vidGrabber.update(); // Pega frame da câmera

if(vidGrabber.isFrameNew()){ // é um frame novo ???

colorImage.setFromPixels(vidGrabber.getPixels(),width,height);

grayImage = colorImage;

if (bLearnBackground == true){

grayBg = grayImage;// salva o fundo da tela - TO ROUBANDO MESMO!

bLearnBackground = false;}

grayDiff.absDiff(grayBg, grayImage); // fazer fundo x atual

grayDiff.threshold(threshold);

contourFinder.setThreshold(threshold); // procurar blobs no atual

contourFinder.findContours(grayDiff);

apontador = encontraPontoMaisDistante(); // procurar “dedo”

}

}

08

:38

fb

.co

m/R

VA

.BR

102

Marcando dedos (pontos distantes)

08

:38

fb

.co

m/R

VA

.BR

103

Ponto mais distante – p1

ofPoint ofApp::encontraPontoMaisDistante(){

int n = contourFinder.size(); //qtidade de blobs capturados

ofPoint maisDistante ; //nosso ponto mais distante

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

ofVec2f centroid = toOf(contourFinder.getCentroid(i)); //Centroide;

ofPolyline convexHull = toOf(contourFinder.getConvexHull(i)); //quinas;

vector<ofPoint> vertices = convexHull.getVertices(); // vetorDeQuinas

vector<ofPoint>::iterator itVec; // para percorrer as quinas.

maisDistante = (*vertices.begin());

float tamMaisDistante = centroid.distanceSquared(maisDistante);

float distanciaAtual = 0;

08

:38

fb

.co

m/R

VA

.BR

104

Ponto mais distante – p2

for(itVec = vertices.begin(); itVec != vertices.end(); itVec++){

//encontrar ponto mais distante do dedo --> eliminar as bordas

if( ((*itVec).x > 40) && ((*itVec).x < width - 40) &&

((*itVec).y > 40) && ((*itVec).y < height - 40)){ //elimina bordas

distanciaAtual = centroid.distanceSquared((*itVec));

if(distanciaAtual > tamMaisDistante){ //maior “simple as possible”

maisDistante = (*itVec);

tamMaisDistante = distanciaAtual;

}

}

}

}

return maisDistante;

}

08

:38

fb

.co

m/R

VA

.BR

105

Draw

void ofApp::draw(){

ofSetColor(255); grayImage.draw(0, 0); // desenha câmera

ofTranslate(320, 0); grayDiff.draw(0, 0); // desenha threshold

ofTranslate(-320,240); contourFinder.draw(); //desenha contorno encontrado

ofSetColor(ofColor::hotPink);

ofDrawBitmapString("openCV Threshold: " + ofToString(threshold),50,50);

ofTranslate(0,-240);

ofFill();

ofSetColor(ofColor::green);

ofCircle(apontador,5); //desenha bola verde no “dedo”

}

08

:38

fb

.co

m/R

VA

.BR

106

Resultado desejado:

08

:38

fb

.co

m/R

VA

.BR

107

PLAYING IN THE AIR!

Interagindo em elementos virtuais com a mão.

08

:38

fb

.co

m/R

VA

.BR

108

Definindo um conjunto de ações • Assunto: Controlar um Arduino • Ações:

• Acender e Apagar um LED via Arduino, com replicação virtual, via botão físico e botão virtual.

• Controlar um servo motor a partir de uma barra virtual.

Dica: Esse é um bom algoritmo para fazer o debounce do toque: http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html

08

:38

fb

.co

m/R

VA

.BR

109

Espalhando controles virtuais pela área capturada pela câmera

• 1º Projeto de Interface (livre em toda a área)

“É você Google Glass? É voce Hololens?” (Clotilde, 1985)

08

:38

fb

.co

m/R

VA

.BR

110

Tipo: ofRectangle

• Tipo que define um retângulo na tela.

• Retângulos são muito usados para definir áreas de toque. (Forma mais simples)

• O tipo ofRectangle possui:

• X,Y,(Z) do canto superior esquerdo (Referência)

• Height, Width

• Operadores sobrecarregados

• Varias funções de posicionamento

• Adição, crescimento para englobar outros, etc etc etc.

08

:38

fb

.co

m/R

VA

.BR

111

Some code... (testar toques? inside() )

ofRectangle controleServo;

ofRectangle chaveOff;

ofRectangle chaveOn;

ofPoint LEDIndicativo;

ofColor ledColor;

bool ledStatus;

// Configurar posição dos

elementos da interface

controleServo.set(30,85,40,140);

chaveOff.set(197,160,40,40);

chaveOn.set(237,160,40,40);

LEDIndicativo.set(160,50);

if( this->controleServo.inside(dedo) ) {

// trata para controle doservo}

if( this->chaveOn.inside(dedo)) {

// trata evento do botão On}

if( this->chaveOff.inside(dedo)) {

// trata evento do botão Off}

ofApp.h ofApp.cpp – setup()

ofApp.cpp – update()

08

:38

fb

.co

m/R

VA

.BR

112

Resultado desejado

08

:38

fb

.co

m/R

VA

.BR

113

Adicionando comandos e leitura do Arduino

// Setup Arduino() ard.sendDigitalPinMode(2, ARD_INPUT); // led do exemplo ard.sendDigitalPinMode(11, ARD_OUTPUT); // botão ard.sendServoAttach(9); // servo ofAddListener(ard.EDigitalPinChanged, this, &ofApp::digitalPinChanged);

void ofApp::digitalPinChanged(const int & pinNum) { this->ledStatus = ard.getDigital(pinNum); if ( this->ledStatus == true){ ard.sendDigital(11,ARD_HIGH); } else { ard.sendDigital(11,ARD_LOW); } }

08

:38

fb

.co

m/R

VA

.BR

114

bool ofApp::updateInterface(ofPoint dedo){ if( this->controleServo.inside(dedo) ) { // trata evento com servo // |controleServo.y ----- dedo.y ---- controleServo.y + controleServo.height| // |0 --------------------- y --------------------------- 180 | positionServo = (int) (dedo.y - controleServo.y)*180/controleServo.height; ard.sendServo(9, positionServo, false); } if( this->chaveOn.inside(dedo)) { // trata evento com botão On ledStatus = 1; ard.sendDigital(11,ARD_HIGH); // envia comando pro arduino } if( this->chaveOff.inside(dedo)) { // trata evento com botão Off ledStatus = 0; ard.sendDigital(11,ARD_LOW); //envia comando para o arduino } // pega dado do status do led this->ledStatus == 1 ? this->ledColor = ofColor::green : this->ledColor = ofColor::white; return true; }

08

:38

fb

.co

m/R

VA

.BR

115

TRACKING PHYSICAL CONTROLS. THINGS ARE GETING REAL

Rastreando controles desenhados na infraestrutura

08

:38

fb

.co

m/R

VA

.BR

116

*Versão projetada

08

:38

fb

.co

m/R

VA

.BR

117

Pseudo Código

• Encontrada a infraestrutura:

• Update:

1. Processar imagem

2. Procurar controles 1. Procurar tipo Slide

2. Procurar tipo Switch

3. Procurar tipo Button

3. Tendo os controles 1. Associar um controle a uma função predefinida de uma paleta de

controles

• Draw:

1. Desenhar paleta de funções num canto da infraestrutura

2. Desenhar controles encontrados (Forma e status) 1. Ajustar ponto de vista!!! (mesmo usando vista superior, em caso de

projeção é necessário corrigir, pois câmera e projetor não estão no mesmo ponto)

08

:38

fb

.co

m/R

VA

.BR

118

Processamento de Imagem

Infra

08

:38

fb

.co

m/R

VA

.BR

119

Etapas do processamento

2. Canny

3. Dilate

4. Erode

6. contourFinder

infra 08

:38

fb

.co

m/R

VA

.BR

120

No “ofApp.h” // Controles ofxCv::ContourFindercontrolFinder; booldoControlDetection; // auxiliares para forçar as imagens: cv::Mat grayImg; cv::Mat canny; cv::Mat eroded; cv::Mat dilated; cv::Mat edgesInput; cv::Mat edges; int BORDER; float ALPHA; vector<Controle> listaDeControles; voidtoogleControlDetection() { doControlDetection == true ? doControlDetection = false : doControlDetection = true; }; void encontraControles(); void processaInteracao(); void desenhaControles();

08

:38

fb

.co

m/R

VA

.BR

121

Processamento da imagem void ofApp::encontraControles(){ Mat img = ofxCv::toCv(this->unwarped); // Get the image in the right format and run edge detection - cheat - tricks ofxCv::convertColor(img, grayImg, CV_RGB2GRAY); //converte a imagem para cinza cv::Canny(grayImg, edgesInput, 160, 180, 3); // extrapola as bordas - edge map canny = edgesInput; cv::dilate(edgesInput, edgesInput, Mat::ones(2, 2, CV_8U), cv::Point(-1, -1), 7); //dilata as bordas dilated = edgesInput; cv::erode(edgesInput, edgesInput, Mat::ones(2, 2, CV_8U), cv::Point(-1, -1), 5); // erode as bordas eroded = edgesInput; const cv::Rect &roi = cv::Rect(BORDER, BORDER, edgesInput.cols - 2*BORDER, edgesInput.rows - 2*BORDER); edgesInput(roi).copyTo(edges); // Find contours in the edge detected image controlFinder.findContours(edges); //... continues }

08

:38

fb

.co

m/R

VA

.BR

122

Procurar Controles

08

:38

fb

.co

m/R

VA

.BR

123

Tipos de Controles:

Switch – Posição 0 ou 1, memoriza a função

Button – Posição 0 ou 1, instantâneo, funciona enquanto clicado, depois perde o valor

Slide - Valor variável entre um máx. e um mín.

08

:38

fb

.co

m/R

VA

.BR

124

Identificação dos tipos de controles

08

:38

fb

.co

m/R

VA

.BR

125

Estrutura de dados genérica (super-hiper-mega simplificada)

enum controlType{ CT_SWITCH, CT_BUTTON, CT_SLIDE };

class Controle { public: int id; controlType type; int value; int max; int min; //Para desenhar: ofPoint pos; ofRectangle posRect; float radius; float angle; void draw(){}; //para preencher os campos void fillSlider( cv::RotatedRect rotRect){} void fillSwitch( cv::RotatedRect rotRect){}; void fillButton( cv::Point center, float radius){}; bool interact(ofPoint dedo); };

Ideal é que sejam feitas classes e polimorfismo de tudo.

class Class Model

ofBaseApp

ofApp

+ par :ofxProjAR

+ setup() :void

+ update() :void

+ draw() :void

+ keyPressed(int) :void

+ keyReleased(int) :void

+ mouseMoved(int, int) :void

+ mouseDragged(int, int, int) :void

+ mousePressed(int, int, int) :void

+ mouseReleased(int, int, int) :void

+ windowResized(int, int) :void

+ dragEvent(ofDragInfo) :void

+ gotMessage(ofMessage) :void

ofxProjAR

+ m_infra :ofxPAR_Infra*

+ m_actuator :ofxPAR_Actuator*

+ controlManager :ofxPAR_ControlManager

+ debug :bool

- actualState :ofxPAR_State*

- stateList :vector<ofxPAR_State*>

+ ofxProjAR()

+ ~ofxProjAR()

+ standardSetup() :void

+ standardUpdate() :void

+ standardDraw() :void

+ setState(AppState) :bool

+ getActualState() :ofxPAR_State*

ofxPAR_Infra

+ cam :ofVideoGrabber

+ camHeight :int

+ camWidth :int

+ unwarped :ofImage

+ showVideoFeed :bool

+ foundInfra :bool

+ projectorPoints :vector<cv::Point2f>

+ toProjectorMatrix :cv::Mat

+ alignmentComplete :bool

+ projWidth :int

+ projHeight :int

# name :string

+ ofxPAR_Infra()

+ ~ofxPAR_Infra()

+ detect() :void

+ draw() :void

+ update() :void

+ setup() :void

+ getTransformation(int, int) :cv::Mat

+ getContours() :ofPolyline

+ unwarpPoint(ofPoint&, int, int) :ofPoint

+ getCamera() :ofVideoGrabber

+ setCamera(ofVideoGrabber) :void

+ setCamera(int, int) :void

+ getRawUnwarped() :ofImage

+ toogleVideoFeed() :void

+ isInfraFound() :bool

+ addCalibrationPoints(int, int) :void

+ resetCalibration() :void

+ doCalibration() :void

+ drawProjectionLimits() :void

# computeProjectorAlignment() :void

# loadProjectorAlignment() :bool

# saveProjectorAlignment() :bool

# resetProjectorAlignment() :void

ofxPAR_Infra_PaperDetector

# trackingColorMode :ofxCv::TrackingColorMode

# contourFinder :ofxCv::ContourFinder

# targetColor :ofColor

# thresholdCV :int

# contour :ofPolyline

# paperImage :cv::Mat

# paper :vector<cv::Point>

# adaptedToScreenSize :vector<cv::Point>

+ ofxPAR_Infra_PaperDetector()

+ ~ofxPAR_Infra_PaperDetector()

+ draw() :void

+ detect() :void

+ calibrate() :void

+ update() :void

+ setup() :void

+ getTransformation(int, int) :cv::Mat

+ getContours() :ofPolyline

+ unwarpPoint(ofPoint&, int, int) :ofPoint

- configureCV() :void

- drawPaperContour() :void

- drawPaperContourIn(int, int) :void

- unwarp(S&, D&) :void

- unwarp(D&) :void

- unwarpPointIntern(ofPoint&, int, int) :ofPoint

ofxPAR_Actuator

+ topBackground :ofxCv::RunningBackground

+ foreground :cv::Mat

+ ofxPAR_Actuator()

+ ~ofxPAR_Actuator()

+ draw() :void

+ drawDetectorInput(float, float, float, float) :void

+ detect(T&, S&, ofPolyline&) :bool

+ detect(cv::Mat&, ofPolyline&) :bool

+ getActuatorPoint() :ofPoint

+ setActuatorThresold(int) :void

ofxPAR_HandDetector

- topFinder :ofxCv::ContourFinder

- sideFinder :ofxCv::ContourFinder

- topFilled :cv::Mat

- contour :ofPolyline

- fingers :vector<size_t>

- fingerPoint :ofPoint

- foundFingerInLast :bool

- fingerThreshold :int

- fAlpha :float

- elem2x2 :cv::Mat

- elem3x3 :cv::Mat

- useCenter :cv::Point {readOnly}

+ ofxPAR_HandDetector()

+ ~ofxPAR_HandDetector()

+ draw() :void

+ drawDetectorInput(float, float, float, float) :void

+ detect(cv::Mat&, ofPolyline&) :bool

+ getActuatorPoint() :ofPoint

+ setActuatorThresold(int) :void

- findFingers(ofPolyline&) :bool

- getFingerPoint() :ofPoint

ofxPAR_ControlManager

+ doControlDetection :bool

+ accent1 :ofColor {readOnly}

+ accent2 :ofColor {readOnly}

+ finder :ofxCv::ContourFinder

+ grayImg :cv::Mat

+ canny :cv::Mat

+ eroded :cv::Mat

+ dilated :cv::Mat

+ edgesInput :cv::Mat

+ edges :cv::Mat

+ controlList :vector<ofxPAR_Control *>

+ lastInputPoint :ofPoint

+ BORDER :int

+ ALPHA :float

+ ofxPAR_ControlManager()

+ ~ofxPAR_ControlManager()

+ setup() :void

+ reset() :void

+ drawDetectorInput(float, float, float, float) :void

+ detect(T&) :void

+ detect(cv::Mat) :void

+ toogleControlDetection() :void

+ processInteraction(ofPoint&) :void

+ drawControls() :void

+ drawDebug() :void

+ assignControls() :void

+ isButton(size_t) :bool

+ isSlider(size_t) :bool

+ isSwitch(size_t) :bool

ofxPAR_Control

# id :int

# name :string

# value :int

# color :ofColor

# controlType :ControlType

# selected :bool

+ ofxPAR_Control()

+ ~ofxPAR_Control()

+ setId(int) :void

+ draw() :void

+ setColor(ofColor&) :void

+ contains(float, float) :bool

+ contains(ofPoint&) :bool

+ onInteraction(float, float) :bool

+ onInteraction(ofPoint&) :bool

+ setSelection(bool) :void

+ isSelected() :bool

+ getValue() :int

ofxPAR_C_Button

- cx :float

- cy :float

- radius :float

- active :bool

- entered :bool

+ ofxPAR_C_Button()

+ ~ofxPAR_C_Button()

+ ofxPAR_C_Button(float, float, float)

+ draw() :void

+ contains(float, float) :bool

+ onInteraction(float, float) :bool

+ operator==(ofxPAR_C_Button&) :bool

+ operator!=(ofxPAR_C_Button&) :bool

ofxPAR_C_Slider

- value :float

+ ofxPAR_C_Slider()

+ ~ofxPAR_C_Slider()

+ ofxPAR_C_Slider(cv::RotatedRect&)

+ draw() :void

+ onInteraction(float, float) :bool

ofxPAR_C_Switch

- active :bool

+ ofxPAR_C_Switch()

+ ~ofxPAR_C_Switch()

+ ofxPAR_C_Switch(cv::RotatedRect&)

+ draw() :void

+ onInteraction(float, float) :bool

ofxPAR_State

+ stateType :AppState

+ name :string

+ app :ofxProjAR*

+ ofxPAR_State()

+ ~ofxPAR_State()

+ draw() :void

+ update() :void

ofxPAR_State_Idle

+ ofxPAR_State_Idle()

+ ~ofxPAR_State_Idle()

+ draw() :void

+ update() :void

ofxPAR_State_InfraSetup

+ ofxPAR_State_InfraSetup()

+ ~ofxPAR_State_InfraSetup()

+ draw() :void

+ update() :void

ofxPAR_State_Play

+ ofxPAR_State_Play()

+ ~ofxPAR_State_Play()

+ draw() :void

+ update() :void

- reprojectPaper() :void

ofxPAR_Control_Rectangular

# angle :float

# rect :ofRectangle

+ ofxPAR_Control_Rectangular()

+ ~ofxPAR_Control_Rectangular()

+ ofxPAR_Control_Rectangular(cv::RotatedRect&)

+ draw() :void

+ contains(float, float) :bool

+ operator==(ofxPAR_Control_Rectangular&) :bool

+ operator!=(ofxPAR_Control_Rectangular&) :bool

# alignPoint(float, float) :ofVec2f

+app

08

:38

fb

.co

m/R

VA

.BR

126

Tipo: vector (de classes)

• Vector é uma estrutura para armazenar sequencialmente.

• No C++ vários tipos de estruturas de dados foram definidas usando containers genéricos. (STL)

vector<Controle> listaDeControles;

• Adição: Controle a;

listaDeControles.push_back(a);

• Remoção: listaDeControles.erase( listaDeControles.begin() + x);

• Percorrer:

vector<Controle>::iterator it = listaDeControles.begin();

for(; it != listaDeControles.end(); it++){

it->id; } // se vetor de ponteiros (*it)->

http://www.openframeworks.cc/tutorials/c++%20concepts/001_stl_vectors_basic.html

vector<Controle*> listaDeControles; 08:3

8

fb.c

om

/RV

A.B

R

127

//... Continuing - void ofApp::encontraControles() listaDeControles.clear(); int n = controlFinder.size(); for(int i = 0; i< n; i++){

if (isButton(i)) { float radius; cv::Point center = controlFinder.getMinEnclosingCircle(i, radius); Controle *b = new Controle(); b->id = i; b->fillButton(center, radius); listaDeControles.push_back(b);

} else if (isSlider(i)) { cv::RotatedRect rect = controlFinder.getMinAreaRect(i); Controle *s = new Controle(); s->id = i; s->fillSlider(rect); listaDeControles.push_back(s);

} else if (isSwitch(i)) { cv::RotatedRect rect = controlFinder.getMinAreaRect(i); Controle *s = new Controle(); s->id = 1; s->fillSwitch(rect); listaDeControles.push_back(s); } } }

08

:38

fb

.co

m/R

VA

.BR

128

//--------------------------------------------------------- bool ofApp::isButton(int i) { float radius; controlFinder.getMinEnclosingCircle(i, radius); float circleArea = PI * radius * radius; double contourArea = controlFinder.getContourArea(i); return abs(1.0 - circleArea / contourArea) < 0.3; } //--------------------------------------------------------- bool ofApp::isSlider(int i) { float radius; ofVec2f center = ofxCv::toOf(controlFinder.getMinEnclosingCircle(i, radius)); float circleArea = PI * radius * radius; double contourArea = controlFinder.getContourArea(i); return circleArea / contourArea > 12; } //--------------------------------------------------------- bool ofApp::isSwitch(int i) { RotatedRect rr = controlFinder.getMinAreaRect(i); float rectArea = rr.size.width * rr.size.height; double contourArea = controlFinder.getContourArea(i); return abs(1.0 - rectArea / contourArea) < 0.25 && abs(1.0 - (float) rr.size.width / rr.size.height) > 0.1; }

08

:38

fb

.co

m/R

VA

.BR

129

Cri

ar o

s co

ntr

ole

s -F

YI

void fillSlider( cv::RotatedRect rotRect){

this->type = controlType::CT_SLIDE;

const cv::Size &s = rotRect.size;

bool switchHeight = s.width < s.height;

if (switchHeight) {

this->posRect.setFromCenter(ofxCv::toOf(rotRect.center), s.height, s.width);

angle = rotRect.angle + 90;

} else {

this->posRect.setFromCenter(ofxCv::toOf(rotRect.center), s.width, s.height);

angle = rotRect.angle; }

this->value = 0;

};

void fillSwitch( cv::RotatedRect rotRect){

this->type = controlType::CT_SWITCH;

const cv::Size &s = rotRect.size;

bool switchHeight = s.width < s.height;

if (switchHeight) {

this->posRect.setFromCenter(ofxCv::toOf(rotRect.center), s.height, s.width);

angle = rotRect.angle + 90;

} else {

this->posRect.setFromCenter(ofxCv::toOf(rotRect.center), s.width, s.height);

angle = rotRect.angle;

}

this->value = 0;

};

void fillButton( cv::Point center, float radius){

this->type = controlType::CT_BUTTON;

this->pos.x = center.x; this->pos.y = center.y; this->radius = radius;

this->value = 0;

};

08

:38

fb

.co

m/R

VA

.BR

130

Draw do botão:

case controlType::CT_BUTTON :{

ofPushMatrix();

ofSetColor(ofColor::green);

ofSetLineWidth(5);

if (this->value == 1) {

ofFill();

} else {

ofNoFill();

}

ofCircle(this->pos, this->radius);

ofPopMatrix();

break;}

08

:38

fb

.co

m/R

VA

.BR

131

case controlType::CT_SWITCH:{

ofPushMatrix();

ofTranslate(this->posRect.getCenter());

ofRotate(this->angle);

ofNoFill();

ofSetLineWidth(3);

ofSetColor(ofColor::blue);

ofRect(-this->posRect.width / 2, -this->posRect.height / 2, this->posRect.width, this->posRect.height);

ofLine(0, -this->posRect.height / 2, 0, this->posRect.height / 2);

float x = (this->value ? 0 : -this->posRect.width / 2);

ofLine(x, -this->posRect.height / 2, x + this->posRect.width / 2, this->posRect.height / 2);

ofLine(x + this->posRect.width / 2, -this->posRect.height / 2, x, this->posRect.height / 2);

ofPopMatrix();

break;}

Draw da Chave:

08

:38

fb

.co

m/R

VA

.BR

132

case controlType::CT_SLIDE:{

ofPushMatrix();

ofTranslate(this->posRect.getCenter());

ofRotate(this->angle);

ofNoFill();

ofSetLineWidth(4);

ofSetColor(ofColor::red);

// Draw the main shape

ofLine(-this->posRect.width / 2, 0, this->posRect.width / 2, 0);

ofLine(-this->posRect.width / 2, -this->posRect.height / 2, -this->posRect.width / 2, this->posRect.height / 2);

ofLine(this->posRect.width / 2, -this->posRect.height / 2, this->posRect.width / 2, this->posRect.height / 2);

// Draw the tick marks

ofSetLineWidth(2);

for (size_t i = 1; i < 8; i++) {

float dx = ((float) i / 8) * this->posRect.width;

ofLine(-this->posRect.width / 2 + dx, -this->posRect.height / 3, -this->posRect.width / 2 + dx, this->posRect.height / 3);

}

// Draw the value marker

float xval = ((float)this->value/100) * this->posRect.width;

float knobHeight = 5 * this->posRect.height / 4;

float knobWidth = this->posRect.width / 8;

// Fill the rectangle with black to erase the background

ofPushStyle();

ofSetColor(0);

ofFill();

ofRect(-this->posRect.width / 2 + xval - knobWidth / 2, -knobHeight / 2, knobWidth, knobHeight);

ofPopStyle();

ofSetLineWidth(5);

ofRect(-this->posRect.width / 2 + xval - knobWidth / 2, -knobHeight / 2, knobWidth, knobHeight);

ofPopMatrix();

break;}

Draw do Slider

08

:38

fb

.co

m/R

VA

.BR

133

FINAL LAP: INTERAÇÃO COM OS CONTROLES

08

:38

fb

.co

m/R

VA

.BR

134

Fixar os pontos de corte da figura!!!!!!!!!!!!!!

08

:38

fb

.co

m/R

VA

.BR

135

Inside!?

bool buttonContains(int x, int y){

return ofDistSquared((float)pos.x, (float)pos.y, (float)x, (float)y) < radius * radius;

}

bool rectContains(int x, int y){

return posRect.inside(x, y);

}

08

:38

fb

.co

m/R

VA

.BR

136

switch(type){

case controlType::CT_BUTTON :

if (buttonContains(dedo.x, dedo.y)) {

value == 1 ? value = 0 : value = 1;

return true; }

break;

case controlType::CT_SWITCH :

if(rectContains(dedo.x,dedo.y)) {

bool right = dedo.x > posRect.getCenter().x;

if ((bool)value != right) value = right;

return true;}

break;

case controlType::CT_SLIDE :

if(rectContains(dedo.x,dedo.y)){

value = (int) ((dedo.x - posRect.x)*100 / posRect.width);

return true;}

break;

default: break;

};

interaction

08

:38

fb

.co

m/R

VA

.BR

137

Resultado Esperado

08

:38

fb

.co

m/R

VA

.BR

138

WRAP-UP

08

:38

fb

.co

m/R

VA

.BR

139

O QUE APRENDEMOS HOJE

O QUE ACONTECEU:

class src

«enumeratio...

controlType

CT_SWITCH

CT_BUTTON

CT_SLIDE

Controle

+ id :int

+ type :controlType

+ value :int

+ max :int

+ min :int

+ pos :ofPoint

+ posRect :ofRectangle

+ radius :float

+ angle :float

+ fi l lSlider(rotRect :cv::RotatedRect) :void

+ fi l lSwitch(rotRect :cv::RotatedRect) :void

+ fi l lButton(center :cv::Point, radius :float) :void

+ draw() :void

+ buttonContains(x :int, y :int) :bool

+ rectContains(x :int, y :int) :bool

+ interact(dedo :ofPoint) :bool

ofBaseApp

ofApp

+ debugApp :bool

+ cam :ofVideoGrabber

+ camHeight :int

+ camWidth :int

+ original :ofImage

+ paperFinder :ofxCv::ContourFinder

+ warpedPaper :ofImage

+ verticesInfra :vector<Point2f>

+ foundInfra :bool

+ StopToGetInfraPosition :bool

+ controlFinder :ofxCv::ContourFinder

+ doControlDetection :bool

+ grayImg :cv::Mat

+ canny :cv::Mat

+ eroded :cv::Mat

+ dilated :cv::Mat

+ edgesInput :cv::Mat

+ edges :cv::Mat

+ BORDER :int

+ ALPHA :float

+ listaDeControles :vector<Controle*>

+ colorImage :ofxCvColorImage

+ grayBg :ofxCvGrayscaleImage

+ grayImage :ofxCvGrayscaleImage

+ grayDiff :ofxCvGrayscaleImage

+ bLearnBackground :bool

+ trackingColorMode :ofxCv::TrackingColorMode

+ handFinder :ofxCv::ContourFinder

+ targetColor :ofColor

+ apontador :ofPoint

+ setup() :void

+ update() :void

+ draw() :void

+ keyReleased(key :int) :void

+ trataInfraestrutura() :void

+ desenhaInfraestrutura(x :int, y :int) :void

+ encontraControles(source :ofImage) :void

+ isButton(i :int) :bool

+ isSwitch(i :int) :bool

+ isSlider(i :int) :bool

+ desenhaControles(x :int, y :int) :void

+ processaInteracao() :void

+ encontraPontoMaisDistante() :ofPoint

+ desenhaMao(x :int, y :int) :void

+ encontraMao(source :ofImage) :void

+ findForm(poly :ofPolyline&) :string

+ findForm(poly :T&) :string

+type

08

:38

fb

.co

m/R

VA

.BR

140

class Class Model

ofBaseApp

ofApp

+ par :ofxProjAR

+ setup() :void

+ update() :void

+ draw() :void

+ keyPressed(int) :void

+ keyReleased(int) :void

+ mouseMoved(int, int) :void

+ mouseDragged(int, int, int) :void

+ mousePressed(int, int, int) :void

+ mouseReleased(int, int, int) :void

+ windowResized(int, int) :void

+ dragEvent(ofDragInfo) :void

+ gotMessage(ofMessage) :void

ofxProjAR

+ m_infra :ofxPAR_Infra*

+ m_actuator :ofxPAR_Actuator*

+ controlManager :ofxPAR_ControlManager

+ debug :bool

- actualState :ofxPAR_State*

- stateList :vector<ofxPAR_State*>

+ ofxProjAR()

+ ~ofxProjAR()

+ standardSetup() :void

+ standardUpdate() :void

+ standardDraw() :void

+ setState(AppState) :bool

+ getActualState() :ofxPAR_State*

ofxPAR_Infra

+ cam :ofVideoGrabber

+ camHeight :int

+ camWidth :int

+ unwarped :ofImage

+ showVideoFeed :bool

+ foundInfra :bool

+ projectorPoints :vector<cv::Point2f>

+ toProjectorMatrix :cv::Mat

+ alignmentComplete :bool

+ projWidth :int

+ projHeight :int

# name :string

+ ofxPAR_Infra()

+ ~ofxPAR_Infra()

+ detect() :void

+ draw() :void

+ update() :void

+ setup() :void

+ getTransformation(int, int) :cv::Mat

+ getContours() :ofPolyline

+ unwarpPoint(ofPoint&, int, int) :ofPoint

+ getCamera() :ofVideoGrabber

+ setCamera(ofVideoGrabber) :void

+ setCamera(int, int) :void

+ getRawUnwarped() :ofImage

+ toogleVideoFeed() :void

+ isInfraFound() :bool

+ addCalibrationPoints(int, int) :void

+ resetCalibration() :void

+ doCalibration() :void

+ drawProjectionLimits() :void

# computeProjectorAlignment() :void

# loadProjectorAlignment() :bool

# saveProjectorAlignment() :bool

# resetProjectorAlignment() :void

ofxPAR_Infra_PaperDetector

# trackingColorMode :ofxCv::TrackingColorMode

# contourFinder :ofxCv::ContourFinder

# targetColor :ofColor

# thresholdCV :int

# contour :ofPolyline

# paperImage :cv::Mat

# paper :vector<cv::Point>

# adaptedToScreenSize :vector<cv::Point>

+ ofxPAR_Infra_PaperDetector()

+ ~ofxPAR_Infra_PaperDetector()

+ draw() :void

+ detect() :void

+ calibrate() :void

+ update() :void

+ setup() :void

+ getTransformation(int, int) :cv::Mat

+ getContours() :ofPolyline

+ unwarpPoint(ofPoint&, int, int) :ofPoint

- configureCV() :void

- drawPaperContour() :void

- drawPaperContourIn(int, int) :void

- unwarp(S&, D&) :void

- unwarp(D&) :void

- unwarpPointIntern(ofPoint&, int, int) :ofPoint

ofxPAR_Actuator

+ topBackground :ofxCv::RunningBackground

+ foreground :cv::Mat

+ ofxPAR_Actuator()

+ ~ofxPAR_Actuator()

+ draw() :void

+ drawDetectorInput(float, float, float, float) :void

+ detect(T&, S&, ofPolyline&) :bool

+ detect(cv::Mat&, ofPolyline&) :bool

+ getActuatorPoint() :ofPoint

+ setActuatorThresold(int) :void

ofxPAR_HandDetector

- topFinder :ofxCv::ContourFinder

- sideFinder :ofxCv::ContourFinder

- topFilled :cv::Mat

- contour :ofPolyline

- fingers :vector<size_t>

- fingerPoint :ofPoint

- foundFingerInLast :bool

- fingerThreshold :int

- fAlpha :float

- elem2x2 :cv::Mat

- elem3x3 :cv::Mat

- useCenter :cv::Point {readOnly}

+ ofxPAR_HandDetector()

+ ~ofxPAR_HandDetector()

+ draw() :void

+ drawDetectorInput(float, float, float, float) :void

+ detect(cv::Mat&, ofPolyline&) :bool

+ getActuatorPoint() :ofPoint

+ setActuatorThresold(int) :void

- findFingers(ofPolyline&) :bool

- getFingerPoint() :ofPoint

ofxPAR_ControlManager

+ doControlDetection :bool

+ accent1 :ofColor {readOnly}

+ accent2 :ofColor {readOnly}

+ finder :ofxCv::ContourFinder

+ grayImg :cv::Mat

+ canny :cv::Mat

+ eroded :cv::Mat

+ dilated :cv::Mat

+ edgesInput :cv::Mat

+ edges :cv::Mat

+ controlList :vector<ofxPAR_Control *>

+ lastInputPoint :ofPoint

+ BORDER :int

+ ALPHA :float

+ ofxPAR_ControlManager()

+ ~ofxPAR_ControlManager()

+ setup() :void

+ reset() :void

+ drawDetectorInput(float, float, float, float) :void

+ detect(T&) :void

+ detect(cv::Mat) :void

+ toogleControlDetection() :void

+ processInteraction(ofPoint&) :void

+ drawControls() :void

+ drawDebug() :void

+ assignControls() :void

+ isButton(size_t) :bool

+ isSlider(size_t) :bool

+ isSwitch(size_t) :bool

ofxPAR_Control

# id :int

# name :string

# value :int

# color :ofColor

# controlType :ControlType

# selected :bool

+ ofxPAR_Control()

+ ~ofxPAR_Control()

+ setId(int) :void

+ draw() :void

+ setColor(ofColor&) :void

+ contains(float, float) :bool

+ contains(ofPoint&) :bool

+ onInteraction(float, float) :bool

+ onInteraction(ofPoint&) :bool

+ setSelection(bool) :void

+ isSelected() :bool

+ getValue() :int

ofxPAR_C_Button

- cx :float

- cy :float

- radius :float

- active :bool

- entered :bool

+ ofxPAR_C_Button()

+ ~ofxPAR_C_Button()

+ ofxPAR_C_Button(float, float, float)

+ draw() :void

+ contains(float, float) :bool

+ onInteraction(float, float) :bool

+ operator==(ofxPAR_C_Button&) :bool

+ operator!=(ofxPAR_C_Button&) :bool

ofxPAR_C_Slider

- value :float

+ ofxPAR_C_Slider()

+ ~ofxPAR_C_Slider()

+ ofxPAR_C_Slider(cv::RotatedRect&)

+ draw() :void

+ onInteraction(float, float) :bool

ofxPAR_C_Switch

- active :bool

+ ofxPAR_C_Switch()

+ ~ofxPAR_C_Switch()

+ ofxPAR_C_Switch(cv::RotatedRect&)

+ draw() :void

+ onInteraction(float, float) :bool

ofxPAR_State

+ stateType :AppState

+ name :string

+ app :ofxProjAR*

+ ofxPAR_State()

+ ~ofxPAR_State()

+ draw() :void

+ update() :void

ofxPAR_State_Idle

+ ofxPAR_State_Idle()

+ ~ofxPAR_State_Idle()

+ draw() :void

+ update() :void

ofxPAR_State_InfraSetup

+ ofxPAR_State_InfraSetup()

+ ~ofxPAR_State_InfraSetup()

+ draw() :void

+ update() :void

ofxPAR_State_Play

+ ofxPAR_State_Play()

+ ~ofxPAR_State_Play()

+ draw() :void

+ update() :void

- reprojectPaper() :void

ofxPAR_Control_Rectangular

# angle :float

# rect :ofRectangle

+ ofxPAR_Control_Rectangular()

+ ~ofxPAR_Control_Rectangular()

+ ofxPAR_Control_Rectangular(cv::RotatedRect&)

+ draw() :void

+ contains(float, float) :bool

+ operator==(ofxPAR_Control_Rectangular&) :bool

+ operator!=(ofxPAR_Control_Rectangular&) :bool

# alignPoint(float, float) :ofVec2f

+app

IDEAL:

08

:38

fb

.co

m/R

VA

.BR

141

• Existe um framework em C++ chamado openFrameworks. Novo player interessante: Unreal Engine + Blueprints (AWESOME)

• openFrameworks pode ser expandido com componentes da comunidade, chamados addons.

• Com ele é possível controlar o Arduino (em C++).

• O Arduino pode se transformar numa interface de

dados usando a lib Firmata.

• Arduino é barato e fácil de usar. Um possível software para desenhar circuitos é o Fritzing

•Realidade Aumentada é só uma interface de acesso aos elementos virtuais.

08

:38

fb

.co

m/R

VA

.BR

142

• openCV é uma biblioteca de visão computacional.

• Com openCV podemos rastrear cores, diferenças de

imagens, etc.

• Pense se sua aplicação pode usar equipamentos

simples!

• Quanto mais simples e do cotidiano do usuário melhor.

• Visão computacional nem sempre é um resultado por si.

Ideal são soluções hibridas.

• Adicionando elementos de interação físicos (sensores e atuadores) à Realidade Aumentada, que fazem a troca

bidirecional de informação cria-se Realidade Cruzada.

08

:38

fb

.co

m/R

VA

.BR

143

08

:38

fb

.co

m/R

VA

.BR

144

Motivador Pesquisa

Dúvidas: christophercerqueira@gmail.com Site: http://cscerqueira.com.br

Facebook: http://fb.com/RVA.BR

Para maiores dúvidas: INPE – SJC

Prédio Satélite Sala 95

Drª. Ana Maria Ambrosio

Msc. Christopher Cerqueira

aluno doutorado

Dr. Claudio Kirner

08

:38

fb

.co

m/R

VA

.BR

145