You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/pt/5-retail/lessons/2-check-stock-device/single-board-computer-count...

10 KiB

Contar stock a partir do seu dispositivo IoT - Hardware IoT Virtual e Raspberry Pi

Uma combinação das previsões e das suas caixas delimitadoras pode ser usada para contar o stock numa imagem.

Mostrar caixas delimitadoras

Como um passo útil de depuração, pode não só imprimir as caixas delimitadoras, mas também desenhá-las na imagem que foi gravada no disco quando uma imagem foi capturada.

Tarefa - imprimir as caixas delimitadoras

  1. Certifique-se de que o projeto stock-counter está aberto no VS Code e que o ambiente virtual está ativado, caso esteja a usar um dispositivo IoT virtual.

  2. Altere a instrução print no ciclo for para o seguinte, para imprimir as caixas delimitadoras no terminal:

    print(f'{prediction.tag_name}:\t{prediction.probability * 100:.2f}%\t{prediction.bounding_box}')
    
  3. Execute a aplicação com a câmara apontada para algum stock numa prateleira. As caixas delimitadoras serão impressas no terminal, com valores de esquerda, topo, largura e altura entre 0 e 1.

    pi@raspberrypi:~/stock-counter $ python3 app.py 
    tomato paste:   33.42%  {'additional_properties': {}, 'left': 0.3455171, 'top': 0.09916268, 'width': 0.14175442, 'height': 0.29405564}
    tomato paste:   34.41%  {'additional_properties': {}, 'left': 0.48283678, 'top': 0.10242918, 'width': 0.11782813, 'height': 0.27467814}
    tomato paste:   31.25%  {'additional_properties': {}, 'left': 0.4923783, 'top': 0.35007596, 'width': 0.13668466, 'height': 0.28304994}
    tomato paste:   31.05%  {'additional_properties': {}, 'left': 0.36416405, 'top': 0.37494493, 'width': 0.14024884, 'height': 0.26880276}
    

Tarefa - desenhar caixas delimitadoras na imagem

  1. O pacote Pip Pillow pode ser usado para desenhar em imagens. Instale-o com o seguinte comando:

    pip3 install pillow
    

    Se estiver a usar um dispositivo IoT virtual, certifique-se de que executa este comando dentro do ambiente virtual ativado.

  2. Adicione a seguinte instrução de importação ao topo do ficheiro app.py:

    from PIL import Image, ImageDraw, ImageColor
    

    Isto importa o código necessário para editar a imagem.

  3. Adicione o seguinte código ao final do ficheiro app.py:

    with Image.open('image.jpg') as im:
        draw = ImageDraw.Draw(im)
    
        for prediction in predictions:
            scale_left = prediction.bounding_box.left
            scale_top = prediction.bounding_box.top
            scale_right = prediction.bounding_box.left + prediction.bounding_box.width
            scale_bottom = prediction.bounding_box.top + prediction.bounding_box.height
    
            left = scale_left * im.width
            top = scale_top * im.height
            right = scale_right * im.width
            bottom = scale_bottom * im.height
    
            draw.rectangle([left, top, right, bottom], outline=ImageColor.getrgb('red'), width=2)
    
        im.save('image.jpg')
    

    Este código abre a imagem que foi guardada anteriormente para edição. Em seguida, percorre as previsões, obtendo as caixas delimitadoras e calcula a coordenada inferior direita usando os valores da caixa delimitadora entre 0 e 1. Estes valores são então convertidos para coordenadas da imagem, multiplicando pela dimensão relevante da imagem. Por exemplo, se o valor da esquerda fosse 0.5 numa imagem com 600 píxeis de largura, isso seria convertido para 300 (0.5 x 600 = 300).

    Cada caixa delimitadora é desenhada na imagem usando uma linha vermelha. Finalmente, a imagem editada é guardada, substituindo a imagem original.

  4. Execute a aplicação com a câmara apontada para algum stock numa prateleira. Verá o ficheiro image.jpg no explorador do VS Code e poderá selecioná-lo para ver as caixas delimitadoras.

    4 latas de polpa de tomate com caixas delimitadoras em volta de cada lata

Contar stock

Na imagem mostrada acima, as caixas delimitadoras têm uma pequena sobreposição. Se esta sobreposição fosse muito maior, as caixas delimitadoras poderiam indicar o mesmo objeto. Para contar os objetos corretamente, é necessário ignorar caixas com uma sobreposição significativa.

Tarefa - contar stock ignorando sobreposição

  1. O pacote Pip Shapely pode ser usado para calcular a interseção. Se estiver a usar um Raspberry Pi, precisará de instalar uma dependência de biblioteca primeiro:

    sudo apt install libgeos-dev
    
  2. Instale o pacote Pip Shapely:

    pip3 install shapely
    

    Se estiver a usar um dispositivo IoT virtual, certifique-se de que executa este comando dentro do ambiente virtual ativado.

  3. Adicione a seguinte instrução de importação ao topo do ficheiro app.py:

    from shapely.geometry import Polygon
    

    Isto importa o código necessário para criar polígonos e calcular sobreposições.

  4. Acima do código que desenha as caixas delimitadoras, adicione o seguinte código:

    overlap_threshold = 0.20
    

    Isto define a percentagem de sobreposição permitida antes de as caixas delimitadoras serem consideradas como representando o mesmo objeto. 0.20 define uma sobreposição de 20%.

  5. Para calcular a sobreposição usando o Shapely, as caixas delimitadoras precisam de ser convertidas em polígonos Shapely. Adicione a seguinte função para fazer isso:

    def create_polygon(prediction):
        scale_left = prediction.bounding_box.left
        scale_top = prediction.bounding_box.top
        scale_right = prediction.bounding_box.left + prediction.bounding_box.width
        scale_bottom = prediction.bounding_box.top + prediction.bounding_box.height
    
        return Polygon([(scale_left, scale_top), (scale_right, scale_top), (scale_right, scale_bottom), (scale_left, scale_bottom)])
    

    Esta função cria um polígono usando a caixa delimitadora de uma previsão.

  6. A lógica para remover objetos sobrepostos envolve comparar todas as caixas delimitadoras e, se algum par de previsões tiver caixas delimitadoras que se sobreponham mais do que o limite, uma das previsões é eliminada. Para comparar todas as previsões, compara-se a previsão 1 com 2, 3, 4, etc., depois a 2 com 3, 4, etc. O seguinte código faz isso:

    to_delete = []
    
    for i in range(0, len(predictions)):
        polygon_1 = create_polygon(predictions[i])
    
        for j in range(i+1, len(predictions)):
            polygon_2 = create_polygon(predictions[j])
            overlap = polygon_1.intersection(polygon_2).area
    
            smallest_area = min(polygon_1.area, polygon_2.area)
    
            if overlap > (overlap_threshold * smallest_area):
                to_delete.append(predictions[i])
                break
    
    for d in to_delete:
        predictions.remove(d)
    
    print(f'Counted {len(predictions)} stock items')
    

    A sobreposição é calculada usando o método Polygon.intersection do Shapely, que retorna um polígono com a área de sobreposição. A área é então calculada a partir deste polígono. Este limite de sobreposição não é um valor absoluto, mas precisa de ser uma percentagem da caixa delimitadora, por isso a menor caixa delimitadora é encontrada, e o limite de sobreposição é usado para calcular qual a área de sobreposição que não pode exceder a percentagem definida. Se a sobreposição exceder este valor, a previsão é marcada para eliminação.

    Uma vez que uma previsão foi marcada para eliminação, não precisa de ser verificada novamente, por isso o ciclo interno é interrompido para verificar a próxima previsão. Não se pode eliminar itens de uma lista enquanto se itera sobre ela, por isso as caixas delimitadoras que se sobrepõem mais do que o limite são adicionadas à lista to_delete, sendo eliminadas no final.

    Finalmente, o número de stocks é impresso no terminal. Este valor poderia ser enviado para um serviço IoT para alertar se os níveis de stock estiverem baixos. Todo este código é executado antes de as caixas delimitadoras serem desenhadas, por isso verá as previsões de stock sem sobreposições nas imagens geradas.

    💁 Este é um método muito simples para remover sobreposições, eliminando apenas o primeiro de um par sobreposto. Para código de produção, seria necessário adicionar mais lógica, como considerar as sobreposições entre múltiplos objetos ou se uma caixa delimitadora está contida dentro de outra.

  7. Execute a aplicação com a câmara apontada para algum stock numa prateleira. O resultado indicará o número de caixas delimitadoras sem sobreposições que excedam o limite. Experimente ajustar o valor de overlap_threshold para ver previsões a serem ignoradas.

💁 Pode encontrar este código na pasta code-count/pi ou code-count/virtual-iot-device.

😀 O seu programa de contagem de stock foi um sucesso!

Aviso Legal:
Este documento foi traduzido utilizando o serviço de tradução por IA Co-op Translator. Embora nos esforcemos para garantir a precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.