Nuova sezione libri disponibile!

Sviluppiamo un bot Telegram che legge i codici a barre degli alimenti

Ludovico Russo

lettura in 5 minuti

Qualche giorno fa, ho sviluppato un breve articolo che spiega come implementare un sistema in grado di leggere ed analizzare i codici a barre per alimenti utilizzando OpenCV e la libreria zbar, ovviamente in Python.

In questa guida, voglio estendere il codice implementato nel tutorial precedente ed integrarlo ad un bot Telegram, in modo che questo sia in grado di leggere le informazioni dal codice a barre ed rispondere all'utente con queste info.

Vediamo come fare

Per prima cosa, come sempre, dobbiamo creare un ambiente virtuale ed installare python e le varie dipendenze... Dobbiamo installare le varie librerie viste nel tutorial precedente pi√Ļ la libreria telepot per gestire Telegram. Questa volta non la faccio lunga:

$ mkdir barcode-telegram
$ cd barcode-telegram
$ virtualenv -ppython3 env
$ source env/bin/activate
(env)$ pip install telepot pyzbar opencv-python requests

Siamo pronti per iniziare. Ovviamente, partiamo dal codice già implementato nel tutorial precedente. Creiamo un file bot_barcode.py ed implementiamo il seguente codice:

from pyzbar.pyzbar import decode
import cv2
import requests

def get_barcode_info(img):
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    barcodes = decode(gray_img)

    if len(barcodes) == 1:
        code = barcodes[0].data
        url = "https://it.openfoodfacts.org/api/v0/product/{}.json".format(code)
        data = requests.get(url).json()
        if data["status"] == 1:
            product = data["product"]
            brand = product["brands"]
            return "produttore: {}    nome: {}".format(product["brands"], product["product_name"])
        else:
            return "Prodotto non trovato!"
    else:
        return "Codice a barre non trovato!"

La funzione get_barcode_info, come già spieato in precedenza, riceve un'immagine OpenCV e ritorna la stringa contenente le informazioni trovate!

Precedentemente avevamo impresso le immagini all'interno dell'immagine stessa con OpenCV. Questa volta, semplicemente facciamo ritornare queste informazioni a Telegram.

Impostiamo quindi il bot Telegram, implementando il seguente codice:

# ...
import telepot

def get_barcode_info(img):
  #...

def on_chat_message(msg):
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'text':
        bot.sendMessage(chat_id, 'ciao, sono un bot molto stupido!')

TOKEN = '*** inserisci il tuo token qui  ***'

bot = telepot.Bot(TOKEN)
bot.message_loop(on_chat_message)

print 'Listening ...'

import time
while 1:
    time.sleep(10)

Leggete questo mio articolo se non sapete cosa fa il codice implementato su!

Leggere le immagini da Telegram

Per unire il tutto ci manca un pezzo.. Come facciamo a leggere l'immagine da Telegram e passarla alla funzione get_barcode_info?

Fortunatamente, Telepot è già in grado di gestire le immagini. Sfortunatamente mette a disposizione un unico metodo che permette di scaricare l'immagine come file su disco.

Leggere l'immagine come file

Per leggere l'immagine, il modo pi√Ļ semplice che ho trovato consiste nel salvare l'immagine come file e poi leggerla da OpenCV. Questo metodo non √® molto efficace ma funzione, e sar√† il punto di partenza per testare il nostro progetto.

Per prima cosa dobbiamo controllare che il content_type sia di tipo photo. Nel caso, possiamo scaricare l'immagine con il comando bot.download_file(msg['photo'][-1]['file_id'], 'image.png') e a questo punto la possiamo leggere il file image.png con il comando cv2.imread.

if content_type == 'photo':
    bot.download_file(msg['photo'][-1]['file_id'], 'image.png')
    img = cv2.imread('image.png')

Fatto questo, basta passare la foto img a get_barcode_info() e mandare la stringa ottenuta come riposta.

    data = get_barcode_info(img)
    bot.sendMessage(chat_id, data)

Ho notato che il tempo di risposta del bot è lento, quindi per non bloccare l'utente aggiungiamo una risposta di "Attendi" prima di analizzare la foto.

Gestiamo inoltre il caso in cui l'utente invia un dato che non è un'immagine con una semplice risposta automatica.

Il codice completo per la funzione handle è quindi il seguente

def handle(msg):
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'photo':
        bot.download_file(msg['photo'][-1]['file_id'], 'image.png')
        img = cv2.imread('image.png')
        bot.sendMessage(chat_id, "Sto cercando...")
        data = get_barcode_info(img)
        bot.sendMessage(chat_id, data)
    else:
      bot.sendMessage(chat_id, "Inviami una foto contenente un codice a barre!")

Siamo pronti per testare il bot. Avviamo il programma

(env)$ python bot-barcode.py

E iniziamo a comunicare con il bot. Se tutto funziona, dovrebbe essere in grado di rispondere correttamente, come segue!

Bot Telegram Legge i Codici a Barre

Evitare di salvare l'immagine su file

Il salvataggio dell'immagine su file e poi il ricaricamento di qeusta in memoria non è molto efficiente in quanto spreca tempo (di lettura e scrittura) e risorse (Hard Disk). Litigandoci un po', ho però trovato una soluzione efficace che sfrutta il modulo nativo di Python3 io.BytesIO, che essenzialmente simula un file caricato in memoria RAM (quindi che non viene veramente salvato su disco). Quello che dobbiamo, è creare un file io.BytesIO, salvare l'immagine su questo file e poi leggerla con OpenCV. Il tutto è dato da queste linee di codice:

    raw_img = io.BytesIO()
    bot.download_file(msg['photo'][-1]['file_id'], raw_img)
    file_bytes = np.fromstring(raw_img.getvalue(), dtype=np.uint8)
    img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)

Che richiedono di importare le seguenti librerie

import io
import numpy as np

La funzione modificata diventa la seguente

def handle(msg):
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'photo':
        raw_img = io.BytesIO()
        bot.download_file(msg['photo'][-1]['file_id'], raw_img)
        file_bytes = np.fromstring(raw_img.getvalue(), dtype=np.uint8)
        img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
        bot.sendMessage(chat_id, "Sto cercando...")
        data = get_barcode_info(img)
        bot.sendMessage(chat_id, data)
    else:
      bot.sendMessage(chat_id, "Inviami una foto contenente un codice a barre!")

Provate a lanciare il codice. Noterete che √® molto pi√Ļ veloce di quello precedente!

Codice completo

Qui trovate il codice completo sviluppato in questo articolo

from pyzbar.pyzbar import decode
import requests
import telepot
import cv2
import numpy as np
import io

def get_barcode_info(img):
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    barcodes = decode(gray_img)

    if len(barcodes) == 1:
        code = barcodes[0].data
        url = "https://it.openfoodfacts.org/api/v0/product/{}.json".format(code)
        data = requests.get(url).json()
        if data["status"] == 1:
            product = data["product"]
            brand = product["brands"]
            return "produttore: {}    nome: {}".format(product["brands"], product["product_name"])
        else:
            return "Prodotto non trovato!"
    else:
        return "Codice a barre non trovato!"


def handle(msg):
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'photo':
        raw_img = io.BytesIO()
        bot.download_file(msg['photo'][-1]['file_id'], raw_img)
        file_bytes = np.fromstring(raw_img.getvalue(), dtype=np.uint8)
        img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
        bot.sendMessage(chat_id, "Sto cercando...")
        data = get_barcode_info(img)
        bot.sendMessage(chat_id, data)
    else:
      bot.sendMessage(chat_id, "Inviami una foto contenente un codice a barre!")

TOKEN = '*** inserisci il tuo token qui  ***'

bot = telepot.Bot(TOKEN)
bot.message_loop(handle)

print('Listening ...')

import time
while 1:
    time.sleep(10)

Conclusioni

Questo progetto mi è veramente piaciuto e l'ho trovato super divertente. In realtà, con questo tutorial voglio inaugurare una serie di articoli che sfruttano Telegram e la Computer Vision (con OpenCV) per sviluppare bot in grado di fare Image Processing.

Se qualcuno ha possibili applicazioni per queste tecnologie, me lo dica sotto nei commenti, potremmo farla diventare un tutorial!!

A presto.

Ti è piaciuto questo post?

Registrati alla newsletter per rimanere sempre aggiornato!

Ci tengo alla tua privacy. Leggi di pi√Ļ sulla mia Privacy Policy.

Ti potrebbe anche interessare

HB Cloud Tutorial #1 - Uso dei Led
Iniziamo ad utilizzare la piattaforma di Cloud Robotics
HB Cloud Tutorial #2 - Uso dei Bottoni
Rieccomi con il secondo tutorial legato all'uso dei bottoni per il robot **DotBot-ROS**. In questo tutorial, vedremo come configurare ed utilizzare in Python un bottone attaccato ad un pin GPIO del Raspberry Pi 3.
HB Cloud Tutorial #3 - I Motori
I Motori sono una delle parti essenziali dei robot. In questo tutorial, vederemo come è possibile in modo semplice ed intuitivo implementare un programma in Python che controlla i motori in base a comandi inviati via Wifi al Robot.
Inviare Goals alla Navigation Stack - versione nodo ROS Python
Inviare un goal all ROS navigation stack utilizzando un nodo Python
Controllare siBOT dalla piattaforma HBR
Come controllare il manipolatore siBOT utilizzando la piattaforma HBR
Sviluppare un rilevatore di fiamma con la visione artificiale
Sviluppare un rilevatore di fiamma con la visione artificiale
Scriviamo un Blog in Python e Flask
Tutorial su come implementare, a partire da zero, un blog personale utilizzando Python e Flask! Prima parte!
Un laboratorio di Fisica con Arduino e Python
Primi esperimenti con Arduino e Python per realizzare un semplice laboratorio di fisica sfruttando la potenza di Python e la versatilità di Arduino
Canopy: una Pythonica alternativa a Matlab
Presento questo interessante tool python che può essere considerato una buona alternativa a Matlab per l'analisi dei dati!
Spyder, un'altra alternativa in Python a Matlab
Una velocissima prova del tool interattivo Spyder per l'analisi scientifica in Python
Simuliamo il moto parabolico in Python e Spyder
Un piccolo tutorial per iniziare ad utilizzare Spyder con Python
Python + Arduino = Nanpy
Programmare Arduino in Python con Nanpy
Utilizzo di Nanpy con il sensore di temperatura/umidità della famiglia DHT
Come utilizzare Nanpy col sensore DHT di temperatura e Umidità
Accendere led con Arduino e Telegram
Un bot telegram in grado di controllare Arduino realizzato da 3 ragazzi del Liceo Stampacchia
Implementiamo un bot Telegram con Python
Una semplice guida per iniziare a muovere i primi passi nello sviluppo di chatbot Telegram con Python
Pillole di Python: pyscreenshot
Una semplice tutorial che mostra il funzionamento della libreria pyscreenshot
Python Decorators
Introduzione ai decoratori in Python
TDD con Flask e PyTest per lo sviluppo di API REST. Parte 1
Tutorial su come usare il Test Driver Development (TDD) con Flask e PyTest per sviluppare delle semplici API REST
Implementiamo un bot Telegram con Python - I Comandi
Vediamo come gestire i comandi del nostro bot in Telegram
4 (+1) Libri su Python (in Inglese) da cui imparare
Una lista di libri su Python (in Inglese) da cui ho imparato a programmare
Virtualenv: gestiamo meglio le dipendenze in Python
A cosa servono e come si utilizzano i virtualenv Python
Leggere i codici a barre con OpenCV e zbar in Python
Come usare Python per leggere i codici a barre degli alimenti e ricavarne alcune informazioni utili
TDD con Flask e PyTest per lo sviluppo di API REST. Parte 2
Tutorial su come usare il Test Driver Development (TDD) con Flask e PyTest per sviluppare delle semplici API REST
TDD con Flask e PyTest per lo sviluppo di API REST. Parte 3
Tutorial su come usare il Test Driver Development (TDD) con Flask e PyTest per sviluppare delle semplici API REST
Divertiamoci sviluppando UI da terminale con ASCIIMATICS
Le UI da terminale fanno molto anni '80, però sono sempre diventerti da implementare. Oggi vi voglio introdurre ad una semplice libreria per creare questo tipo di applicazione.
Sviluppiamo un Robot con tecnologie Open Source
Inizio una serie di videoguide, in cui voglio introdurvi al mondo della robotica di servizio in modo pratico, facendo vedere come è possibilile, sfruttando tecnologie completamente Open Source, quali Arduino, Raspberry Pi, ROS e Docker, costruire un piccolo robot di Servizio.
Parliamo come GMaps: come creare file audio con gtts (Google Text to Speech) in Python
gtts è una libreria in Python per sfruttare le API di Google Text to Speech per generare file audio dal testo
Robot Open Source - Introduzione a Docker
√ą disponibile il video "Introduzione a Docker".
I chatbot possono Parlare? Sviluppiamo un bot telegram che manda messaggi vocali
Usiamo le API di sintesi vocale di google per creare un bot in grado di mandare messaggi vocali
Robot Open Source - Docker e Raspberry
√ą disponibile il video "Docker e Raspberry".
Un bot telegram che invia messaggi al verificarsi di eventi sui GPIO del Raspberry Pi
Mandare un messaggio tramite telegram quando il un GPIO del Raspberry cambia stato è possibile, ecco come!