Objetivo

O objetivo deste trabalho é fazer um programa que recebe uma sequencia de fotos tiradas de um modelo tridimensional em diferentes ângulos, usando luz estruturada, e partir destas imagens obter a nuvem de pontos em três dimensões do objeto reconstruído.

O programa consiste das seguintes etapas:

1) Identificação e decodificação das transições da luz estruturada na superfície do objeto. 

2) Definição de pontos correspondentes em imagens de vistas diferentes utilizando a geomteria epipolar. 

3) Triangulação dos pontos correspondentes de forma a se obter o ponto tridimensional. 

4)Geração e visualização da nuvem de pontos. 

Implementação 

Identificação e decodificação das transições da luz estruturada na superfície do objeto

Nesta etapa as transições de luz estruturada são identificadas em todas as imagens, negativas e positivas, e para todos os ângulos de rotação da câmera. O algoritmo de identificação de transição é simples:

 Do inicio da imagem ao fim faz:

a)       Pega o próximo pixel e seu vizinho direto à direita.

b)       Se a diferença entre o valor do slide negativo e positivo para a mesma posição de camera tiver sinais diferentes para estes dois pixels vizinhos (em qualquer das 3 bandas (RGB)) então este é um pixel de transição; caso contrário volta para (a).

c)       Usando a função getBcslStripeCode (Asla) recupera-se o código correspondente àquela transição. Esta função recebe como entrada as duas cores das faixas identificadas no slide positivo 1 e as duas cores das faixas identificadas no slide positivo 2 e gera como saída o código da transição. Vale lembrar que são duas imagens com padrões positivos pois deseja-se codificar um numero grande de faixas, que não seria possivel com apenas um padrão.

d)       Na imagem de saída da função armazena-se na banda R o valor 255, na G a precisão em sub-pixels, e na banda B o código da transição.

Esta etapa é recebe como entrada quatro imagens de uma mesma posição de camera com a luz estruturada projetada e gera uma imagem de saída com as transições identificadas e decodificadas, correspondente a uma determinada posição da camera.

Das quatro imagens de entrada, duas são positivas e outras duas são negativas, ou seja, o complemento das positivas. Estas imagens positivas e negativas são utilizadas para que seja possível eliminar o efeito de modificação da cor projetada que a cor natural do objeto causa. Após ser feita esta compensação de forma a se obter as cores do padrão projetada, as transições são identificadas e a decodificação realizada.

Definição de pontos correspondentes em imagens de vistas diferentes utilizando a geomteria epipolar

Esta etapa do programa define os pontos em duas imagens que correspondem ao mesmo ponto nas coordenadas do mundo. A partir destes pontos correspondentes torna-se possível fazer uma triangulação e com isso determinar a coordenada em 3 dimensões do ponto no mundo.

Para isso usamos as idéias de geometria epipolar, utilizando duas imagens A e B correspondentes a vistas diferentes do objeto 3D, ou seja, diferentes posições da camera. A geometria epipolar usa informações de projeção da camera calibrada, para definir, dado um ponto na imagem A, uma região onde o ponto correspondente na imagem B poderia estar. Esta região é na realidade uma reta, onde algumas vezes considera-se uma determinada espessura para obtenção de resultados melhores (um numero maior de pontos correspondentes).

Esta função recebe como entrada um ponto de transição da imagem A; a imagem B; a matriz F da camera B; e o codigo da transição. Como saída ela retorna o ponto correspondente em B.

O primeiro passo é encontrar a reta epipolar em B correspondente ao ponto dado em A. Para tanto usou-se uma função disponível (Gattass), que recebe um ponto em A e a matriz F de B, e  calcula os coeficientes da reta epipolar.

                stereoEpipolarLineEquation((double) ponto.x,(double) altura-ponto.y,F1,&a,&b,&c);

                epiLine1[0]=a;

                epiLine1[1]=b;

                epiLine1[2]=c;

Feito isso percorre-se a imagem B (em X, se tivermos a procura de transições verticais, ou em Y se as transições forem horizontais – ambos foram implementados) e calcula-se o valor Y resposta da reta epipolar para cada valor de X no dominio (largura da imagem). Se o valor de Y estiver dentro da imagem (intervalo [0 altura]) e o valor do pixel na banda de codigo for igual ao codigo do pixel em A fornecido como entrada, então estes são pontos correspondentes.

                //Percorre  x

                for (i=0;i<largura;i++)

                {

                               ret.x=(float)i;

                               ret.y= (float) floor(((epiLine1[0]*ret.x+epiLine1[2])/epiLine1[1]));

                               yP = altura-ret.y;

                               ind = 3*(i+(int)yP*largura)+2;

                               if ((altura > yP)&&(0 <= yP) && (imagem[ind] == col))

                               {

                                               ret.x=(float)i;

                                               ret.y=yP;

                                               ret.z=imagem[ind-1];

                                               //printf("reta mesmo :-> %lf,%lf,%lf\n",a,b,c);

                                               return ret;

                               }

                }

Este algoritmo roda para todos os angulos vizinhos (0 e 30, 30 e 60, etc) e gera como saida uma lista com as coordenadas dos pontos correspondentes nas duas imagens de entrada.

pontos :-> 444.160000,60.000000,447.000000,55

codigos faixa :-> 14.000000,14.000000

pontos :-> 417.050000,78.000000,418.000000,76

codigos faixa :-> 3.000000,3.000000

...

 

Triangulação dos pontos correspondentes de forma a se obter o ponto tridimensional

Nesta etapa o programa realiza a triangulação dos pontos correspondentes de forma a obter as coordenadas tridimensionais dos pontos no mundo. A entrada desta etapa é uma lista de pontos correspondentes e a saida é uma lista de pontos em coordenadas do mundo.

Esta função utiliza funções de calculo de triangulação disponibilizadas (Gattass) para o calculo das coordendas do mundo. A função stereoReconstruct recebe como entrada as coordenadas dos pontos correspondentes em A e B, a distancia focal e a matriz de rotação das cameras de A e B, e o centro de cada imagem. Como saída ela retorna um vetor com as coordenadas no mundo do ponto a que correspondem os dois pontos de entrada.

                int erro;

                Vector eye_a = algVector(a.cameraPosition.x,a.cameraPosition.y,a.cameraPosition.z,1);

                Vector eye_b = algVector(b.cameraPosition.x,b.cameraPosition.y,b.cameraPosition.z,1);

                Vector pl = stereoReconstruct(xa,ya,a.focalLenght,a.Ra,eye_a,a.w/2,a.h/2,

                               xb,yb,b.focalLenght,b.Ra,eye_b,b.w/2,b.h/2,&erro);

                Vector Pw = pl;

                if (erro) Pw.z = -1.0f;

                return Pw;

Geração e visualização da nuvem de pontos

A geração dos pontos é feita acumulando a lista de pontos de saída da etapa anterior. Para vizualização da nuvem de pontos gerada para cada par de vistas diferentes, utilizou-se o software ArcBall (Gattass).  


============================================================================

Código Fonte 

============================================================================