Neste tutorial, você aprenderá como executar costura de imagens usando as funções Python, OpenCV e as funções cv2.createStitcher
e cv2.Stitcher_create
. Usando o código de hoje você será capaz de costurar várias imagens juntas, criando um panorama de imagens costuradas.
Publicei há menos de dois anos dois guias sobre costura de imagens e construção de panoramas:
- Fundamentals of image stitching
- Visão panorâmica e costura de imagens em tempo real
Bambos destes tutoriais cobriram os fundamentos do algoritmo típico de costura de imagens, que, no mínimo, requerem quatro passos-chave:
- Detectar pontos-chave (DoG, Harris, etc.)) e extração de descritores invariantes locais (SIFT, SURF, etc.).) a partir de duas imagens de entrada
- Casar os descritores entre as imagens
- Utilizar o algoritmo RANSAC para estimar uma matriz homográfica usando nossos vetores de características correspondentes
- Aplicar uma transformação de deformação usando a matriz homográfica obtida no Passo #3
No entanto, o maior problema com minhas implementações originais é que elas não eram capazes de lidar com mais de duas imagens de entrada.
No tutorial de hoje, vamos revisitar a costura de imagens com OpenCV, incluindo como coser mais de duas imagens juntas em uma imagem panorâmica.
Para aprender a coser imagens com OpenCV e Python, basta continuar lendo!
- Procurando o código fonte para este post?
- Image Stitching with OpenCV and Python
- OpenCV’s image stitching algorithm
- Estrutura do projeto
- O cv2.createStitcher e cv2.Stitcher_create functions
- Implementando costura de imagem com Python
- Basic image stitching results
- Um ponto de imagem melhor com OpenCV e Python
- Resultados da costura de imagem melhorada
- Limitações e desvantagens
- Correr em erros ao executar costura de imagens usando OpenCV?
- Resumo
Procurando o código fonte para este post?
Saltar para a secção de downloads
Image Stitching with OpenCV and Python
Na primeira parte do tutorial de hoje, vamos rever brevemente o algoritmo de costura de imagens do OpenCV que é cozido na própria biblioteca do OpenCV através das funções cv2.createStitcher
e cv2.Stitcher_create
.
De lá vamos rever nossa estrutura de projeto e implementar um script Python que pode ser usado para costura de imagens.
Vamos rever os resultados deste primeiro script, anotar suas limitações, e então implementar um segundo script Python que pode ser usado para resultados de costura de imagens mais agradáveis esteticamente.
Finalmente, vamos rever os resultados do nosso segundo script e novamente anotar quaisquer limitações ou inconvenientes.
OpenCV’s image stitching algorithm
O algoritmo que vamos usar aqui hoje é semelhante ao método proposto por Brown e Lowe no seu trabalho de 2007, Automatic Panoramic Image Stitching with Invariant Features.
Insensível aos algoritmos de costura de imagens anteriores que são sensíveis à ordenação das imagens de entrada, o método Brown e Lowe é mais robusto, tornando-o insensível a:
- Ordenação de imagens
- Orientação de imagens
- Mudanças de iluminação
- Imagens ruidosas que não fazem parte do panorama
Outras vezes, o seu método de costura de imagens é capaz de produzir imagens panorâmicas de saída esteticamente mais agradáveis através do uso de compensação de ganho e mistura de imagens.
Uma revisão completa e detalhada do algoritmo está fora do escopo deste post, então se você estiver interessado em aprender mais, por favor consulte a publicação original.
Estrutura do projeto
Vejamos como este projeto está organizado com o comando tree
>
$ tree --dirsfirst.├── images│ └── scottsdale│ ├── IMG_1786-2.jpg│ ├── IMG_1787-2.jpg│ └── IMG_1788-2.jpg├── image_stitching.py├── image_stitching_simple.py└── output.png2 directories, 6 files
As imagens de entrada vão para a pasta images/
. Eu optei por fazer uma subpasta para o meu scottsdale/
conjunto de imagens no caso de eu querer adicionar subpastas adicionais aqui mais tarde.
Hoje vamos rever dois scripts Python:
-
image_stitching_simple.py
: A nossa versão simples de costura de imagens pode ser completada em menos de 50 linhas de código Python! -
image_stitching.py
: Este script inclui o meu hack para extrair um ROI da imagem cosida para um resultado esteticamente agradável.
O último ficheiro, output.png
, é o nome da imagem cosida resultante. Usando argumentos de linha de comando, você pode facilmente alterar o nome do arquivo + caminho da imagem de saída.
O cv2.createStitcher e cv2.Stitcher_create functions
OpenCV já implementou um método similar ao papel de Brown e Lowe através do método cv2.createStitcher
(OpenCV 3.x) e cv2.Stitcher_create
(OpenCV 4) funções.
Assumindo que você tenha o OpenCV corretamente configurado e instalado, você será capaz de investigar a assinatura da função cv2.createStitcher
para OpenCV 3.x:
createStitcher(...) createStitcher() -> retval
Note como esta função tem apenas um único parâmetro, try_gpu
que pode ser usado para melhorar toda a sua pipeline de costura de imagem. O suporte a GPU do OpenCV é limitado e eu nunca consegui fazer esse parâmetro funcionar, então recomendo sempre deixá-lo como False
.
A função cv2.Stitcher_create
para OpenCV 4 tem uma assinatura similar:
Stitcher_create(...) Stitcher_create() -> retval . @brief Creates a Stitcher configured in one of the stitching .modes. . . @param mode Scenario for stitcher operation. This is usually .determined by source of images to stitch and their transformation. .Default parameters will be chosen for operation in given scenario. . @return Stitcher class instance.
Para executar o pesponto da imagem real precisaremos chamar o método .stitch
:
OpenCV 3.x:stitch(...) method of cv2.Stitcher instance stitch(images) -> retval, panoOpenCV 4.x:stitch(...) method of cv2.Stitcher instance stitch(images, masks) -> retval, pano . @brief These functions try to stitch the given images. . . @param images Input images. . @param masks Masks for each input image specifying where to .look for keypoints (optional). . @param pano Final pano. . @return Status code.
Este método aceita uma lista de entrada images
, e então tenta costurá-las em um panorama, retornando a imagem panorâmica de saída para a função de chamada.
A variável status
indica se a costura da imagem foi ou não um sucesso e pode ser uma das quatro variáveis:
-
OK = 0
: A costura da imagem foi um sucesso. -
ERR_NEED_MORE_IMGS = 1
: No caso de receber este código de status, você precisará de mais imagens de entrada para construir seu panorama. Normalmente este erro ocorre se não forem detectados pontos-chave suficientes nas suas imagens de entrada. -
ERR_HOMOGRAPHY_EST_FAIL = 2
: Este erro ocorre quando a estimativa da homografia do RANSAC falha. Mais uma vez, você pode precisar de mais imagens ou suas imagens não têm textura/objetos distintos e únicos o suficiente para que os pontos-chave sejam precisamente combinados. -
ERR_CAMERA_PARAMS_ADJUST_FAIL = 3
: Eu nunca encontrei este erro antes, então eu não tenho muito conhecimento sobre ele, mas a essência é que ele está relacionado com a falha em estimar corretamente os intrínsecos/extrínsecos da câmera a partir das imagens de entrada. Se você encontrar este erro você pode precisar consultar a documentação do OpenCV ou mesmo mergulhar no código C++ do OpenCV.
Agora que revisamos os métodos cv2.createStitcher
, cv2.Stitcher_create
, e .stitch
, vamos passar para a implementação real da costura de imagens com OpenCV e Python.
Implementando costura de imagem com Python
Vamos prosseguir e começar a implementar nosso algoritmo de costura de imagem!
Abrir o arquivo image_stitching_simple.py
e inserir o seguinte código:
# import the necessary packagesfrom imutils import pathsimport numpy as npimport argparseimport imutilsimport cv2# construct the argument parser and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--images", type=str, required=True,help="path to input directory of images to stitch")ap.add_argument("-o", "--output", type=str, required=True,help="path to the output image")args = vars(ap.parse_args())
Nossos pacotes necessários são importados nas Linhas 2-6. Notavelmente, estaremos usando OpenCV e imutils. Se você ainda não o fez, vá em frente e instale-os:
- Para instalar OpenCV, basta seguir um dos meus guias de instalação do OpenCV.
- O pacote imutils pode ser instalado/atualizado com o pip:
pip install --upgrade imutils
. Certifique-se de atualizá-lo pois novas funcionalidades são frequentemente adicionadas.
De lá vamos analisar dois argumentos de linha de comando nas linhas 9-14:
-
--images
: O caminho para o diretório de imagens de entrada para costurar. -
--output
: O caminho para a imagem de saída onde o resultado será salvo.
Se você não está familiarizado com os conceitos de argparse
e argumentos de linha de comando então leia este post do blog.
La vamos carregar nossas imagens de entrada:
# grab the paths to the input images and initialize our images listprint(" loading images...")imagePaths = sorted(list(paths.list_images(args)))images = # loop over the image paths, load each one, and add them to our# images to stitch listfor imagePath in imagePaths:image = cv2.imread(imagePath)images.append(image)
Aqui vamos pegar nossa imagePaths
(Linha 18).
Então para cada imagePath
, vamos carregar a image
e adicioná-la à lista de images
(Linhas 19-25).
Agora os images
estão na memória, vamos em frente e costurá-los juntos em um panorama usando a capacidade incorporada do OpenCV:
# initialize OpenCV's image stitcher object and then perform the image# stitchingprint(" stitching images...")stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()(status, stitched) = stitcher.stitch(images)
O objeto stitcher
é criado na Linha 30. Note que dependendo se você está usando OpenCV 3 ou 4, um construtor diferente é chamado.
Subseqüentemente, podemos passar nosso images
para o método .stitch
(Linha 31). A chamada para .stitch
retorna tanto um status
como a nossa imagem stitched
(assumindo que a costura foi bem sucedida).
Finalmente, vamos ambos (1) escrever a imagem costurada no disco e (2) exibi-la na tela:
# if the status is '0', then OpenCV successfully performed image# stitchingif status == 0:# write the output stitched image to diskcv2.imwrite(args, stitched)# display the output stitched image to our screencv2.imshow("Stitched", stitched)cv2.waitKey(0)# otherwise the stitching failed, likely due to not enough keypoints)# being detectedelse:print(" image stitching failed ({})".format(status))
Assumindo que a nossa bandeira status
indica sucesso (Linha 35), vamos escrever a stitched
imagem no disco (Linha 37) e exibi-la até que uma tecla seja pressionada (Linhas 40 e 41).
Outros, vamos simplesmente imprimir uma mensagem de falha (Linhas 45 e 46).
Basic image stitching results
Para dar uma tentativa ao nosso script de costura de imagens, certifique-se de usar a secção “Downloads” do tutorial para descarregar o código fonte e imagens de exemplo.
No diretório images/scottsdale/
você encontrará três fotos que tirei ao visitar a famosa casa Taliesin West do Frank Lloyd Wright em Scottsdale, AZ:
O nosso objectivo é coser estas três imagens numa única imagem panorâmica. Para executar a costura, abra um terminal, navegue até onde você baixou o código + imagens, e execute o seguinte comando:
$ python image_stitching_simple.py --images images/scottsdale --output output.png loading images... stitching images...
Notem como fizemos costura de imagem com sucesso!
Mas e as regiões pretas em torno do panorama? O que são essas?
As regiões são de executar as urdiduras de perspectiva necessárias para construir o panorama.
Há uma maneira de nos livrarmos delas…mas vamos precisar de implementar alguma lógica adicional na próxima secção.
Um ponto de imagem melhor com OpenCV e Python
O nosso primeiro script de costura de imagem foi um bom começo, mas aquelas regiões pretas que rodeiam o panorama em si não são algo a que chamaríamos de “esteticamente agradáveis”.
E mais ao ponto, você não veria tal imagem de saída de aplicações populares de costura de imagens embutidas no iOS, Android, etc.
Por isso, vamos hackear um pouco o nosso script e incluir alguma lógica adicional para criar panoramas esteticamente mais agradáveis.
Vou reiterar novamente que este método é um hack.
Estaremos revendo operações básicas de processamento de imagens incluindo threshold, extração de contornos, operações morfológicas, etc., para obter o resultado desejado.
Ao meu conhecimento, os bindings Python do OpenCV não nos fornecem a informação necessária para extrair manualmente o máximo da região retangular interna do panorama. Se o OpenCV o faz, por favor me informe nos comentários como eu adoraria saber.
Vamos prosseguir e começar – abra o script image_stitching.py
e insira o seguinte código:
# import the necessary packagesfrom imutils import pathsimport numpy as npimport argparseimport imutilsimport cv2# construct the argument parser and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--images", type=str, required=True,help="path to input directory of images to stitch")ap.add_argument("-o", "--output", type=str, required=True,help="path to the output image")ap.add_argument("-c", "--crop", type=int, default=0,help="whether to crop out largest rectangular region")args = vars(ap.parse_args())# grab the paths to the input images and initialize our images listprint(" loading images...")imagePaths = sorted(list(paths.list_images(args)))images = # loop over the image paths, load each one, and add them to our# images to stich listfor imagePath in imagePaths:image = cv2.imread(imagePath)images.append(image)# initialize OpenCV's image sticher object and then perform the image# stitchingprint(" stitching images...")stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()(status, stitched) = stitcher.stitch(images)
Todo este código é idêntico ao nosso script anterior com uma exceção.
O argumento --crop
da linha de comando foi adicionado. Quando um 1
é fornecido para este argumento no terminal, iremos em frente e executaremos nosso hack de corte.
O próximo passo é onde começamos a implementar funcionalidades adicionais:
# if the status is '0', then OpenCV successfully performed image# stitchingif status == 0:# check to see if we supposed to crop out the largest rectangular# region from the stitched imageif args > 0:# create a 10 pixel border surrounding the stitched imageprint(" cropping...")stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10,cv2.BORDER_CONSTANT, (0, 0, 0))# convert the stitched image to grayscale and threshold it# such that all pixels greater than zero are set to 255# (foreground) while all others remain 0 (background)gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
Notem como eu fiz um novo bloco para quando a bandeira --crop
estiver definida na linha 40. Vamos começar por este bloco:
- Primeiro, vamos adicionar uma borda de
10
pixel a todos os lados da nossa imagemstitched
(Linhas 43 e 44), assegurando que vamos ser capazes de encontrar os contornos do panorama completo mais tarde nesta secção. - Então vamos criar uma versão
gray
da nossastitched
imagem (Linha 49). - E a partir daí vamos limitar a
gray
imagem (Linha 50).
Aqui está o resultado (thresh
) desses três passos:
Temos agora uma imagem binária do nosso panorama onde os pixels brancos (255) são o primeiro plano e os pixels pretos (0) são o fundo.
Dando a nossa imagem limiar podemos aplicar a extracção de contorno, calcular a caixa delimitadora do maior contorno (i.e, o próprio contorno do panorama), e desenhar a caixa de contorno:
# find all external contours in the threshold image then find# the *largest* contour which will be the contour/outline of# the stitched imagecnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)# allocate memory for the mask which will contain the# rectangular bounding box of the stitched image regionmask = np.zeros(thresh.shape, dtype="uint8")(x, y, w, h) = cv2.boundingRect(c)cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
Contornos são extraídos e analisados nas Linhas 55-57. A linha 58 então agarra o contorno com a maior área (ou seja, o contorno da própria imagem costurada).
Note: A função imutils.grab_contours
é nova em imutils==0.5.2
para acomodar OpenCV 2.4, OpenCV 3, e OpenCV 4 e suas diferentes assinaturas de retorno para cv2.findContours
.
Linha 62 aloca memória para nossa nova máscara retangular. A linha 63 calcula então a caixa de delimitação do nosso maior contorno. Usando a informação do rectângulo de delimitação, na linha 64, desenhamos um rectângulo branco sólido na máscara.
A saída do bloco de código acima pareceria o seguinte:
Esta caixa de delimitação é a menor região rectangular que todo o panorama pode caber.
Agora, aqui vem um dos maiores hacks que já montei para um post de blog:
# create two copies of the mask: one to serve as our actual# minimum rectangular region and another to serve as a counter# for how many pixels need to be removed to form the minimum# rectangular regionminRect = mask.copy()sub = mask.copy()# keep looping until there are no non-zero pixels left in the# subtracted imagewhile cv2.countNonZero(sub) > 0:# erode the minimum rectangular mask and then subtract# the thresholded image from the minimum rectangular mask# so we can count if there are any non-zero pixels leftminRect = cv2.erode(minRect, None)sub = cv2.subtract(minRect, thresh)
Nas linhas 70 e 71 criamos duas cópias do nosso mask
image:
- A primeira máscara,
minMask
, será lentamente reduzida em tamanho até que possa caber dentro da parte interna do panorama (veja a Figura 5 no topo desta seção). - A segunda máscara,
sub
, será usada para determinar se precisamos continuar reduzindo o tamanho deminMask
.
Linha 75 inicia um looping de while
que continuará looping até não haver mais pixels em primeiro plano em sub
.
Linha 79 realiza uma operação morfológica de erosão para reduzir o tamanho de minRect
.
Linha 80 então subtrai thresh
de minRect
– assim que não houver mais pixels em primeiro plano em minRect
então podemos quebrar o loop.
Incluí uma animação do hack abaixo:
No topo, temos a nossa imagem sub
e no fundo temos a imagem minRect
.
Notem como o tamanho de minRect
é progressivamente reduzido até não haver mais pixels em primeiro plano em sub
– neste ponto sabemos que encontramos a menor máscara rectangular que pode caber na maior região rectangular do panorama.
Dado o rectângulo interior mínimo podemos novamente encontrar contornos e calcular a caixa de delimitação, mas desta vez vamos simplesmente extrair o ROI da stitched
imagem:
# find contours in the minimum rectangular mask and then# extract the bounding box (x, y)-coordinatescnts = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)(x, y, w, h) = cv2.boundingRect(c)# use the bounding box coordinates to extract the our final# stitched imagestitched = stitched
Aqui temos:
- Contornos encontrados em
minRect
(Linhas 84 e 85). - Contornos de análise de contornos para múltiplas versões OpenCV (Linha 86). Você precisará de
imutils>=0.5.2
para usar esta função. - Abrancar o maior contorno (Linha 87).
- Calcular a caixa de delimitação do maior contorno (Linha 88).
- Extraiu o ROI do nosso
stitched
usando a informação da caixa de delimitação (Linha 92).
A imagem final stitched
pode ser exibida na nossa tela e depois salva no disco:
# write the output stitched image to diskcv2.imwrite(args, stitched)# display the output stitched image to our screencv2.imshow("Stitched", stitched)cv2.waitKey(0)# otherwise the stitching failed, likely due to not enough keypoints)# being detectedelse:print(" image stitching failed ({})".format(status))
Linhas 95-99 handle salvando e exibindo a imagem independentemente do nosso hack de corte ser ou não realizado.
Apenas como antes, se a bandeira status
não voltou como um sucesso, vamos imprimir uma mensagem de erro (Linhas 103 e 104).
Vamos continuar e verificar os resultados da nossa costura de imagem melhorada + pipeline OpenCV.
Resultados da costura de imagem melhorada
Again, certifique-se de que usou a secção “Downloads” do tutorial de hoje para descarregar o código fonte e imagens de exemplo.
De lá, abra um terminal e execute o seguinte comando:
$ python image_stitching.py --images images/scottsdale --output output.png \--crop 1 loading images... stitching images... cropping...
Note como desta vez removemos as regiões pretas das imagens costuradas de saída (causadas pelas transformações de deformação) aplicando o nosso hack detalhado na seção acima.
Limitações e desvantagens
Num tutorial anterior, demonstrei como se podia construir um panorama em tempo real e um algoritmo de costura de imagens – este tutorial baseava-se no facto de estarmos a realizar manualmente a detecção de pontos-chave, extracção de características e correspondência de pontos-chave, dando-nos acesso à matriz homográfica utilizada para empenar as nossas duas imagens de entrada num panorama.
E enquanto as funções do OpenCV incorporadas cv2.createStitcher
e cv2.Stitcher_create
são certamente capazes de construir panoramas precisos e esteticamente agradáveis, uma das principais desvantagens do método é que ele abstrai qualquer acesso às matrizes homográficas.
Uma das suposições da construção de panoramas em tempo real é que a cena em si não está mudando muito em termos de conteúdo.
Após calcularmos a estimativa inicial da homografia, devemos apenas ocasionalmente recompor a matriz.
Não ter que executar uma correspondência de pontos-chave e a estimativa RANSAC nos dá um tremendo impulso de velocidade na construção de nosso panorama, então sem acesso às matrizes de homografia bruta, seria um desafio pegar o algoritmo de costura de imagem embutido no OpenCV e convertê-lo para o tempo real.
Correr em erros ao executar costura de imagens usando OpenCV?
É possível que você encontre erros ao tentar usar a função cv2.createStitcher
ou cv2.Stitcher_create
funções.
Os dois erros “fáceis de resolver” que vejo as pessoas se esquecem de qual versão do OpenCV elas estão usando.
Por exemplo, se você estiver usando OpenCV 4 mas tentar ligar para cv2.createSticher
você vai encontrar a seguinte mensagem de erro:
>>> cv2.createStitcherTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: module 'cv2' has no attribute 'createStitcher'
Você deveria estar usando a função cv2.Stitcher_create
.
Simplesmente, se você estiver usando OpenCV 3 e tentar ligar para cv2.Sticher_create
você vai receber este erro:
>>> cv2.Stitcher_createTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: module 'cv2' has no attribute 'Stitcher_create'
Em vez disso, use a função cv2.createSticher
.
Se você não tiver certeza de qual versão do OpenCV você está usando você pode verificar usando cv2.__version__
:
>>> cv2.__version__'4.0.0'
Aqui você pode ver que eu estou usando o OpenCV 4.0.0.
Você pode executar a mesma verificação no seu sistema.
O erro final que você pode encontrar, e sem dúvida o mais comum, está relacionado ao OpenCV (1) não ter suporte a contrib e (2) ser compilado sem a opção OPENCV_ENABLE_NONFREE=ON
habilitada.
Para resolver este erro você deve ter os módulos opencv_contrib
instalados junto com a opção OPENCV_ENABLE_NONFREE
definida como ON
.
Se você estiver encontrando um erro relacionado aos módulos não livres e contrib do OpenCV, certifique-se de consultar meus guias de instalação do OpenCV para garantir que você tenha a instalação completa do OpenCV.
Nota: Por favor note que eu não posso ajudar a depurar a sua própria instalação do OpenCV se você não seguiu um dos meus guias de instalação, então certifique-se de que você está usando meus guias de instalação do OpenCV ao configurar seu sistema.
Resumo
No tutorial de hoje você aprendeu como executar a costura de múltiplas imagens usando OpenCV e Python.
Usando ambos OpenCV e Python fomos capazes de coser várias imagens juntas e criar imagens panorâmicas.
As nossas imagens panorâmicas de saída não só eram precisas na sua colocação de costura, mas também esteticamente agradáveis também.
No entanto, um dos maiores inconvenientes de usar a classe de costura de imagens embutida do OpenCV é que ela abstrai grande parte do cálculo interno, incluindo as próprias matrizes homográficas resultantes.
Se você estiver tentando realizar costura de imagens em tempo real, como fizemos em um post anterior, você pode achar benéfico fazer o cache da matriz homográfica e só ocasionalmente realizar a detecção de pontos-chave, extração de características e combinação de características.
Cortar estas etapas e usar a matriz em cache para realizar a distorção de perspectiva pode reduzir a carga computacional do seu pipeline e, em última instância, acelerar o algoritmo de costura de imagem em tempo real, mas infelizmente, as encadernações do OpenCV cv2.createStitcher
Python não nos fornecem acesso às matrizes em bruto.
Se você está interessado em aprender mais sobre a construção de panoramas em tempo real, por favor consulte meu post anterior.
Espero que você tenha gostado do tutorial de hoje sobre costura de imagens!
Para baixar o código fonte do post de hoje, e ser notificado que os tutoriais são publicados aqui no PyImageSearch, basta digitar seu endereço de e-mail no formulário abaixo!