À medida que as câmeras são aprimoradas, a detecção de objetos em tempo real se torna uma funcionalidade cada vez mais procurada. De carros autônomos e sistemas de vigilância inteligentes a aplicativos de realidade aumentada, essa tecnologia é usada em muitas situações.

A visão computacional, um termo sofisticado para a tecnologia que usa câmeras com computadores para realizar operações como essas, é um campo vasto e complicado. No entanto, talvez você não saiba que pode começar a usar a detecção de objetos em tempo real com muita facilidade no conforto do seu navegador.

Este artigo explica como você pode criar um aplicativo de detecção de objetos em tempo real usando o React e implantá-lo na Kinsta. O aplicativo de detecção de objetos em tempo real aproveita o feed da webcam do usuário.

Pré-requisitos

Vejamos um detalhamento das principais tecnologias utilizadas neste guia:

  • React: O React é usado para construir a interface de usuário (UI) do aplicativo. É excelente na renderização de conteúdo dinâmico e será útil para apresentar o feed da webcam e os objetos detectados no navegador.
  • TensorFlow.js: O TensorFlow.js é uma biblioteca JavaScript que traz o poder do Aprendizado de Máquina (Machine Learning) para o navegador. Permite carregar modelos pré-treinados para detecção de objetos e executá-los diretamente no navegador, eliminando a necessidade de processamento complexo no lado do servidor.
  • Coco SSD: O aplicativo usa um modelo de detecção de objetos pré-treinado chamado Coco SSD, que é leve e capaz de reconhecer uma grande variedade de objetos do cotidiano em tempo real. Embora o Coco SSD seja uma ferramenta avançada, é importante observar que foi treinado com um conjunto geral de dados de objetos. Se você tiver necessidades específicas de detecção, poderá treinar um modelo personalizado usando o TensorFlow.js seguindo este guia.

Configure um novo projeto React

  1. Crie um novo projeto React. Para isso, execute o seguinte comando:
    npm create vite@latest kinsta-object-detection --template react

    Isso criará para você a linha de base de um projeto React usando vite.

  2. Em seguida, instale as bibliotecas TensorFlow e Coco SSD executando os seguintes comandos no projeto:
    npm i @tensorflow-models/coco-ssd @tensorflow/tfjs

Agora você está pronto para começar a desenvolver seu aplicativo.

Configurando o aplicativo

Antes de escrever o código para a lógica de detecção de objetos, vamos entender o que é desenvolvido neste guia. Esta é a aparência da interface do usuário do aplicativo:

Design de interface do usuário (UI) do aplicativo.
Design de interface do usuário (UI) do aplicativo.

Quando um usuário clica no botão Start Webcam, é solicitado a conceder permissão ao aplicativo para acessar o feed da webcam. Quando a permissão é concedida, o aplicativo começa a exibir o feed da webcam e detecta objetos presentes no feed. Em seguida, renderiza uma caixa para mostrar os objetos detectados no feed em tempo real e também adiciona uma etiqueta a ela.

Para começar, crie a interface do usuário para o aplicativo colando o seguinte código no arquivo App.jsx:

import ObjectDetection from './ObjectDetection';
function App() {
  return (
    <div className="app">
      <h1>Image Object Detection</h1>
        <ObjectDetection />
    </div>
  );
}

export default App;

Esse snippet de código especifica um cabeçalho para a página e importa um componente personalizado chamado ObjectDetection. Esse componente contém a lógica para capturar o feed da webcam e detectar objetos em tempo real.

Para criar esse componente, crie um novo arquivo chamado ObjectDetection.jsx em seu diretório src e cole o seguinte código nele:

import { useEffect, useRef, useState } from 'react';

const ObjectDetection = () => {
  const videoRef = useRef(null);
  const [isWebcamStarted, setIsWebcamStarted] = useState(false)

  const startWebcam = async () => {
    // TODO
  };

  const stopWebcam = () => {
     // TODO
  };

  return (
    <div className="object-detection">
      <div className="buttons">
        <button onClick={isWebcamStarted ? stopWebcam : startWebcam}>{isWebcamStarted ? "Stop" : "Start"} Webcam</button>
      </div>
      <div className="feed">
        {isWebcamStarted ? <video ref={videoRef} autoPlay muted /> : <div />}
      </div>
    </div>
  );
};

export default ObjectDetection;

O código acima define uma estrutura HTML com um botão para iniciar e parar o feed da webcam e um elemento <video> que será usado para mostrar ao usuário o feed da webcam quando estiver ativo. Um contêiner de estado isWebcamStarted é usado para armazenar o estado do feed da webcam. Duas funções, startWebcam e stopWebcam, são usadas para iniciar e parar o feed da webcam. Vamos defini-las:

Aqui está o código para a função startWebcam:

const startWebcam = async () => {
    try {
      setIsWebcamStarted(true)
      const stream = await navigator.mediaDevices.getUserMedia({ video: true });

      if (videoRef.current) {
        videoRef.current.srcObject = stream;
      }
    } catch (error) {
      setIsWebcamStarted(false)
      console.error('Error accessing webcam:', error);
    }
  };

Essa função se encarrega de solicitar que o usuário conceda acesso à webcam e, quando a permissão é concedida, define o <video> para mostrar o feed da webcam em tempo real para o usuário.

Se o código não conseguir acessar o feed da webcam (possivelmente devido à falta de webcam no dispositivo atual ou se a permissão for negada ao usuário), a função imprimirá uma mensagem no console. Você pode usar um bloco de erro para exibir o motivo da falha para o usuário.

Em seguida, substitua a função stopWebcam pelo código a seguir:

const stopWebcam = () => {
    const video = videoRef.current;

    if (video) {
      const stream = video.srcObject;
      const tracks = stream.getTracks();

      tracks.forEach((track) => {
        track.stop();
      });

      video.srcObject = null;
      setPredictions([])
      setIsWebcamStarted(false)
    }
  };

Esse código verifica as faixas de stream de vídeo em execução que estão sendo acessadas pelo objeto <video> e interrompe cada uma delas. Por fim, define o estado de isWebcamStarted para false.

Nesse ponto, tente executar o aplicativo para verificar se você pode acessar e visualizar o feed da webcam.

Certifique-se de colar o seguinte código no arquivo index.css para garantir que o aplicativo tenha a mesma aparência da visualização que você viu anteriormente:

#root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;
  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;
  min-width: 100vw;
  min-height: 100vh;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  font-weight: 500;
  color: #646cff;
  text-decoration: inherit;
}

a:hover {
  color: #535bf2;
}

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 100vw;
  min-height: 100vh;
}

h1 {
  font-size: 3.2em;
  line-height: 1.1;
}

button {
  border-radius: 8px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1em;
  font-weight: 500;
  font-family: inherit;
  background-color: #1a1a1a;
  cursor: pointer;
  transition: border-color 0.25s;
}

button:hover {
  border-color: #646cff;
}

button:focus,

button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }

  a:hover {
    color: #747bff;
  }

  button {
    background-color: #f9f9f9;
  }
}

.app {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.object-detection {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  .buttons {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: row;

    button {
      margin: 2px;
    }
  }

  div {
    margin: 4px;
  }
}

Além disso, remova o arquivo App.css para evitar bagunçar os estilos dos componentes. Agora você está pronto para escrever a lógica para integrar a detecção de objetos em tempo real ao seu aplicativo.

Configure a detecção de objetos em tempo real

  1. Comece adicionando os imports do Tensorflow e do Coco SSD na parte superior de ObjectDetection.jsx:
    import * as cocoSsd from '@tensorflow-models/coco-ssd';
    
    import '@tensorflow/tfjs';
  2. Em seguida, crie um estado no componente ObjectDetection para armazenar o array de previsões geradas pelo modelo Coco SSD:
    const [predictions, setPredictions] = useState([]);
  3. Em seguida, crie uma função que carregue o modelo Coco SSD, colete o feed de vídeo e gere as previsões:
    const predictObject = async () => {
        const model = await cocoSsd.load();
    
        model.detect(videoRef.current).then((predictions) => {
          setPredictions(predictions);
        })
    
          .catch(err => {
            console.error(err)
          });
      };

    Essa função usa o feed de vídeo e gera previsões para os objetos presentes no feed. Ela fornecerá a você um array de objetos previstos, cada um contendo uma etiqueta, uma porcentagem de confiança e um conjunto de coordenadas mostrando a localização do objeto no quadro do vídeo.

    Você precisa chamar continuamente essa função para processar os quadros de vídeo à medida que eles chegam e, em seguida, usar as previsões armazenadas no estado predictions para mostrar caixas e etiquetas para cada objeto identificado no feed de vídeo ao vivo.

  4. Em seguida, use a função setInterval para chamar a função continuamente. Você também deve impedir que essa função seja chamada depois que o usuário interromper o feed da webcam. Para fazer isso, use a função clearInterval do JavaScript. Adicione o seguinte contêiner de estado e o hook useEffect no componente ObjectDetection para configurar a função predictObject para ser chamada continuamente quando a webcam estiver ativada e removida quando a webcam estiver desativada:
    const [detectionInterval, setDetectionInterval] = useState()
    
      useEffect(() => {
        if (isWebcamStarted) {
          setDetectionInterval(setInterval(predictObject, 500))
        } else {
          if (detectionInterval) {
            clearInterval(detectionInterval)
            setDetectionInterval(null)
          }
        }
      }, [isWebcamStarted])

    Isso configura o aplicativo para detectar os objetos presentes diante da webcam a cada 500 milissegundos. Você pode alterar esse valor, dependendo da velocidade com que deseja que a detecção de objetos seja feita, mas lembre-se de que fazer isso com muita frequência pode fazer o aplicativo usar muita memória do navegador.

  5. Agora que você tem os dados de previsão no contêiner de estado prediction, pode usá-los para exibir uma etiqueta e uma caixa ao redor do objeto no feed de vídeo em tempo real. Para fazer isso, atualize a instrução return do ObjectDetection para retornar o seguinte:
    return (
        <div className="object-detection">
          <div className="buttons">
            <button onClick={isWebcamStarted ? stopWebcam : startWebcam}>{isWebcamStarted ? "Stop" : "Start"} Webcam</button>
          </div>
          <div className="feed">
            {isWebcamStarted ? <video ref={videoRef} autoPlay muted /> : <div />}
            {/* Add the tags below to show a label using the p element and a box using the div element */}
            {predictions.length > 0 && (
              predictions.map(prediction => {
                return <>
                  <p style={{
                    left: `${prediction.bbox[0]}px`, 
                    top: `${prediction.bbox[1]}px`,
                    width: `${prediction.bbox[2] - 100}px`
                }}>{prediction.class  + ' - with ' 
                + Math.round(parseFloat(prediction.score) * 100) 
                + '% confidence.'}</p>
                <div className={"marker"} style={{
                  left: `${prediction.bbox[0]}px`,
                  top: `${prediction.bbox[1]}px`,
                  width: `${prediction.bbox[2]}px`,
                  height: `${prediction.bbox[3]}px`
                }} />
                </>
              })
            )}
          </div>
          {/* Add the tags below to show a list of predictions to user */}
          {predictions.length > 0 && (
            <div>
              <h3>Predictions:</h3>
              <ul>
                {predictions.map((prediction, index) => (
                  <li key={index}>
                    {`${prediction.class} (${(prediction.score * 100).toFixed(2)}%)`}
                  </li>
                ))}
              </ul>
            </div>
          )}
    
        </div>
      );

    Isso renderizará uma lista de previsões logo abaixo do feed da webcam e desenhará uma caixa ao redor do objeto previsto usando as coordenadas do Coco SSD junto com uma etiqueta na parte superior das caixas.

  6. Para estilizar as caixas e a etiqueta corretamente, adicione o seguinte código ao arquivo index.css:
    .feed {
      position: relative;
    
      p {
        position: absolute;
        padding: 5px;
        background-color: rgba(255, 111, 0, 0.85);
        color: #FFF;
        border: 1px dashed rgba(255, 255, 255, 0.7);
        z-index: 2;
        font-size: 12px;
        margin: 0;
      }
    
      .marker {
        background: rgba(0, 255, 0, 0.25);
        border: 1px dashed #fff;
        z-index: 1;
        position: absolute;
      }
    
    }

    Isso encerra o desenvolvimento do aplicativo. Agora você pode reiniciar o servidor de desenvolvimento para testar o aplicativo. Aqui está a aparência que você deve ter quando concluído:

    Demonstração da detecção de objetos em tempo real usando a webcam
    Demonstração da detecção de objetos em tempo real usando a webcam

Você pode encontrar o código completo neste repositório do GitHub.

Implante o aplicativo concluído na Kinsta

A etapa final é implantar o aplicativo na Kinsta para torná-lo disponível aos seus usuários. Para fazer isso, a Kinsta permite que você hospede até 100 sites estáticos gratuitamente diretamente do seu provedor Git preferido (Bitbucket, GitHub ou GitLab).

Quando seu repositório git estiver pronto, siga estas etapas para implantar seu aplicativo de detecção de objetos na Kinsta:

  1. Faça login ou crie uma conta para visualizar seu painel MyKinsta.
  2. Autorize a Kinsta com seu provedor Git.
  3. Clique em Sites estáticos na barra lateral esquerda e, em seguida, clique em Adicionar site.
  4. Selecione o repositório e o branch do qual você deseja implantar.
  5. Atribua um nome exclusivo ao seu site.
  6. Adicione as configurações de build no seguinte formato:
    • Comando de build: yarn build ou npm run build
    • Versão do node: 20.2.0
    • Diretório de publicação: dist
  7. Por fim, clique em Criar site.

Depois que o aplicativo for implantado, você poderá clicar em Visitar site no painel para acessar o aplicativo. Agora você pode tentar executar o aplicativo em vários dispositivos com câmeras para ver o desempenho dele.

Como alternativa à Hospedagem de Site Estático, você pode implantar seu site estático com a Hospedagem de Aplicativos da Kinsta, que oferece maior flexibilidade de hospedagem, uma gama mais ampla de benefícios e acesso a recursos mais robustos. Por exemplo, escalabilidade, implantação personalizada usando um Dockerfile e análises completas que englobam dados históricos e em tempo real.

Resumo

Você criou com sucesso um aplicativo de detecção de objetos em tempo real usando React, TensorFlow.js e a Kinsta. Isso permite explorar o empolgante mundo da visão computacional, criando experiências interativas diretamente no navegador do usuário.

Lembre-se de que o modelo Coco SSD que usamos é apenas um ponto de partida. Explorando mais, você pode se aprofundar na detecção de objetos personalizados usando o TensorFlow.js, o que permite adaptar o aplicativo para identificar objetos específicos relevantes para suas necessidades.

As possibilidades são vastas! Este aplicativo serve como base para criar aplicativos mais detalhados, como experiências de realidade aumentada ou sistemas de vigilância inteligentes. Ao implantar seu aplicativo na plataforma confiável da Kinsta, você pode compartilhar sua criação com o mundo e testemunhar o poder da visão computacional ganhando vida.

Qual é o problema que você encontrou e que acha que a detecção de objetos em tempo real pode resolver? Deixe-nos saber nos comentários abaixo!

Kumar Harsh

Kumar é um desenvolvedor de software e autor técnico baseado na Índia. Ele é especialista em JavaScript e DevOps. Você pode saber mais sobre o trabalho dele em seu site.