
Reconstrução 3D com OpenCV e Python
Saiba como o OpenCV oferece suporte a reconstruções 3D e veja um exemplo de aplicativo que movimenta um braço robótico.
O OpenCV é uma biblioteca para visão computacional em tempo real. Ele oferece funções extremamente avançadas que simplificam a arte de processar imagens e obter informações sobre elas. Neste artigo, vamos analisar algumas funções que usamos para fazer uma reconstrução 3D a partir de uma imagem, com o objetivo de criar um braço robótico autônomo.
O OpenCV usa um modelo de câmera estenopeica (pinhole). Esse modelo projeta pontos 3D no plano da imagem usando uma transformação de perspectiva.
O OpenCV inclui vários recursos que ajudam a atingir o nosso objetivo. Essas funções trabalham com um padrão de tabuleiro de xadrez para calibrar o modelo. Por isso, o primeiro passo é fotografar um tabuleiro de xadrez. Tiramos várias fotos para melhorar a calibração.

Vimos acima um trecho do código. Agora, vamos ver sua finalidade.
Nas primeiras linhas, importamos as bibliotecas necessárias. Em seguida, definimos os critérios de parada para os algoritmos iterativos do OpenCV. Eles são usados na função cornerSubPix.
As próximas variáveis são para preparar os pontos do objeto. Depois, definimos algumas matrizes vazias para armazenar os pontos do objeto e os pontos da imagem de todas as imagens do tabuleiro de xadrez.
A próxima etapa é abrir todas as imagens em escala de cinza, para passá-las como parâmetros para a função findChessboardCorners(). Essa função tem três parâmetros. O primeiro parâmetro é a imagem, que deve ser em uma escala de cinza de 8 bits. O segundo parâmetro é o número de cantos internos por tabuleiro de xadrez, que deve ser uma tupla (points_per_row, points_per_column). O terceiro parâmetro são os cantos. Como não queremos detectá-los neste caso, escrevemos None.
O próximo passo é refinar os locais dos cantos com a função cornerSubPix(). Em seguida, desenhamos os cantos no tabuleiro de xadrez. A imagem a seguir mostra onde localizamos os cantos do tabuleiro e onde eles foram desenhados.

Agora já identificamos os pontos do objeto e os pontos das imagens. Estamos prontos para a calibração da câmara, usando a função calibrateCamera(). Essa função retorna todos os parâmetros necessários para fazer a reconstrução 3D, como a matriz da câmera, os coeficientes de distorção, os vetores de rotação, etc.

Temos os parâmetros da câmera e vamos usá-los para a reconstrução 3D.

Na primeira linha, fazemos um refinamento para melhorar a localização dos cantos. Em seguida, aplicamos os parâmetros da câmara já obtidos. Na função solvePnRansac(), o OpenCV encontra uma pose do objeto a partir de correspondências de pontos 3D e 2D, usando um método iterativo para estimar os parâmetros do modelo matemático com um conjunto de dados observados que contém exceções (outliers). Na terceira linha, definimos os eixos para criar uma caixa na imagem e projetar nessa caixa. O próximo passo é projetar os pontos e, em seguida, desenhá-los usando a função draw().

Acima, é possível ver a imagem de entrada, à esquerda, e a imagem com os eixos adicionados, à direita.
Caso: braço robótico autônomo
Com essas projeções 2D e 3D, podemos identificar as coordenadas espaciais de um objeto a partir de uma imagem. Optamos por implementar esse algoritmo do OpenCV para criar um braço robótico autônomo. Para torná-lo autônomo, precisamos usar um modelo de detecção de objetos, que permitirá que o braço identifique a identidade e a localização dos objetos a pegar.
Para isso, usamos o modelo MASK r-cnn para detecção de objetos e segmentação de instâncias no Keras e TensorFlow. Acesse este GitHub para encontrar informações mais específicas sobre o modelo.
Além do modelo MASK, usamos uma placa Arduino Mega para o controle do braço, pois sabemos qual é a posição dos objetos e precisamos descobrir como movimentar o braço para agarrá-los. Por isso, escrevemos uma função Arduino para controlar cada um dos quatro motores do braço.
Cada motor tem um potenciômetro que funciona como um goniômetro. Para isso, é preciso calcular a relação entre a tensão no potenciômetro e a posição do motor. É muito simples obter essa relação com uma regressão linear, que pode ser feita em Excel ou OriginLab. Após obter essa relação, podemos usá-la na função Arduino. Vamos preparar um trecho de código:

Na imagem anterior, vemos um trecho de código das funções que usamos para a programação da placa Arduino. Cada motor tem uma dessas funções.

A imagem acima mostra a configuração do braço robótico e o tabuleiro de xadrez. Usamos uma webcam posicionada na frente do braço para fazer a calibração da câmara e a reconstrução 3D.