Quer saber como criar aplicativos que utilizam a câmera do Android para analisar o que está acontecendo e fornecer informações relevantes com Inteligência Artificial e Machine Learning? Vamos mostrar como!
Boas-vindas a mais um conteúdo da Alura. Meu nome é Junior e serei seu instrutor.
Audiodescrição: Junior se identifica como um homem de pele clara, cabelos loiros e escuros. No rosto, utiliza um óculos com lentes grandes e armação na cor preta. No corpo, usa uma camiseta preta. Ao fundo, há uma parede lisa com uma luz degradê que vai do azul até o rosa.
Neste curso, vamos utilizar o aplicativo AI Found, que permite listar uma série de produtos.
Quando clicamos em um dos itens na lista, vemos uma tela que traz informações sobre esse produto, como a descrição e a quantidade. Podemos clicar nos botões de mais e de menos para adicionar algumas quantidades ao carrinho.
O que realmente queremos fazer com esse aplicativo? Quando clicarmos na opção de pesquisa avançada, no canto inferior direito da tela de lista de itens, ele abrirá a câmera e conseguiremos visualizar informações do que está na foto.
Ele identificará que existe um produto, trará para nós o nome dele, exibindo uma caixa de destaque em volta e uma aba com o nome do produto na parte inferior da tela.
Ao clicar nessa aba, ele traz aquela mesma tela de descrição, só que para o produto que ele está visualizando. Além disso, se movimentarmos a câmera do dispositivo para outro produto, ele trocará o que identificou e trará para nós a informação do novo item.
Para entender como tudo isso vai funcionar, vamos utilizar uma biblioteca do ML Kit para rastreio e detecção de objetos. Para isso, vamos entender como essa biblioteca fornece informações relevantes, como rótulos, número de objetos que são detectados e os IDs de cada um.
Vamos entender como essas informações podem ser utilizadas para desenhar as caixas delimitadoras em volta do produto na câmera e fazer a pesquisa do que queremos dentro do aplicativo. Vamos entender como esse padrão de design aparece, permitindo que facilmente alternemos entre um produto que está sendo exibido agora e qualquer outro.
Durante nossos vídeos, além de utilizar o próprio emulador, vamos utilizar um dispositivo físico, permitindo, por exemplo, entrarmos na câmera do celular com nosso aplicativo aberto e apontar para um produto real que temos em mãos. Assim, ele fará a identificação do que estamos buscando, permitindo fazer a adição dele no nosso carrinho. Vamos ver isso em tempo real.
Este é um conteúdo importante para quem quer adicionar a funcionalidade da câmera do seu dispositivo, trazer informações mais relevantes do que ela está vendo, utilizando o poder de processamento do próprio dispositivo, sem precisar enviar nada para fora dele, utilizando o Machine Learning e a biblioteca de detecção e rastreio de objetos da própria Google.
Se tiver alguma dúvida ou quiser compartilhar algo conosco, convidamos você a utilizar nossos canais do Discord ou mesmo no fórum do curso.
Esperamos que você tenha se animado para começar. Vamos lá!
Antes de começar a implementar nossas funcionalidades, é crucial conhecer a estrutura do projeto, o AI Found.
Após fazer o download e instalar, vamos abri-lo no Android Studio e revisar as pastas que temos.
A ideia com esse aplicativo é adicionar uma função que agrega valor à pesquisa de produtos. No mundo real, vários aplicativos semelhantes têm adicionado a possibilidade de apontar a câmera do celular e pesquisar o que está ali, trazendo informações como preço, descrição e produtos similares. Alguns aplicativos estão começando a adicionar essa funcionalidade.
Vamos ver, em primeira mão, como fazer isso dentro de um aplicativo real.
A estrutura desse projeto está quase toda feita — toda a parte de lógica e visual já está pronta. Nós o recebemos somente para implementar a nova função.
Estrutura de pastas do aplicativo:
Dentro da pasta "data", temos os modelos Product
e
ProductObject
que fazem o aplicativo funcionar, como o de produto, que tem o nome, o ID, a quantidade, a descrição, a imagem desse produto, que é um @DrawableRes
, porque está direto no projeto.
Dentro de "extensions", temos o arquivo ComposeExtensions.kt
com extensões do próprio Composable, feitas para facilitar implementações futuras. Já o arquivo StringExtensions.kt
tem duas extensões de string que utilizamos no arquivo ProductSample.kt
, da pasta "sampledata".
No interior desse arquivo, temos o código de uma API falsa. Apesar de não a ter disponível por completo, temos uma ideia de como pegar todos os produtos, o formato que eles serão retornados e como fazer a requisição para um único produto.
Isso é muito útil em casos reais, onde a API ainda está sendo construída por outro time, mas já temos que começar a implementar essa funcionalidade. No ProductSample.kt
temos, portanto, uma simulação de como fazer essas buscas.
Nesse arquivo também temos uma lista com alguns produtos de exemplo, como refrigerantes, batata, ketchup. Eles possuem o nome, o preço, e sua imagem, permitindo fazer os primeiros testes.
Dentro da pasta "ui", temos toda a parte visual do app, com a parte do carrinho, componentes do Jetpack Compose, a pasta de detalhes, de home. Toda a parte de navegação também está nessa pasta.
Dentro da pasta "utils", por sua vez, temos o arquivo PermissionUtils
com parte de permissões, além da MainActivity
e da classe de AppApplication
para injeção de dependências.
Caso haja interesse em aprender sobre permissões e armazenamento de arquivos, temos conteúdos disponíveis sobre esse assunto na plataforma da Alura, como o curso Jetpack Compose: lidando com armazenamento de arquivos no Android.
Descendo um pouco mais, dentro da pasta "assets" temos dois arquivos de modelos customizados, model_a.tflite
e model_products.tflite
. No curso anterior de Ml Kit com imagens, entendemos o que esses modelos são, como funcionam, e até como criar os nossos. Neste curso, também faremos uso deles.
Dentro da pasta "res", temos a pasta "drawable" com duas imagens principais para testar o aplicativo: amostra1_varios_produtos.png
, com várias fotos de itens que vamos utilizar, e amostra2_dois_produtos.png
, que possui outros produtos.
Conhecemos várias pastas do aplicativo, mas não falamos da câmera. A seguir, vamos comentar um pouco melhor sobre como essa questão funciona no Jetpack Compose. Vamos lá!
Para entender como funciona o componente de câmera no projeto, especificamente com o Jetpack Compose, localizaremos a pasta "camera" dentro do diretório "ui".
cameraAnalyzer
CameraContainer.kt
CameraScreen.kt
CameraScreenUiState
CameraViewModel
Em seu interior, vamos encontrar arquivos que precisamos analisar com mais atenção.
Começaremos acessando o cameraAnalyzer
. Ele implementa o ImageAnalysis.Analyzer
, cuja função entenderemos em breve. Antes, é importante saber que no CameraContainer.kt
, o segundo arquivo nesta pasta, preparamos todas as permissões de câmera necessárias para a câmera e para o preview funcionarem.
Em seguida, entramos no principal arquivo que precisamos analisar com mais atenção, que é o CameraScreen.kt
. Este é um código quase todo feito em Jetpack Compose. Com este projeto aberto, podemos fazer o seguinte teste:
Primeiro, removeremos todas as linhas abaixo, que abrangem por volta da linha 54 até a 59. Esse trecho é uma parte de análise da câmera.
CameraScreen.kt
:
val cameraAnalyzer = remember {
CameraAnalyzer { imageProxy ->
Log.d("CameraAnalyzer", "Image received: ${state.imageWidth}x${state.imageHeight}")
imageProxy.close()
}
}
Depois, vamos remover todo o código dos dois set
abaixo, localizados por volta da linha 58 até a linha 62.
setEnabledUseCases(CameraController.IMAGE_ANALYSIS)
setImageAnalysisAnalyzer(
ContextCompat.getMainExecutor(context),
cameraAnalyzer
)
Com isso, percebemos que nenhum erro vai aparecer. Se rodarmos o projeto, ele ainda vai funcionar normalmente.
Queremos deixar esse código dessa maneira para explicar que, para que a câmera apareça em tela junto com o preview, precisamos do componente cameraController
que controla a câmera e está por volta da linha 56, e de um preview para mostrar o que a câmera está capturando. Para isso, temos o CameraPreview
, por volta da linha 62.
CameraPreview(cameraController = cameraController)
Vamos clicar nele e pressionar "Ctrl+B" para acessar o seu código, por volta da linha 86 no mesmo arquivo.
private fun CameraPreview(
modifier: Modifier = Modifier,
cameraController: LifecycleCameraController,
) {
val lifecycleOwner = LocalLifecycleOwner.current
AndroidView(
factory = { context ->
PreviewView(context).aplicativoly {
this.controller = cameraController
cameraController.bindToLifecycle(lifecycleOwner)
}
},
modifier = modifier.fillMaxSize()
)
}
No momento em que estamos gravando este conteúdo, o Jetpack Compose não tem uma maneira nativa de exibir o preview da câmera. Portanto, precisamos utilizar a opção de interoperabilidade dele com o sistema de Views, chamando o AndroidView
e passando informações para ele.
Apesar de estarmos utilizando a interoperabilidade, esse é um recurso que funciona muito bem. Declaramos com o próprio modifier
do Jetpack Compose que esse componente deve fazer parte da tela inteira e preencher todo o seu conteúdo.
Dentro desse AndroidView
, passamos o cameraController
, obtido via Jetpack Compose, e um ciclo de vida também obtido com o Jetpack Compose para fazer o controle de quando, por exemplo, minimizamos o aplicativo, trocamos ou recebemos algo que possa fazer com que o ciclo de vida mude, seja interrompido ou finalizado.
Feito isso, temos dois passos únicos para adicionar a câmera e adicionar o preview. O aplicativo vai funcionar. Porém, como este é um curso que visa trabalhar com a análise da câmera, vamos devolver os dois trechos de código que recortamos pressionando "Ctrl+Z" várias vezes.
Entre eles, o trecho de análise da câmera possui o cameraAnalyzer
já implementado, que vai fazer uso da classe cameraAnalyzer
que já deixamos pronta na mesma pasta "camera".
val cameraAnalyzer = remember {
CameraAnalyzer { imageProxy ->
Log.d("CameraAnalyzer", "Image received: ${state.imageWidth}x${state.imageHeight}")
imageProxy.close()
}
}
Vamos acessar a classe cameraAnalyzer
no arquivo CameraAnalyzer
.
CameraAnalyzer.kt
:
class CameraAnalyzer(
private val onImageProxy: (image: ImageProxy) -> Unit
) : ImageAnalysis.Analyzer {
override fun analyze(image: ImageProxy) {
onImageProxy(image)
}
}
Você pode criar qualquer classe com o nome que seja, desde que ela implemente esse ImageAnalysis.Analyzer
e sobrescreva o método analyze
, que terá um ImageProxy
— basicamente, cada frame (quadro) do preview que veremos na câmera.
Ou seja, quando apontamos a câmera do celular, ela vai transmitir em tempo real o que está passando na frente, como se fossem várias imagens uma atrás da outra. Conseguimos ter acesso aos quadros dessas imagens por meio do analyze
que passamos para o cameraController
no arquivo CameraScreen.kt
, realizando a instância do cameraAnalyzer
.
O código que implementamos como amostra do cameraAnalyzer
no arquivo CameraScreen.kt
pega cada um desses quadros dentro de um Log.d
, mostrando o tamanho da sua altura e da sua largura. No final, precisamos ter ciência que cada imagem precisa ser fechada depois que trabalhamos com ela. Por isso, temos um imageProxy.Close
no final desse bloco.
No segundo trecho que retornamos ao código, com os dois set
, deixamos essa análise sendo passada pelo cameraController
dentro de um LifecycleCaeraController(context).apply
.
CameraScreen.kt
:
val cameraController = remember {
LifecycleCameraController(context).apply {
setEnabledUseCases(CameraController.IMAGE_ANALYSIS)
setImageAnalysisAnalyzer(
ContextCompat.getMainExecutor(context),
cameraAnalyzer
)
}
}
Feito isso, entendemos como o código da câmera funciona.
No final, por volta da linha 75, temos um pequeno overlay, que é um componente do Compose, o qual vamos utilizar para desenhar informações em cima da tela, como por exemplo, se existe um produto detectado ou não. Nesse caso, por enquanto, apenas mostramos um único texto.
// 3 Overlay
BoxWithConstraints(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.2f))
) {
Text(
text = state.textMessage ?: "Nenhum produto detectado",
fontSize = 20.sp,
color = Color.White,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
)
Log.d("CameraScreen", "Screen size: ${maxWidth.dpToPx()} x ${maxHeight.dpToPx()}")
}
Além desse projeto que recebemos e que já entendemos como funciona, também recebemos o link de um arquivo da Google sobre o caso da Adidas, comentando sobre essa uma marca muito famosa de roupas e calçados implementou uma funcionalidade no seu aplicativo utilizando a biblioteca de detecção e rastreio de objetos.
Isso permite que, quando alguém entre na loja da Adidas e aponte a câmera do celular para algum produto como um calçado, obtenha informações como quais são os calçados similares àquele, e se aquele calçado existir na loja, quais são os tamanhos, qual é o preço e quais são as cores disponíveis, por exemplo.
Essa é uma função que tem ficado cada vez mais comum nos aplicativos — apontamos a câmera e obtemos informações extras de um produto ou local. A biblioteca de detecção e rastreio utilizada pela Adidas permite fazer isso.
A seguir, começaremos a entender como essa biblioteca funciona e quais as diferenças dela para outras que já utilizamos antes. Vamos lá!
O curso Android com IA: usando a câmera para detectar objetos com Machine Learning possui 149 minutos de vídeos, em um total de 54 atividades. Gostou? Conheça nossos outros cursos de IA para Mobile em Inteligência Artificial, ou leia nossos artigos de Inteligência Artificial.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.