Video Creator – #Parte 7: Busca e download de imagens

Bom dia, boa tarde, boa noite!

Essa é a sétima parte da série sobre o projeto Video Creator, onde mostrarei como fiz a busca pelas imagens.

Se você entrou direto nesse post, te aconselho a começar por aqui, para entender exatamente do que se trata essa série.

Sobre essa parte

Basicamente o que fiz foi concatenar o assunto pesquisado com a primeira keyword da lista de keywords de cada sentença.

Bem simples!

Requisitos:

O principal requisito, é claro, é óbvio… criação do Bing Resource na Azure e a criação da instância do Bing Custom Search. Tudo isso eu mostrei no último post!

Utilizei também 2 imports praticamente pradrões nesse projeto:

import json
import requests

rimage.py

A parte da busca e do download das imagens, ficou no robô rimage.py.

A chamada ao endpoint do ping resolvi colocar dentro de uma função que recebe 2 parâmetros: a query de pesquisa e a quantidade de imagens que o serviço irá devolver. Ficou assim:

# implementando busca de imagens pelo Bing
def search_images_on_bing(query, count="1"):
    logging.info("Searching images on Bing with custom bing image search")

    url = credentials['bing_endpoint'] + "?q=" + query + "&count="+ count +"&customconfig=" + credentials['bing_custom_config_id'] +"&licence=ShareCommercially&size=Large"
    r = requests.get(url, headers={'Ocp-Apim-Subscription-Key': credentials['azure_subscription_key']})
    response = json.loads(r.text)
    if 'value' in response:
        result = [d['contentUrl'] for d in response['value']]
    else:
        result = []
    
    return result

Notem que essa função é bem simples, recebe uma query e a quantidade que ela deve retornar de resultado, ai foi só bater na api passando esses parâmetros, fazer o parser do json e extrair somente os links das imagens para enviar como retorno.

Para esse projeto eu utilizei os seguintes parâmetros:

  • licence=ShareCommercially
    • Retornará imagens que podem ser usadas com propósito pessoal ou comercial
  • size=Large
    • Retornará imagens de no mínimo 500×500 pixels

A Api do bing é realmente fantástica. Existem inúmeros parâmetros que podem ser usados para refinar a busca. Quem quiser personalizar ainda mais a busca, só ver os parametros disponíveis na página oficial da api:

https://docs.microsoft.com/en-us/rest/api/cognitiveservices-bingsearch/bing-custom-images-api-v7-reference

Criei uma outra função responsável por iterar nas sentenças, montar a query de pesquisa e chamar a função acima. Ficou assim:


def fetch_images_from_sentences():
    logging.info("Fetching images from sentences...")
    print("Fetching images from sentences", end='\n\n')
    # loading content
    logging.info("Get sentences from object saved")
    print("Loading content from content.json")
    video_content = rcontent.load()
    for sentence in video_content['sentences']:
        if len(sentence['keywords'])>0:
            if video_content['search_term'] != sentence['keywords'][0]:
                sentence['image_search_query'] = "{} {}".format(video_content['search_term'], sentence['keywords'][0])
                sentence['images'] = search_images_on_bing(sentence['image_search_query'], "5")
                time.sleep(1.5)
    rcontent.save(video_content)

Três pontos importantes aqui:

O primeiro é sobre o atributo sentence['image_search_query'], onde eu armazeno o termo que eu utilizei para buscar as imagens, e ele é composto pelo assunto do video + a primeira keyword da lista. Isso para evitar que seja buscado imagens com uma keyword muito genérica que não tenha ligação com o assunto principal.

O segundo é sobre como foi construído o fluxo das coisas. O robô de imagem funciona completamente independente dos demais. O que ele precisa é que exista um arquivo content.json na estrutura esperada. Por isso quando rodamos o rimage.py, ele utiliza a função load() do rcontent.py para buscar o conteúdo do video e efetuar a busca das imagens. Após encontrar as imagens, ele gera uma lista com os links e grava dentro do atributo images, dentro de sentences.

O terceiro ponto é o time.sleep(1.5) no final da função, que precisei incluir para respeitar os limites de Free Tier do Bing Resource. Com isso, eu garanto que só vou fazer 1 chamada por segundo.

Download das imagens

Para o download das imagens, inclui todos os passos dentro de uma função que eu chamei de download_images(). Ficou assim:


def download_images():
    logging.info("Downloading images from each sentences")
    #os.chdir('./')
    path = CONTENT_IMAGES_PATH

    # create directory
    os.makedirs(path, exist_ok=True)
    # limpando a pasta
    os.system("rm -rf {}/*".format(path))
    video_content = rcontent.load()

    list_img = []

    for idx_s, sentence in enumerate(video_content['sentences']):
        for idx_i, image in enumerate(sentence['images']):
            if image not in list_img:
                # if an image doesn't downloaded, try another one
                try:
                    print("Trying to download: ", image)
                    image_filename = "{}/{}_original.jpg".format(path,idx_s)
                    wget.download(image,image_filename)
                    list_img.append(image)
                    print("")
                    break
                except Exception as ex:
                    logging.error(ex)
                    continue
    
    video_content['images_used'] = list_img
    rcontent.save(video_content)

O que essa função faz é basicamente:

  1. verificar se a pasta onde ficará as imagens já existe, se não… cria…
  2. Remover todas as imagens existentes na pasta
  3. Carrega o conteúdo da content.json para buscar os links das imagens buscadas
  4. Itera nas sentenças e nas imagens encontradas.
  5. Faz uma verificação se a imagem já não foi baixada
  6. Tenta realizar o download da imagem, se por algum motivo ele não conseguir, ele tenta a próxima imagem.
  7. Grava o link das imagens baixadas dentro do atributo images_used e salva o objeto em content.json

Next steps?!

Com conteúdo textual e imagens devidamente providenciadas, é hora de começar a montar o video.

Mostro como fiz, no próximo post!

Abraço!