layout: true background-image: url(images/bgnd.png) --- class: center, middle ![Center-aligned image](images/tdc.png) # Visão computacional com OpenCV e Python ### Eduardo Henrique Arnold ### William Jamir Silva --- # Agenda - .font[Visão computacional: Introdução e Aplicações] - .font[Bibliotecas: OpenCV e Numpy] - .font[Exemplo de aplicação: Realidade Aumentada] --- # Visão Computacional
> "Visão computacional é a .highlight[ciência responsável pela visão de uma máquina], pela forma .highlight[como um computador enxerga o meio] à sua volta, > extraindo informações significativas a partir de imagens capturadas por câmeras de vídeo, sensores, scanners, entre outros dispositivos. > Estas informações permitem .highlight[reconhecer], .highlight[manipular] e .highlight[pensar sobre os objetos] que compõem uma imagem " > ** Ballard, Dana Harry**, Computer Vision, PrenticeHall, 1982. ???
Estuda mecanismos que permitem adquirir, processar, analizar e entender imagens para produzir informações e permitir tomada de decisão. --- ## Carros autônomos ![:img 90%, center](images/nvidia_computer_vision2.jpg) * .font[Detecção de objetos] * .font[Estimação de distância e velocidade] * .font[Representação 3D] ??? Detecção de objeto: * Atenção aos obstáculos inesperados, cones de tráfego, pedestre atravessando, mudança repentina de faixa. * Scanner a laser, no teto do carro gera uma representação 3D milimetricamente precisa dos arredores --- ## Realidade aumentada
.center[
Error Loading the file.
] * .font[Detecção de objetos (marcadores)] * .font[Estimar posição da câmera na cena] * .font[Sobreposição de modelo] --- ## Outras aplicações * .font[Reconstrução 3D de objetos] * .font[Monitoramento de trânsito] * .font[Sensoreamento remoto] * .font[Controle de qualidade em processos industriais] --- # Bibliotecas .left-column[ ### OpenCV 3.1 ] .right-column[ ![:img 30%, center](images/ocv.png) - **Open** **C**omputer **V**ision - Padrão na indústria e na academia - Algoritmos otimizados e no estado da arte - Processamento de imagens e vídeo - Aprendizado de máquina - Licença BSD ] ??? OpenCV é uma biblioteca de processamento de imagens com diversos algoritmos de visão computacional, desenvolvida em C/C++ também tem suporte para Java Python e Visual basic --- # Bibliotecas .left-column[ ### OpenCV 3.1 ### Python 2.7 ] .right-column[ .left-column[![:img 80%,center](images/np.png)] .right-column[## Numpy] É utilizado como alternativa as estruturas de dados fornecidas nativamente pelo OpenCV em C++. O wrapper do OpenCV para Python fez essa opção pois é uma biblioteca consolidada e permite manipulação rápida de dados mesmo em Python. ] ??? O objetivo de se utilizar o Numpy é de expressasr images como arrays multidimensionais, o que ajuda computacionalmente a realizar cálculos numericos na imagem. É a alternativa Python para as estruturas de dados fornecidas pelo OpenCV nativamente em C++. --- #Objetivo final ## Uma aplicação simples de realidade aumentada .left-column50[ Passos: * Adquirir imagem da câmera * Identificar **marcador** * Detectar bordas * Selecionar contornos * Transformação de perspectiva * Amostrar imagem * Reconhecer ID e orientação * Gerar estimativa de pose da câmera * Inserir modelo 3D sob imagem ] .right-column50[![:img 100%,center](images/augmented-reality.jpg)] --- # Aquisição da imagem * Imagens são representadas com matrizes, arrays do **Numpy** * **OpenCV** usa sistema **BGR** por padrão para imagens coloridas * Índices são **row-major**, ie, [row,column] ```python import cv2 cam = cv2.VideoCapture(0) # 0 -> index of camera s, img = cam.read() cv2.imwrite("filename.jpg",img) #save image print img[2,3,0] #Intensity at row 2, column 3, blue channel ``` .left-column50[![:img 90%, center](images/pixel.gif)] .right-column50[![:img 80%, center](images/pixel-color.gif)] --- # Preprocessamento ## Redimensionamento e conversão para escala de cinza ```python img = cv2.imread("filename.jpg") dim = (640, 480) resized = cv2.resize(img, dim) gray = cv2.cvtColor(resized ,cv2.COLOR_BGR2GRAY) cv2.imshow("Result", gray) cv2.waitKey(0) ``` --- ## Identificar Marcadores - Bordas - Canny .left-column50[![:img 95%, left](images/demo/original.png)] .right-column50[![:img 95%, right](images/demo/edges.png)] ```python img = cv2.GaussianBlur(img, (5,5), 0) edges = cv2.Canny(img, 100, 200) ``` - Segundo e terceiro argumento: limiarização das bordas - Específico da aplicação, obter empíricamente --- ## Identificar Marcadores - Obter contornos São conjuntos de pontos que se mantém conectados através da ligação entre pixels vizinhos que possuem mesma cor ou intensidade. .left-column50[![:img 95%,left](images/demo/edges.png)] .right-column50[![:img 95%,right](images/demo/contours.png)] .no-column[ ```python _, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) ``` * A função retorna uma lista contendo conjunto de pontos (**Numpy** array). * Segundo e terceiro argumentos permitem obter hierarquia entre contornos e utilizar módos de aproximação.] --- ### Identificar Marcadores - Selecionar contornos quadrilaterais Para reduzir o número de candidatos a marcadores selecionamos apenas os contornos quadrilaterais através de uma aproximação poligonal .left-column50[![:img 90%,left](images/demo/contours.png)] .right-column50[![:img 90%,right](images/demo/contours-filtered.png)] ```python candidates = [] for contour in contours: #Get perimeter and poligonal approximation perimeter = cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, 0.1*perimeter, True) #Save as candidate if quadrilateral if len(approx) == 4: approx = np.array(approx, dtype='float32').reshape(4,2) candidates.append(orderPointsCW(approx)) ``` --- ### Identificar Marcadores - Transformação de Perspectiva A transformação de perspectiva permite obter uma imagem planar do marcador que possibilatará sua identificação essa transformação é repetida para cada candidato a marcador. .left-column50[![:img 80%,left](images/demo/original_patch.png)] .right-column50[![:img 50%,right](images/demo/patch.png)] ```python #Form destination points and get perspective matrix height, width = 100, 100 dst = np.array([[0,0], [width-1,0], [width-1,height-1], [0, height-1]], dtype='float32') matrix = cv2.getPerspectiveTransform(contour, dst) #Perform perspective transform to get patch patch = cv2.warpPerspective(img, matrix, (height, width)) ``` --- ### Identificar Marcadores - Threshold automático Para obter uma imagem binária utilizamos o método de threshold automático de Otsu baseado na distribuição das intensidades dos pixels.
.left-column50[![:img 50%,center](images/demo/patch.png)] .right-column50[![:img 50%,center](images/demo/patch_threshold.png)] ```python _, patch = cv2.threshold(patch, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) ``` --- ### Identificação dos marcadores - Amostragem das células * Nosso marcador é composto de 7x7 células. * Para encontrar o código do marcador dividimos a imagem em células e selecionamos o pixel central de cada célula para estabelecer o valor daquela célula (0 ou 1). .left-column50[ ![:img 40%,center](images/demo/patch_threshold_grid.png) ] .right-column50[![:img 83%,center](images/code_numpy.png)] ```python cells = codes.cells cellsize = patch.shape[0]/cells code = np.zeros((cells,cells)) for i in range(cells): for j in range(cells): px = i*cellsize+0.5*cellsize py = j*cellsize+0.5*cellsize px, py = round(px), round(py) code[i,j] = patch[px, py]/255. print code ``` ??? ```python [[ 0. 0. 0. 0. 0. 0. 0.] [ 0. 1. 0. 0. 1. 1. 0.] [ 0. 0. 1. 1. 0. 0. 0.] [ 0. 0. 1. 0. 0. 1. 0.] [ 0. 0. 1. 0. 0. 1. 0.] [ 0. 0. 0. 1. 0. 1. 0.] [ 0. 0. 0. 0. 0. 0. 0.]] ``` --- ### Identificação dos marcadores - Reconhecimento * Com o padrão obtido no passo anterior pode-se validar o candidato como um marcador através da comparação com um dicionário de marcadores válidos. * Também é possível obter a orientação correspondente. ![:img 50%, center](images/demo/markers.png) --- # Estimativa de pose da câmera Com os marcadores detectados é possível fazer a identificação da cena e, através da calibração de câmera, obter uma matriz de transformação do espaço dos objetos para o espaço da imagem. (OpenCV *solvePnP*). ![:img 50%, center](images/pose.jpg) Isso permite, por exemplo, inserir modelos de objetos sob a cena e criar uma aplicação básica de realidade aumentada. --- ## Inserindo modelos 3D sob a imagem ### Computação gráfica com OpenGL e Python OpenGL é uma biblioteca complexa para computação gráfica e está fora do escopo da apresentação, porém, como bonus, trouxemos uma demonstração de seu funcionamento. .center[
Fallback text.
] --- class: center, middle ## Obrigado pela atenção ### Código disponível publicamente em https://github.com/eduardohenriquearnold/tdcfloripa