Visão computacional 101: vamos criar um trocador de rostos em Python | Alvin Wan | Skillshare
Menu
Pesquisar

Velocidade de reprodução


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Visão computacional 101: vamos criar um trocador de rostos em Python

teacher avatar Alvin Wan, Research Scientist

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Aulas neste curso

    • 1.

      Introdução

      1:16

    • 2.

      O que é visão computacional?

      5:04

    • 3.

      Noções básicas de código OpenCV

      10:08

    • 4.

      Como funcionam os trocadores de rostos?

      4:12

    • 5.

      Codificação da detecção de rosto

      9:59

    • 6.

      Como os detectores de rosto funcionam?

      4:59

    • 7.

      Codificação da troca de rosto

      12:40

    • 8.

      Próximos passos

      0:33

  • --
  • Nível iniciante
  • Nível intermediário
  • Nível avançado
  • Todos os níveis

Gerado pela comunidade

O nível é determinado pela opinião da maioria dos estudantes que avaliaram este curso. Mostramos a recomendação do professor até que sejam coletadas as respostas de pelo menos 5 estudantes.

1.156

Estudantes

--

Sobre este curso

Como funciona uma troca de rosto que vai trabalhar? O que é visão de computador?

Neste curso, vamos explorar os fundamentos de visão de computador enquanto cria um aplicativo de de troca de rosto de Snapchat, que é de uma a que o Snapchat, este filtro vai detectar pares e de as de a que se a e a a fazer o que você vai de uma Este curso foi feito para iniciantes que têm uma pouco familiaridade com aprendizagem e codificação. Se já se familiar, isso está tudo certo, esses dois cursos você vai se aproximar:

  1. Para aprender a Python, sugiro fazer a minha programação 1: curso Python para iniciantes.
  2. Para aprender os conceitos básicos de inteligência de máquinas e a aprendizagem de máquinas, faça meu curso de mestrado de inteligência learn de máquinas. Ferramentas para dominar o curso de máquinas de aprendizagem.

Vamos abordar muitos tópicos e takeaways:

  • Crie uma aplicação de de a troca de rosto
  • Qual visão de computador
  • Como a de a que de a de a o de a o mundo
  • Compressa o problema de detecção de rosto
  • Entender taxonomies de problemas de visão de computador
  • Conceitos de visão de computador como de filtros, extração de recursos e detecção

Ao final deste curso, você terá uma aplicação de troca de rosto para que você brinquem com a volta. Mostre isso para os amigos e família!

Ainda não sabe se este curso é para você? Experimente um vídeo de quatro minutos curto. Se isso de a curios, este curso é definitivamente seu de a de de volta!

Se você quiser fazer o seu código no seu próprio computador, certifique-se de seguir as instruções de instalação antes de começar a aula.

Interessado em programação criativa? Confira meu VR 101 (a natural de a a natureza) a o meu a a a de a a

Interessando em mais ciência de dados ou aprendizagem de máquinas? Confira meu de coping 101. a Python, SQL 101 (design de banco de banco ) ou dados 101 (de de out

Siga-me na Skillshare para ser o primeiro que a conhecer mais cursos em mais áreas!

Conheça seu professor

Teacher Profile Image

Alvin Wan

Research Scientist

Top Teacher

Hi, I'm Alvin. I was formerly a computer science lecturer at UC Berkeley, where I served on various course staffs for 5 years. I'm now a research scientist at a large tech company, working on cutting edge AI. I've got courses to get you started -- not just to teach the basics, but also to get you excited to learn more. For more, see my Guide to Coding or YouTube.

Welcoming Guest Teacher Derek! I was formerly an instructor for the largest computer science course at UC Berkeley, where I taught for several years and won the Distinguished GSI (graduate student instructor) award. I am now a software engineer working on experimentation platforms at a large tech company. 4.45 / 5.00 average rating (943 reviews) at UC Berkeley. For more, see my Skillshare or Webs... Visualizar o perfil completo

Habilidades relacionadas

Computador Fotografia IA para fotografia
Level: Intermediate

Nota do curso

As expectativas foram atingidas?
    Superou!
  • 0%
  • Sim
  • 0%
  • Um pouco
  • 0%
  • Não
  • 0%

Por que fazer parte da Skillshare?

Faça cursos premiados Skillshare Original

Cada curso possui aulas curtas e projetos práticos

Sua assinatura apoia os professores da Skillshare

Aprenda em qualquer lugar

Faça cursos em qualquer lugar com o aplicativo da Skillshare. Assista no avião, no metrô ou em qualquer lugar que funcione melhor para você, por streaming ou download.

Transcrições

1. Introdução: Aqui está uma troca de rosto. Você já viu isso em fotos, vídeos, fotos, o que quiser. É bobagem, divertido, e às vezes muito assustador. Você pode trocar rostos com seu amigo, uma celebridade, seu bebê ou até mesmo seu cachorro. Vamos construir essa troca de rosto. Olá, sou Aldo, professor de Ciência da Computação e estudante de doutorado na UC Berkeley. Eu ajudo o computador ver, estudando visão computacional para a realidade virtual e auto-condução carros. Já cortei mais de 15 mil alunos e mal posso esperar para te mostrar a magia também. Nesta aula, você vai aprender o básico da visão computacional. Eu coloquei essa classe para qualquer um interessado; programadores, designers, líderes de negócios, qualquer um, se você não conhece Python, não há problema. Apanhe-se com o meu curso de Coding 101, Python para iniciantes. Não sabe AML? Isso também está bem. Pegue minhas ferramentas de inteligência artificial de masterclass para aprendizado de máquina. No final desta aula, você entenderá imagens, processamento de imagens, detecção de rostos e muito mais. Você também terá um aplicativo de área de trabalho totalmente funcional que pode trocar rostos para imagens enquadrar as partes. Isso levará apenas uma hora; nada para instalar, nenhuma configuração complicada. Você só precisa de um laptop com internet. Irá embora com um trocador facial e conhecimento em visão computacional num instante. Espero que esteja animada porque sei que estou. Vamos fazer isto. 2. O que é visão computacional?: Vamos começar respondendo, o que é visão computacional? Aqui está a definição. Visão computacional, amplamente definida é a visão da IA. Há uma série de tarefas de visão computacional que refletem isso, como detecção de objetos, que caixas e classifica todos os objetos na cena como a flor à esquerda. Super resolução, que alucina detalhes para tornar suas imagens mais nítidas, como a cor nítida à direita, contrastou com os arbustos borrados à esquerda. Estimativa de pontos-chave que identifica pontos-chave como articulações e membros, como o dançarino antigo à esquerda. Podemos agora reresponder o que é visão computacional de uma forma aplicada? Visão computacional é mais especificamente extrair informações de ou gerar imagens. Para entender melhor esse campo, vamos analisar a estrutura para aprendizado de máquina que abordamos em nossa classe mestre de IA. Se você ainda não fez este curso, eu recomendo fazê-lo. Em nossa masterclass de IA, discutimos a compartimentação de nosso conhecimento de ML em quatro categorias. Dados, modelo, objetivo e algoritmo. Os dados descrevem as entradas e saídas, o que aprendemos e o que prevemos. Modelo descreve como fazer previsões. Objetivo descreve o objetivo, o que o modelo está otimizando para. Finalmente, o algoritmo descreve como o modelo aprende. Não discutimos muito o algoritmo, e vamos ignorá-lo novamente desta vez. Na visão computacional, os dados são sempre visuais, nomeadamente imagens e vídeos. Além disso, podemos usar outros sinais relacionados como áudio ou profundidade, sobre imagens e vídeos. Vamos nos concentrar nos dados desta lição. Nossos modelos na visão computacional clássica e no aprendizado profundo hoje extraem padrões da imagem usando uma ferramenta chamada filtros. Discutiremos isso nas aulas posteriores. Finalmente, nosso objetivo é geralmente maximizar a precisão. Como sempre, pularemos os algoritmos. Para entender o resto da visão computacional, precisamos entender como as imagens são representadas. O que é uma imagem? Como uma imagem é representada como números? Vejamos um exemplo. Podemos construir uma imagem em preto e branco usando números onde zero corresponde a preto e um corresponde a branco. Concentre-se na linha divisória entre uns e zeros. Que forma você vê? Salvar esta matriz de números como uma imagem nos dá isso. Acontece que é um diamante. E se quisermos imagens em tons de cinza, não apenas preto e branco? Bem, ainda usando zero para preto e um para branco, também podemos usar qualquer valor entre zero e um, como 0.1,0.26, ou 0.74391. números mais próximos de zero são mais escuros e os números mais próximos de um ou mais claros. Isso nos permite representar branco, preto e qualquer sombra de cinza. Considere o seguinte, por exemplo, você pode dizer o que é isso? Novamente, cada número corresponde ao brilho de um pixel. Salvar esta caixa de números como uma imagem nos dá isso, uma bola de pokey. Este é impossível de ver apenas a partir dos números no slide anterior, mas agora você sabe como as imagens em escala em preto e branco e cinza são representadas numericamente. Para introduzir cores, precisamos de uma maneira de codificar mais informações. Aqui está como. Primeiro, cada imagem tem uma altura e largura. Esta imagem é h por w. Cada pixel, como vimos antes em uma imagem em escala de cinza tem um valor. Podemos dizer equivalentemente que nossa imagem tem dimensões H por W por um. Atualizar esta imagem em tons de cinza para uma imagem colorida envolve o seguinte. Para uma representação de cores, representamos a cor de cada pixel usando três valores entre zero e um. Um número corresponde ao grau de vermelho, um ao grau de verde e o último ao grau de azul. Chamamos isso de espaço de cores RGB. Isso significa que para cada pixel em nossa imagem, temos três valores, R, G e B. Como resultado, nossas imagens agora H por W por três. É assim que se obtém uma imagem colorida como esta. Na realidade, cada valor varia de 0- 255 em vez de 0-1. Mas a ideia é a mesma. Diferentes combinações de números correspondem a cores diferentes, como 171, 180, 190 azul claro completo, ou 200, 199,188, marrom claro completo. Em resumo, cada imagem será representada como uma caixa de números que tem três dimensões, altura, largura e três canais de cores. Manipular esta caixa de números diretamente equivale a manipular a imagem, e é assim que as imagens são representadas como números. Em resumo, definimos visão computacional como extração de informações ou geração de imagens. Nós abordamos abstrações de ML para visão computacional, dados, modelo, objetivo e algoritmo. Finalmente, discutimos como as imagens são representadas numericamente. Com todo esse conhecimento, você está bem equipado para começar a trabalhar com codificação de imagens. Para obter uma cópia desses slides e mais recursos mistura check-out este URL. Isso conclui esta introdução. Vamos começar a codificação na próxima lição. 3. Noções básicas de código OpenCV: Bem-vindo à primeira lição de codificação deste curso. Vamos sujar as mãos com algum código. Se você gostaria de uma introdução rápida à programação em Python, certifique-se de conferir meu curso Python para iniciantes antes antes de iniciar esta lição. Você pode pausar o vídeo aqui para acessar esse URL. Em um nível alto, vamos gerar uma imagem e então vamos tentar nossa webcam. O objetivo é explorar utilitários OpenCV fundamentais. Comece acessando este URL. Isso criará um ambiente para nós remotamente para que não tenhamos que fazer nenhuma configuração em nossos computadores. Você vai ver do lado direito, eu já fiz isso. Para este tutorial, eu recomendo o uso do Google Chrome. Infelizmente, testei o código em alguns navegadores diferentes e apenas o Google Chrome é suportado no momento. Seu objetivo será gerar essa imagem. O primeiro passo é criar a representação numérica da imagem assim. Lembre-se de antes que uns e zeros podem fazer uma imagem em preto e branco como discutimos, zero aqui é preto e um é branco. No entanto, na realidade, os números variam de 0 a 255, então vamos usar 255 para branco e zero para preto. Vamos criar esta matriz em código agora. No lado direito, eu vou clicar no X, bem, eu estou aqui no canto superior direito para que possamos fechar esta janela de visualização. À esquerda, clique em Novo arquivo e digite generate.py. Isso criará um novo arquivo para nós. Vamos agora minimizar este navegador de arquivos. Agora vou ampliar meu código para que você possa ver melhor o que estou fazendo. Para começar, em seu generate.py, importe numpy, que contém seus utilitários de álgebra linear. Por convenção, nós renomeamos numpy para np por conveniência mais tarde. Em seguida, importe OpenCV, que contém seus utilitários de visão computacional e imagem. Primeiro criaremos uma representação numérica da nossa imagem. Vá em frente e digite a imagem é igual a uma matriz numpy e esta matriz numpy vai levar em uma lista de listas que especifica os números que temos no lado esquerdo. Digitando esses números agora. Depois de inserir os números, defina um tipo de dados. Este tipo de dados será um inteiro sem sinal. Este tipo de dados aqui é importante. Definimos o tipo de dados como um inteiro sem porque todos os nossos inteiros nesta imagem são positivos. Isso é necessário para OpenCV ou cv2 salvar com sucesso sua matriz como uma imagem. Em seguida, redimensionaremos nossa imagem. Aqui está como redimensionar, chamar cv2.resize na imagem para redimensionar e passar o tamanho desejado da imagem. Neste caso, a nossa imagem é alta. Então queremos uma largura de 90 pixels e uma altura de 150 pixels. Mas se rodarmos este código, ficaríamos muito desapontados. Nosso oito de tamanho superior ficaria feio assim. Em vez disso, queremos um oito afiado. Então vamos aumentar o tamanho usando outra técnica de redimensionamento chamada vizinhos mais próximos. Para fazer isso, vamos adicionar um terceiro argumento à nossa função de redimensionamento. Novamente, aqui está o redimensionamento. Passamos a imagem para redimensionar o tamanho final e o terceiro argumento diz cv2 para usar a técnica de amostragem mais próxima do vizinho. Vamos tentar isso em código agora. Agora vamos escrever, imagem é igual a cv2.resize imagem vírgula 90, 150. Então, finalmente, o método de interpolação, que é CV2.INTER_Nearest. Você verá, infelizmente, que meu código está cortado do lado direito. Isto aqui diz que a interpolação é igual a CV2.INTER_Nearest. Com nossa imagem redimensionada, tudo o que resta é salvá-la. Para salvar a imagem, use cv2.imwrite, como mostrado aqui. O primeiro argumento é o caminho, e o segundo argumento é a imagem. Vamos tentar isto. Após o seu código existente, digite cv2.imwrite irá fornecer o caminho da imagem e a imagem em si e é isso. Estamos prontos para executar este código. Terminamos de escrever nosso código em um arquivo Python chamado generate.py. Nas lições anteriores do Python, especialmente aquelas no Repl.it, nós apertaríamos o botão verde run na parte superior da tela para executar o arquivo Python. Nós não temos um bom botão verde, então vamos fazer isso manualmente e executar nosso arquivo Python através da linha de comando. Para iniciar a linha de comando, reabra o navegador de arquivos no lado esquerdo clicando na seta. Depois de fazer isso, você verá a caixa de diálogo de uma ferramenta no canto inferior esquerdo, clique em Ferramentas e, no menu suspenso, selecione Terminal. Naquele Terminal, você verá alguma configuração como eu vejo aqui. Vou diminuir um pouco. Depois de ver este terminal, agora você pode inserir seu comando. Em particular, o comando é Python e o argumento é o caminho do arquivo, que é generate.py neste caso. Vá em frente e digite Python generate.py e pressione Enter. Depois de executar o código, você deverá ver um 8.png na barra lateral esquerda. Clique nele para ver sua imagem gerada e voila, você gerou sua primeira imagem. Vamos agora começar a manipular as saídas da webcam. Navegue até este URL. Depois de carregar a página, feche a pré-visualização no lado direito, clicando no X no canto superior direito. No lado esquerdo, vamos agora criar um novo arquivo. Nesta parte da lição, nosso objetivo é conectar nossos utilitários OpenCV à webcam. Vamos começar iniciando um aplicativo web mínimo usando uma biblioteca personalizada criada apenas para este curso chamado Web OpenCV. No lado direito, clique em Novo arquivo e digite app.py. Aqui eu vou minimizar esta barra lateral clicando na seta no canto superior esquerdo. Nesta parte da lição, nosso objetivo é conectar-se à nossa webcam usando os utilitários OpenCV fornecidos nesta lição. Vamos começar iniciando um aplicativo web mínimo usando uma biblioteca personalizada criada apenas para este curso chamado Web OpenCV. Importar webopencv como WCV. Em seguida, importaremos o OpenCV para nossos utilitários gerais de visão computacional. Então importe cv2. Em seguida, vamos instanciar seu aplicativo web. Você pode fazer isso digitando no aplicativo é igual a WCV.WebApplication. Finalmente, você pode executar seu aplicativo web, app.run, e é isso. Para visualizar seu novo aplicativo, clique em Mostrar no canto superior esquerdo. Para mim, minimizei tanto a minha tela que só consigo ver um par de óculos de sol. Clique em Em uma Nova Janela. Esta é a minha nova janela. Infelizmente, o topo é cortado, nesta nova janela, clique em Mostrar e, em seguida, clique em Permitir. Quando terminar, clique em Parar para parar a webcam. Se você está preocupado com a privacidade, não se preocupe, os dados nessa webcam só estão sendo comunicados do seu computador para o seu próprio servidor de falhas, que é o que você está codificando agora. Então, apenas seu código e o servidor estão processando sua webcam. Ninguém mais vê isso. Agora você é o desenvolvedor. Agora adicione sua primeira transformação de imagem ao aplicativo web. Esta transformação acabará por escrever texto na imagem que recebe. Mas, por enquanto, vamos transformar que não faz nada. Crie uma função chamada Hello. Ele leva em dois argumentos, a imagem e outro objeto chamado o quadro, e retorna a imagem. Todas as transformações, exceto imagens como entrada e retornam a imagem processada. Também precisamos de um decorador chamado app.transform. Vamos pular os detalhes técnicos de como um decorador funciona. Por enquanto, basta saber que este decorador registra são transformados com o nosso aplicativo web. Qualquer transformação registrada aparecerá em nossa interface web. Além disso, o texto em rosa será usado como o nome dos transformadores. Vamos tentar isso agora em código. Abaixo de onde seu aplicativo está definido, adicione seu novo decorador, com o nome da transformação Olá. Agora vamos aplicar um argumento de palavra-chave, padrão é verdadeiro. Isso garante que a transformação Hello seja aplicada automaticamente quando a webcam é carregada. Defina sua função hello, que leva na imagem e outro argumento chamado o quadro, e finalmente, retorna a imagem. Agora, se você atualizar a página em uma nova janela, verá que a transformação Hello é escolhida por padrão. Aqui temos “Olá”. Em seguida, vamos escrever algum texto HelloWorld na transmissão ao vivo da webcam. Veja como fazer isso. Aqui está a imagem a anotar. O texto que queremos mostrar, a posição do texto, a fonte que queremos usar e o tamanho da fonte efetivamente. Isso é realmente dado como uma escala relativa ao tamanho padrão da fonte. Finalmente, temos a cor em RGB. Então aqui 255, 0, 0 significa vermelho. Na função Hello agora irá adicionar texto à imagem logo acima onde você retorna ou tipo de imagem e CV2.putText. Vamos passar na imagem, a string Hello World, a posição, a fonte. Vamos dar-lhe um tamanho de fonte de um. Finalmente, usaremos a cor verde. Aqui, vamos usar 0, 255, 0. Agora, navegue até seu aplicativo da Web. Clique em Iniciar e você verá o texto Hello World aplicado. Lá vamos nós. Aqui estão os passos que cobrimos. Cobrimos OpenCVS, escrita de imagens e utilitários de adição de texto. Não há necessidade de memorizar isto. Você sempre pode procurá-los. Eu só queria te dar alguma prática para trabalhar com esses utilitários. Para obter uma cópia desses slides, o código finalizado e mais recursos, verifique esse URL. Isso é tudo para o básico do OpenCV. 4. Como funcionam os trocadores de rostos?: Vamos investigar trocas faciais. Algo que se pareça com isso. Como é que isto funciona? Deixe-me explicar. Vamos começar dividindo esse produto de troca de inteligência artificial em sub-problemas. O que é uma troca de rosto? Em nossa versão simples da troca facial, uma troca de rosto leva duas etapas, detecta todas as faces e troca pixels por essas faces. Vamos falar sobre esses dois passos com mais detalhes agora. Primeiro passo, a detecção de rosto, resumida de rosto leva em uma imagem como esta e desenha caixas em torno de rostos. Vamos descrever esses algoritmos de desenho de caixa com mais detalhes agora. Vamos introduzir a detecção facial descrevendo os dados associados, o modelo, o objetivo e o algoritmo. Como atualização, aqui está o significado de cada um desses termos. Primeiro, dados. Nosso modelo de detecção de rosto aceita uma imagem e prevê uma caixa que contém o rosto. Essas caixas são representadas usando quatro números. Cada descrição da caixa inclui o canto superior esquerdo, x e y, e a altura e a largura. Estes quatro números definem exclusivamente uma caixa. Um modelo de detecção de faces prevê estas quatro coordenadas para um rosto. Segundo modelo, o modelo específico de detecção de rosto que usaremos é chamado de classificador em cascata Haar. Discutiremos esse modelo com mais detalhes em uma lição posterior. Terceiro objetivo, o objetivo do nosso modelo é maximizar a precisão da detecção de rostos. Para medir a precisão, usamos uma métrica chamada interseção sobre união ou IOU. Vamos falar sobre como o IOU é calculado. Veja como funciona a IOU ou a interseção sobre o sindicato. Digamos que esta caixa vermelha é a nossa caixa prevista, o azul é a nossa verdade. Intuitivamente, quanto menos essas duas caixas se sobrepõem, menor precisão deve ser. Quanto mais eles se sobrepõem, maior será a nossa precisão. Calculamos a sobreposição denotada em rosa para misturar suas caixas maiores para obter automaticamente maior precisão. Nós também dividimos pela união denotada em verde. Esta interseção sobre união ou IoU é como medimos a precisão para detectores de objetos. Finalmente, como de costume, vamos pular o algoritmo. Isso conclui nossa introdução à detecção de rostos. Discutiremos a detecção de rostos com mais detalhes em uma lição posterior. Por enquanto, vamos passar para o segundo passo da troca de rosto, a troca em si. O segundo passo é uma troca de pixels, precisaremos fazer algum redimensionamento caso as duas faces detectadas tenham tamanhos diferentes, mas isso é muito simples. Agora, vamos ver um exemplo desses dois passos juntos. Primeiro, detecte ambas as faces e depois troque-as. Reconhecidamente, isso não parece convincente. Para esta classe, construiremos essa troca de rosto simples, mas deixe-me explicar como as trocas faciais de nível industrial tornam isso mais realista. Vamos refazer a quebra do produto de IA de troca de rosto. Esta foi a nossa compreensão anterior da troca facial. Primeiro, em vez de apenas detectar rostos, agora irá detectar pontos-chave no rosto. Aqui está um exemplo visual de pontos-chave faciais. Os pontos-chave faciais podem corresponder a partes significativas do rosto, como a ponte do nariz, área logo acima de uma sobrancelha, covinhas e muito mais. Com nossos pontos-chave, deformamos pixels para que cada região da face seja deformada para a região correspondente de uma segunda fase. Para visualizar isso, digamos que temos dois rostos agora, temos os pontos-chave faciais de antes para a pessoa à esquerda. Também temos os mesmos pontos-chave faciais para a pessoa à direita. Vamos nos concentrar nos três pontos-chave ao redor do olho esquerdo. Estes pontos-chave formam triângulos, para enfrentar a troca irá deformar o triângulo à esquerda para o triângulo à direita. Depois de algumas técnicas de mesclagem de imagens, então teremos uma troca de rosto fotorrealista, algo assim. É isso. Nós cobrimos uma versão mínima da troca facial que irá construir, que consiste em duas etapas, detectar as faces e trocar os pixels. Também cobrimos as técnicas profissionais de troca de rosto usadas por aplicativos populares para obter uma cópia desses slides e mais recursos, certifique-se de verificar este URL e agora você sabe como funcionam as trocas faciais. Vamos começar a codificar mais uma vez para começar a construir a nossa própria troca de rosto. 5. Codificação da detecção de rosto: Nesta lição, vamos experimentar com um detector facial. Em um nível alto, detectaremos rostos em uma imagem e, em seguida, detectaremos rostos em nossa webcam. O objetivo é explorar utilitários de detecção de espaço. Comece acessando este URL como eu fiz no lado direito. Isso criará um ambiente para nós remotamente para que, como antes, não façamos nenhuma configuração em nossos computadores. No lado direito aqui para me preparar para o nosso desenvolvimento, vou fechar esta pré-visualização no lado direito clicando no x no canto superior direito. No navegador de arquivos, vou clicar em Novo arquivo e, em seguida, digite detect.py. Então isso vai abrir automaticamente detect.py em nosso editor. Vou minimizar o nosso navegador de arquivos clicando nesta seta para a esquerda. Então eu vou ampliar para que você possa ver melhor o que estou fazendo. Começaremos lendo e escrevendo uma única imagem. Para ler a imagem, use cv2.imread como mostrado aqui. O primeiro argumento é o caminho da imagem a ser lida. Vamos tentar isso, em seu novo arquivo Python, começar importando OpenCV, importar cv2. Em seguida, leia a imagem, kids.jpg. Aqui, vamos digitar imagem é igual a cv2.imread e kids.jpg. Para salvar a imagem, use cv2.imwrite, como mostrado aqui. O primeiro argumento é o caminho e o segundo argumento é a imagem. Vamos tentar isso agora, escreva a imagem em um novo arquivo chamado out.jpg, cv2.imwrite para out.jpg e, em seguida, inclua a imagem à direita. Em seguida, vamos reabrir nosso navegador de arquivos e, no lado esquerdo, clique em Ferramentas na parte inferior e, em seguida, clique em Terminal. Aguarde até que a configuração termine. Assim que a configuração estiver concluída, você será recebido com um prompt como este. Aqui nós estamos indo para digitar em python detect.py. Pressione Enter. Isso irá executar o script Python que você acabou de escrever. O script irá ler kids.jpg e salvá-lo em out.jpg. Para verificar, abra out.jpg à esquerda. Aqui, você verá que out.jpg corresponde a kids.jpg. Vamos instanciar nosso detector facial. Se você quiser uma atualização sobre o que é instanciação ou quais objetos são, certifique-se de verificar minha classe de programação orientada a objetos de nível intermediário. Você pode pausar o vídeo aqui para acessar esse URL. Instanciar o detector facial e passar os parâmetros do modelo. Aqui, os parâmetros do modelo são armazenados em um arquivo chamado parameters.xml. No seu navegador de arquivos, clique em detect.py mais uma vez. Aqui eu vou fechar novamente meu terminal na parte inferior clicando no x. Eu também vou minimizar meu navegador de arquivos. Você não precisa fazer nenhuma dessas coisas. Estou só a declutinar o vídeo para que possas ver melhor o meu código. Logo acima da imagem, vamos instanciar o detector facial. Detector é igual a CV2.cascadeClassifier. Novamente, o argumento é parameters.xml. Vamos agora usar o detector de rostos para detectar rostos. Vamos fazer isso usando o método DetectMultiScale, passar a imagem para este método e, adicionalmente, passar um novo argumento de palavra-chave chamado scaleFactor é igual a 1.3. Discutiremos o que esse ScaleFactor significa mais tarde. Por enquanto, vamos passar ambos os argumentos e o método irá então retornar um monte de retângulos, cada retângulo correspondente a um rosto na imagem. Vamos tentar isso agora. Depois de definir seu detector de rosto e depois de ter carregado na imagem, vamos agora detectar todas as faces executando, retângulos é igual ao detector.DetectMultiscale, e como temos escrito lá à esquerda, nós vai passar na imagem e o ScaleFactor. Finalmente, vamos desenhar retângulos na imagem correspondente às faces detectadas. Veja como fazer isso. Chame a função cv2.rectangle. Aqui vamos passar na imagem para desenhar retângulos, as coordenadas para o canto superior esquerdo do retângulo, coordenadas para o canto inferior direito do retângulo, a cor da borda do retângulo. Lembre-se, o primeiro número aqui representa a quantidade de vermelho, o segundo a quantidade de verde, e o último a quantidade de azul, com a quantidade varia de 0 a 255. Como resultado, 0, 255, 0 significa verde. Há uma sutileza aqui. O esquema de cores não tem realmente RGB, mas BGR para OpenCV, mas estamos omitindo esse detalhe por enquanto. Mas se você tentar mudar essas cores, seria por isso que o primeiro número realmente controla o grau de azul. Finalmente, vamos definir a largura da linha para a borda do retângulo, que tem dois pixels de largura. Vamos agora tentar isso em código. No lado esquerdo, vamos percorrer todos os retângulos. Aqui, sabemos que o retângulo é uma tupla de quatro números como falamos na lição anterior. Agora podemos escrever x, y, w, h é igual a retângulo. Esta sintaxe nos permite atribuir x para o primeiro número, y para o segundo, w para o terceiro, e h para o quarto. Agora, desenhe o retângulo usando a função que discutimos. CV2.Retângulo, a imagem, a coordenada inicial, a coordenada final, a cor verde e, finalmente, a largura da borda. Se ainda não o fez, abra o navegador de arquivos à esquerda, clique em Ferramentas e selecione Terminal. Na parte inferior, você verá alguma configuração. Quando o terminal estiver pronto, digite python detect.py no terminal. Isso executa o script Python de detecção de rosto que você acabou de escrever. Depois de executar este script, clique em out.jpg à esquerda, você verá que a imagem agora tem retângulos desenhados em torno de cada face. Agora vamos repetir a detecção de rosto, mas para nossa própria webcam. Comece acessando este URL. Uma vez que sua página é carregada, como antes, minimize sua visualização clicando no x no canto superior direito. Agora, já temos um arquivo criado para nós. Isto é da lição anterior. Vou fechar o navegador de arquivos no lado esquerdo clicando na seta para a esquerda. Para começar, alteraremos a taxa de quadros do nosso feed de vídeo baseado na Web. Isso impede que nossa aplicação web fique muito atrasada. Adicione uma taxa de quadros de argumento de palavra-chave ao construtor assim. Em nosso código eu vou digitar em framerate igual a 5. Além disso, vamos excluir CV2.putText, vamos substituir isso mais tarde. Como antes, vamos instanciar o detector facial. Novamente, como antes, passe os parâmetros do modelo em parameters.xml para este cascaDeclassifier. Logo acima da definição do aplicativo, eu vou digitar no detector é igual a CV2.cascaDeclassifier parameters.xml. Em seguida, detecte todas as faces na imagem. Estamos configurando a detecção de rosto ligeiramente, como antes de passar a imagem para detectar rostos e como antes adicionalmente passar em ScaleFactor é igual a 1.3. Este ScaleFactor nos permite detectar rostos de maior porte. Eis como, digamos, o detector facial foi treinado para detectar rostos deste tamanho. Aqui o quadrado azul é a imagem, o círculo é uma representação abstrata de um rosto. Durante a inferência, um rosto maior como este normalmente seria perdido uma vez que o nosso detector não é treinado para rostos tão grandes. Para contornar isso, reduzimos a imagem em 30% e colocamos o detector nela. Em seguida, repita isso, reduza a imagem em mais 30% e execute o detector novamente. Neste último passo, nosso rosto durante a inferência é do mesmo tamanho que os rostos durante o treinamento para que nosso detector seja capaz de detectar o rosto. Isto é o que DetectMultiscale significa. Vamos codificar isso agora. Primeiro, vamos renomear essa transformação de Hello World para Encontrar Faces. Também vamos renomear a função para find_faces. Em seguida, encontre todos os rostos na imagem como fizemos antes. Nós também adicionaremos o fator de escala como mencionamos anteriormente, para tornar o detector mais robusto para diferentes tamanhos de rosto, retângulos é igual a detector.DetectMultiscale, e vamos passar na imagem e um ScaleFactor de 1.3. Finalmente, desenhe retângulos em torno de todos os rostos como antes. Aqui está novamente, como desenhar um retângulo em OpenCV. Vamos fazer isso agora. Vamos percorrer todos os retângulos. Vamos destruir o retângulo em quatro variáveis como fizemos antes. Finalmente, vamos desenhar retângulos em torno de todas as faces. Agora, note que nós podemos realmente simplificar este for-loop. Desde x, y, w, h é igual a retângulo, podemos realmente substituir retângulo com estas quatro variáveis. Agora vou apagar esta linha. Aqui temos para x, y, w, h em retângulos. Agora, clique em Mostrar no canto superior esquerdo. Para mim, infelizmente, minha janela é muito pequena, então parece um par de óculos de sol. Isso abrirá uma visualização da sua aplicação web. Eu vou fazer zoom novamente para que você possa ver. Vou, em seguida, clicar em Iniciar e você verá um feed de webcam, exceto com seu rosto encaixotado. Novamente, clique em Permitir se for necessário. É isso para esta lição, agora você já explorou os utilitários de detecção de rosto no OpenCV para obter uma cópia desses slides, o código finalizado e mais recursos, certifique-se de verificar este URL. 6. Como os detectores de rosto funcionam?: Deixe-me dar um passo atrás para explicar como funcionam os detectores faciais. Vamos começar com a detecção de características simples, como bordas. Tire nossa imagem da lição anterior. Digamos que queremos extrair pequenas características simples, como bordas. Em um nível alto, queremos encontrar esses pequenos recursos em cada patch possível da imagem. Digamos que cada patch é dois por dois para começar. Vamos começar do canto superior esquerdo e perguntar, encontramos o recurso aqui? Que tal aqui? Que tal aqui? Assim por diante e assim por diante até que você tenha coberto toda a imagem. Agora, como você encontra pequenas características como bordas em cada um desses patches dois por dois? Considere um patch dois por dois com uma borda e outros patches sem bordas. Agora considere suas representações numéricas. Lembre-se que o preto é zero e um é branco, então a caixa esquerda contém zeros e uns. A caixa do meio contém todos os uns e a caixa direita contém todos os zeros. Vamos agora considerar um filtro de dois por dois, que é apenas uma matriz de números dois por dois. Multiplique o filtro dois por dois com o nosso patch dois por dois. Element-wise, multiplique o negativo vermelho 1 pelo zero vermelho. Multiplique o negativo preto 1 pelo zero preto. Multiplique os verdes e multiplique os azuis. Finalmente, adicione-os todos juntos e ganhamos dois. Faça o mesmo para a imagem do meio e obtemos zero. Faça o mesmo para a imagem certa e obteremos zero novamente. Isto é perfeito. Nosso filtro produz valores positivos para bordas verticais e produz zero para imagens sem bordas. Isto é apenas para um pequeno remendo de dois por dois. Vamos agora considerar toda a imagem. Esta é agora a representação numérica da nossa imagem de diamante. Atravessaremos cada remendo de dois por dois na imagem. Em cada patch, multiplicamos e somamos o filtro dois por dois com um patch dois por dois. Isso nos dá uma matriz de saídas onde se denota uma borda com preto à esquerda e branco à direita. Negativo 1 indica uma aresta na direção inversa. Visualizados como uma imagem, temos branco como borda esquerda, preto como uma borda direita e cinza como nenhuma borda. Chamamos isso de convolving um filtro com a imagem. Isso também funciona para imagens coloridas genéricas. Aqui está um pássaro à esquerda. Convolvendo a imagem com o filtro de borda nos dá a imagem à direita, destacando bordas como esperado. Para o detector de rosto de hoje, usaremos filtros Haar ou recursos Haar. Algumas características Haar encontram bordas como a que acabamos de tentar. Outros encontram linhas, mas outros encontram padrões abstratos. Há multidões de possíveis filtros e há também muitos, muitos patches em uma imagem grande. Executar todos os filtros em todos os patches é caro. Vamos tornar isto mais eficiente. Precisamos de uma maneira de economizar custos computacionais. Para fazer isso, o detector de faces neste curso usa um método chamado em cascata. Para entender como o CVS em cascata computa, precisamos entender a intuição. Olhe essa imagem na caixa vermelha. É basicamente verde monótono. Definitivamente não contém um rosto porque é tudo de uma cor e bastante chato. Sabendo disso, poderíamos executar um simples detector primeiro para encontrar todas as partes sem borda da imagem. Convolvendo um filtro de borda com a imagem nos dá essa saída. Observe que esta parte monótona da imagem encaixotada em vermelho à esquerda é toda preta. Agora podemos ignorar essas partes da imagem e focar os filtros posteriores nas partes mais interessantes da imagem denotadas em verde, e essa é a intuição. Execute um pequeno conjunto de filtros da imagem. Chamamos isso de estágio 1. Determine quais partes são interessantes escolhendo os pixels com os valores de saída mais altos. Em seguida, execute o próximo conjunto de filtros nas partes interessantes. Refine quais partes da imagem são consideradas interessantes e repita para o próximo conjunto de filtros, refinando quais partes da imagem são interessantes novamente e continue fazendo isso. Você poderia repetir isso indefinidamente. Em nosso modelo de detecção facial hoje, o modelo usa 38 desses estágios. Estes filtros em cascata permitem-nos executar esta detecção. Especificamente, esse estágio final dos 38 estágios produzirá valores altos para faces. Desenhe uma caixa em torno de valores na imagem que excedam um limite, depois visualize em cima da imagem original, e aí está, uma detecção de rosto bem-sucedida. Vamos recapitular os passos. Em resumo, discutimos como extrair recursos simples, como bordas, usando filtros. Em seguida, discutimos como esses recursos simples são usados para encontrar iterativamente partes interessantes da imagem usando um padrão em cascata. Finalmente, a cascata produz saídas de alto valor para faces. No estágio final, desenhamos uma caixa em torno de saídas de alto valor, e essas caixas identificam rostos na imagem. Para obter uma cópia desses slides e mais recursos, verifique este URL. Agora que você sabe como os detectores de rosto funcionam, vamos encerrar e terminar de codificar nossa troca de rosto. 7. Codificação da troca de rosto: Agora temos código para processar nossa webcam e detectar rostos, estamos prontos para terminar a troca facial. Em um nível alto, seguiremos o mesmo processo de duas etapas que antes. Primeiro, testaremos a troca de rosto em uma imagem e depois implementaremos a troca de rosto para sua webcam. Comece acessando este URL como eu tenho no lado direito. Isso criará um ambiente para nós remotamente, novamente, para que não queiramos fazer nenhuma configuração em nossos próprios computadores. Antes de uma nova função, vamos criar um novo arquivo. No lado esquerdo aqui, se o seu navegador de arquivos entrou em colapso como o meu, vá em frente e clique nele para expandi-lo. No lado direito, vou fechar a minha pré-visualização clicando no x superior direito. Neste arquivo, vou clicar em detect.py, e esse é o arquivo que queremos editar. Vá em frente e feche o arquivo clicando nesta seta para a esquerda no canto superior esquerdo. Neste arquivo, vamos criar uma nova função, trocar rostos para manter sua detecção de rosto e código de desenho de caixa. Vamos definir uma função chamada “swap faces” acima do nosso código atual. Esta função vai levar a imagem e o detector de rosto. Dentro vamos levar este código partir do código de detecção até o código de desenho da caixa. Vou cortar isso e depois colá-lo na nossa nova função. Uma vez colado, você precisará ajustar o recuo. Para mim, as linhas 6 a 10 precisam ser recuadas mais uma vez. Agora, vamos emparelhar os retângulos, ou em outras palavras, os rostos em grupos de dois. Deixe-me explicar como vamos fazer isso. Finja que a lista de retângulos contém apenas números como este. Em seguida, retângulos de 2። 2 irá selecionar todos os outros números. Neste caso, teríamos 0, 2, 4. Em seguida, retângulos, 1። 2 irá ignorar o primeiro e, em seguida, selecionar todos os outros números. Neste caso, teríamos 1, 3, 5. A indexação é um tópico bastante complicado, então não se preocupe se você não entender isso completamente, apenas saiba que isso é conceitualmente o que está acontecendo. Finalmente, zip irá coletar o primeiro item de ambas as listas. Neste caso, 0,1 então ele irá coletar o segundo item de ambas as listas, neste caso, 2,3. Finalmente, o terceiro item de ambas as listas fazendo 4,5. Tudo isso para dizer que expressão de aparência complicada, retângulos zip com um monte de colunas e números, selecione a cada dois retângulos ou a cada duas faces. Vamos codificar isso agora. No seu código à esquerda, vamos mudar este for-loop de modo que temos para retangle1, retangle2 em zip, e então a expressão que tínhamos antes retângulos 1። 2, e vírgula. Eu vou apertar Enter e aqui eu vou escrever, passar e excluir nosso código de desenho da caixa original. Vamos agora extrair ambos os rostos da imagem. Vamos começar definindo uma função auxiliar. Debaixo de rostos de troca, vamos definir o seletor de rostos. Esta função irá, dado um retângulo, retornar uma máscara para que possamos selecionar o rosto. Primeiro, destruiremos o retângulo nos quatro valores, como fizemos antes. Aqui irá retornar, em seguida, um objeto de fatia. Um objeto de fatia permite selecionar uma parte da lista. Nesse caso, duas fatias permitem selecionar parte de uma matriz 2D ou, em outras palavras, uma parte da imagem. Aqui vamos devolver dois objetos de fatia. O primeiro objeto de fatia cortará ao longo da primeira dimensão ou do eixo y de y a y mais h. O segundo objeto de fatia será cortado ao longo da segunda dimensão ou o eixo x de x a x mais a largura. Agora vamos usar esta função de seletor de rosto get, acima, usando nossa nova função auxiliar, converter o primeiro retângulo para uma máscara facial dentro do nosso for-loop. Aqui vamos escrever mask1 é igual para obter seletor de rosto retangle1. Repita a mesma coisa para o segundo retângulo. Agora, use as máscaras para selecionar ambas as faces da imagem. Face1 é igual a imagem da máscara1 e face2 é igual a imagem da máscara2. Agora, como as duas faces podem ter tamanhos diferentes, precisamos redimensionar cada face para caber dentro da outra. Aqui está conceitualmente como vamos fazer isso. Digamos que estamos tentando encaixar a caixa verde dentro da caixa azul, observe que a altura azul é menor que a altura verde. Como a caixa verde é mais alta, vamos encurtá-la para que as alturas de ambas as caixas sejam as mesmas. Nesse caso, a relação entre a altura azul e a altura verde nos diz o quanto precisávamos encolher no retângulo verde. Diga agora que a caixa verde é mais larga do que a caixa azul, observe que a largura azul é menor que a largura verde. Vamos encolher para que as larguras de ambos os retângulos sejam iguais. Neste caso, a relação entre a largura azul e a largura verde nos diz o quanto precisávamos encolher o retângulo verde. Nós realmente não sabemos se o retângulo é muito alto ou muito largo então nós tomamos o mínimo de ambas as razões para ser seguro. Isso garante que o retângulo verde tenha encolhido o suficiente, seja muito alto ou muito largo, para caber dentro do retângulo azul. Vamos agora codificar isso. Assim como antes nós estamos indo para começar definindo uma função auxiliar por baixo get seletor de rosto para encontrar, redimensionar para caber. Esta função levará em duas faces, face1 e face2. Primeiro, destrua a forma do rosto para obter a largura e a altura do rosto. Vamos digitar face1_height, face1_width, sublinhado é que você tem que face1.shape. Na verdade, o rosto tem três dimensões para a sua forma. Se você se lembra de nossa lição anterior, todas as imagens são h por w por 3. Não precisamos dessa última dimensão, então usamos um sublinhado. Sublinhado é convenção para ignorar esta variável. Nós também vamos repetir isso com a segunda face, face2_h, face2_w é igual a face2.shape. Em seguida, calcule a quantidade necessária para encolher a primeira face para caber na segunda face. Este é o fator que mencionamos antes. O fator é igual ao mínimo entre a altura da face 2 dividida pela altura da face 1 e, em seguida, a largura da face 2 dividida pela largura da face 1. Finalmente, vamos redimensionar o face1. Aqui, a função de redimensionamento que tomaremos na primeira face eo segundo argumento é, se necessário argumento embora não vamos usar assim passar em nenhum por agora. Em seguida, vamos digitar o fator a ser dimensionado na dimensão x e, em seguida, o fator a dimensionar na dimensão y. Finalmente, devolva isto. Agora vamos usar o método auxiliar, redimensionar para caber, para redimensionar ambas as faces para caber na outra. Comece com face1 acima no for-loop irá digitar em redimensionado1 é igual a redimensionar para caber face1, face2. Faça o mesmo para o outro tamanho da face 2 é igual a redimensionar para caber face2 no face1. Agora vamos realmente colar um rosto no outro. Conceitualmente irá simplesmente colar o retângulo verde no azul. Novamente, vamos começar com o método auxiliar. Eu vou rolar para baixo e abaixo de redimensionar para caber vamos definir, certifique-se de backspace para que você iniciar uma nova função fora, vamos definir aplicar, que leva no rosto redimensionado e o rosto para colá-lo. Destruir a forma do rosto em sua altura e largura redimensionada 1 altura, redimensionada 1 largura e sublinhado para ignorar que terceira dimensão é igual a dimensione1.shape e, em seguida, cole o rosto no face2. Aqui face2, vamos agora colar o rosto redimensionado no face2. Finalmente, devolva a segunda face. Novamente, a indexação é um tópico bastante complicado, portanto, se você não entender o que esta linha significa, não se preocupe. Por enquanto, você só precisa saber que foi assim que ele colou o rosto redimensionado na segunda face. Rolando de volta para o for-loop que agora vamos usar aplicar, para aplicar cada face. Cole o face2 redimensionado no face1. Mask1 é igual a aplicar redimensioned2 face1. Repita a mesma coisa para a outra máscara de imagem de rosto2 é igual para aplicar redimensionado1 face2. Para a etapa final, nós realmente vamos aplicar nossa função de swap faces para a nossa imagem e o detector de rosto correspondente, role para baixo até a parte inferior do seu arquivo depois de ter instanciado seu detector e leia sua imagem em. Agora vamos chamar rostos de troca na imagem e no detector de rostos. Agora terminamos com o roteiro. Clique no navegador de arquivos no lado esquerdo, clique em Ferramentas e, em seguida, terminal. Aguarde por uma configuração. Uma vez que a configuração é feita, digite Python detect.py. Isso executará seu código de troca de rosto. Depois de executar este script checkout out.JPEG no lado esquerdo. Parece que a imagem não mudou talvez, bem, olhe mais de perto. Os rostos das crianças são trocados. Isso é mais óbvio quando eu alterno entre a imagem original e a trocada. Aqui está a imagem original e aqui está a trocada. Vamos agora aplicar a troca de rosto à nossa webcam. Comece acessando este URL. Uma vez que esta página tenha sido carregada, vou clicar em Fechar na pré-visualização no lado direito, eu recomendo fazer o mesmo para criar mais espaço. No lado esquerdo, vou fechar o navegador de arquivos clicando na seta no canto superior esquerdo. Para começar, vamos copiar todas as funções auxiliares que escrevemos na última etapa. Vou colá-los acima da instanciação do detector facial. Aqui vou colar estes. Observe que realmente não importa onde você cola essas funções. Se você quiser colar exatamente no mesmo local, eu colei depois das importações, mas antes que o detector de rosto seja instanciado. Vamos agora definir uma nova transformação para nosso aplicativo web seja aplicado ao feed ao vivo da webcam. Rolando para baixo depois de todas as nossas funções existentes, vou criar uma nova transformação. Como em uma lição anterior, usaremos o decorador de CV aberto na web em app.transform. Vamos dar a esta transformação um nome de troca de rosto e também vamos fazer esta nova transformação o padrão digitando padrão igual a true. Vou excluir esse padrão igual a verdadeiro abaixo porque não podemos ter duas transformações padrão. Agora vamos definir uma função de troca de rosto que leva tanto a imagem quanto o quadro, em seguida, chamar o método de troca faces helper que você escreveu na última seção. Digite as faces de troca e passe a imagem e o detector de faces e retorne a imagem. Finalmente, é isso. Clique em Mostrar no canto superior esquerdo. Para mim, parece que tinha ícone de óculos de sol. Em seguida, selecione em uma nova janela, isso abre uma visualização de seu aplicativo web. Vou ampliar para que você possa ver o que está acontecendo e, em seguida, clique em Iniciar. Neste caso, estou me trocando por uma foto minha tirada no passado. Certifique-se de que clica em Iniciar e, em seguida, em Permitir. Isso conclui nossa troca de rosto. Agora você pode compartilhar essa troca de rosto com seus amigos e familiares. Faça rostos engraçados, compartilhe tantas fotos e divirta-se com seu próprio aplicativo de troca de rosto. Bom trabalho completando esta lição, foi longa. Para obter uma cópia desses slides, o código finalizado e mais recursos, certifique-se de verificar este URL. Veja a próxima lição para ver as próximas etapas para aprender mais visão computacional. 8. Próximos passos: Parabéns. Você terminou sua obra-prima de troca de rosto. Nós abordamos como as imagens são representadas, como extrair significado de imagens, modelos de detecção de rostos e muito mais. Se isso tiver escolhido seu interesse em aprendizado de máquina e visão computacional, siga-me no Skillshare para ser notificado quando a próxima aula for lançada. Se você estiver interessado em tópicos de ciência de dados também, confira minha classe Data Science 101; o jogo com dados ou a classe SQL 101 para consultar e projetar bancos de dados. Obrigado por se juntar a mim nesta aula de troca de rosto. Parabéns mais uma vez chegando ao final do curso e até a próxima vez.