Índice
Você gosta de NBA e gosta de programação? Então agora é a hora de juntar esses dois universos de uma maneira divertida e relativamente fácil. Além disso, vai servir para você guardar as jogadas que mais gostar dos seus times ou jogadores favoritos. Afinal, em um mundo onde o consumo de conteúdo precisa ser cada vez mais veloz (e precisa chamar a atenção logo), é importante saber que nem todo fã de basquete assiste aos jogos inteiros. Essas pessoas preferem os chamados highlights (o nome mais comum para lances ou jogadas em destaque). O objetivo desse artigo é te ajudar a criar esses vídeos com open source. E aí, vamos nessa?
Este projeto foi escrito em python, mas pode ser facilmente replicado em qualquer linguagem. E antes de começarmos, é importante mencionar as bibliotecas que foram usadas neste projeto:
Jogada por jogada
O play-by-play fornece uma transcrição do jogo em um formato de eventos individuais. Veja alguns exemplos de dados que podem ser encontrados no play-by-play:
- Tempo de posse de bola (no relógio do jogo);
- Período em que a posse de bola ocorreu;
- O jogador que iniciou a posse de bola (no caso de um roubo ou rebote defensivo);
- O jogador adversário que iniciou a posse de bola (no caso de um arremesso perdido ou de um turnover), incluindo o local na quadra de onde o arremesso foi feito e outros identificadores exclusivos que usamos para classificar o tipo de posse.
Lembrando que os dados que estamos extraindo são das APIs oficiais da NBA (data.nba.net e cdn.nba.com) e eles são armazenados no formato JSON. Ou seja, para obter os dados em um formato mais tradicional, como um dataframe, precisamos apenas executar algumas linhas de código.
Portanto, a primeira parte fornece os jogos que foram disputados em uma determinada data:
Em seguida, verificamos se as equipes inseridas realmente jogaram na data determinada. Se tiverem jogado, pegamos o ID do jogo e o inserimos na próxima API. Então nós extraímos os dados e os carregamos em um dataframe do pandas:
raw_game = f'https://cdn.nba.com/static/json/liveData/playbyplay/playbyplay_{game_id}.json'
page = requests.get(raw_game)
j = json.loads(page.content)
df = pd.DataFrame(j['game']['actions'])
Depois disso, o resultado fica parecido com algo assim:
A partir daí, podemos filtrar qualquer tipo de jogada que nos interesse (cestas, roubos de bola, bloqueios, etc.). No nosso caso, estamos apenas considerando as cestas feitas e excluindo os lances livres. Ou seja, fica assim:
ndf = df[['clock', 'period', 'description', 'teamTricode', 'shotResult', 'actionType']]
ndf = ndf[ndf['shotResult'] == 'Made']
ndf = ndf[ndf['actionType'] != 'freethrow']
Agora que temos um conjunto de dados de todos os pontos de interesse no jogo, é hora de encontrá-los na filmagem real do jogo.
Processamento do vídeo do jogo
A próxima etapa é processar o vídeo do jogo em quadros e manipulá-los usando o módulo OpenCV.
Agora, cada quadro passará por uma série de manipulações (pré-processamento) para prepará-lo para o OCR (daqui a pouco vamos falar mais sobre isso). Portanto, se liga nas etapas:
- Cortar o quadro original e deixar apenas o terço inferior, onde está localizado o relógio do jogo (para não perder tempo lendo o quadro inteiro);
- Converter a imagem em escala de cinza;
- Converter a imagem em escala de cinza para preto e branco;
- Aplique o desfoque gaussiano à imagem em preto e branco.
Original
Cortado
Com o desfoque gaussiano
Tesseract
Este é um mecanismo de reconhecimento óptico de caracteres com código-fonte aberto, sendo a biblioteca de OCR mais popular e qualitativa para usarmos. E também é bastante moderna, já que o OCR usa inteligência artificial para pesquisa e reconhecimento de texto em imagens. Na verdade, o trabalho neste caso é bem simples: encontrar modelos em pixels, letras, palavras e frases.
Além disso, ele tem a capacidade de reconhecer mais de 100 idiomas prontos para uso e pode ser treinado para reconhecer outros. Basicamente, o mecanismo procura e extrai texto de imagens. Mas agora trazendo isso para este projeto, estamos usando o python-tesseract (pytesseract), que é um wrapper python para o mecanismo Tesseract-OCR do Google. Nele, há 13 modos de configuração do tesseract. Porém, nós vamos focar no uso do modo 11: texto esparso. Ou seja, vamos encontrar o máximo de texto possível, sem nenhuma ordem específica.
Implementação do Tesseract
A próxima etapa é executar nosso quadro processado por meio do mecanismo tesseract.
Agora que temos todo o texto no quadro, podemos pesquisar as informações que desejamos, ou seja, o quarto atual e o relógio do jogo:
O quarto é “1st” e o relógio do jogo é “7:32”. Entretanto, na saída do Tesseract, a detecção é “ist”. Ou seja, o número “1” foi confundido com a letra “i”.
Portanto, a próxima etapa é criar um mapeamento dos erros comuns para cada quarto.
Combinando os dados do play-by-play com os dados da filmagem
Muito bem, vamos resumir o que temos até agora: criamos um rastreador do play-by-play, manipulamos quadros de filmagem do jogo e os executamos por meio do mecanismo Tesseract para extrair o texto do quadro. Agora é hora de combinar os dados e encontrar os destaques.
Mas como podemos fazer isso? Bom, processando cada quadro da filmagem do jogo, conforme discutido acima, e verificando se a combinação extraída de quarto e relógio do jogo corresponde ao quarto e ao relógio de um destaque.
Se houver uma correspondência, salvamos o número do quadro.
Juntando os quadros
Quando terminarmos de examinar todos os quadros do jogo e tivermos uma lista de frames em que ocorreram destaques, tudo o que temos a fazer é juntá-los. E nós faremos isso usando o módulo moviepy, que nos permite cortar subclipes de vídeos completos. Portanto, para ver toda a jogada que levou ao destaque, pegamos alguns segundos antes e alguns segundos depois do segundo exato em que o destaque ocorreu.
Exemplo de highlights
Agora que terminamos de criar os destaques, vamos ver o resultado.
Melhoria da eficiência
Esse é um script básico para localizar pontos de interesse e criar clipes de destaque, mas está longe de ser eficiente. Entretanto, a eficiência pode ser facilmente aprimorada de várias maneiras, como por exemplo:
- Pular um segundo em vez de verificar cada quadro reduz o número de quadros processados em um jogo de 2 horas (de 60 fps) de 430.000 para 7.200.
- Localizar as coordenadas do relógio do jogo e executar somente essa área no mecanismo de OCR reduzirá o tempo de execução.
- Prefira alterações no placar em vez de no relógio do jogo (se quiser apenas cestas marcadas)
- Use o multiprocessamento para trabalhar em paralelo e acelerar o processo — uma GPU também pode ajudar.
Para resumir
Este é apenas um pequeno exemplo de como as tecnologias de código aberto podem ser utilizadas para criar produtos incríveis. Mas você não precisa parar por aqui, viu? Se quiser, nós trabalhamos em conjunto em alguns projetos de programação de código aberto na nossa Comunidade. Ainda não conhece? Então clique aqui e participe de forma 100% gratuita. E se quiser saber mais detalhes dos vários benefícios que você recebe ao participar de graça, veja aqui. Estou te esperando por lá, combinado? Se tiver qualquer dúvida, pode me pingar pelo @ine.
[Este texto foi traduzido e adaptado a partir do artigo do Better Programming]