Skip to content

Identificare immagini tramite API remote

Tra i servizi che possiamo utilizzare in Xojo tramite chiamate di API remote non possiamo trascurare quelli relativi all’apprendimento automatico, con particolare attenzione verso quelli che permettono di classificare le immagini.

Sulla rete possiamo trovare diverse API, fornite dai principali player del settore, che offrono questi servizi, con costi diversi e modalità di accesso piuttosto simili.

In questo post valutiamo alcuni esempi dei servizi offerti da IBM tramite Watson e come utilizzarli con Xojo

IBM Watson

Già da tempo la IBM ha aperto la sezione Watson dei propri servizi. Come tutti sono a pagamento ma è possibile testarli gratuitamente, come utente Lite, e quindi valutarne le possibilità. La documentazione e la varietà dei servizi è ampia e comprende, tra gli altri, i servizi di riconoscimento delle immagini.

Riconoscimento delle immagini in Watson

Questo servizio offre principalmente due possibilità: identificare i visi in una immagine (restituendone la posizione, il probabile genere del soggetto e il probabile intervallo d’età) e la classificazione (ovvero il riconoscimento di possibili tag associabili all’immagine).

Il concetto chiave di questo tipo di processo è: probabilità. A differenza di come pensano in molti, il risultato è un possibile risultato non una certezza, sta a noi decidere se accettare o meno questo tipo di risultato (ad esempio accettare in automatico i valori con probabilità alta e/o rimandare ad un check successivo “umano” quelli con probabilità medio bassa).

Per la classificazione Watson offre un vasto classificatore (con definizioni localizzate anche in italiano) ed è possibile creare i propri classificatori per progetti specifici. Per l’utente Lite è possibile crearne uno solo sostituibile ma non aggiornabile, ma non ci sono limiti nelle classi definibili a parte il limite di quante immagini (numero e dimensione totale) è possibile caricare sul sistema.

La documentazione del servizio è completa, semplice da utilizzare e dopo aver creato il servizio nel proprio account e possibile iniziare ad usarlo con il terminale o con l’interfaccia web offerta.

Uso con Xojo

Visto che i servizi sono API REST possiamo riprendere i concetti di quanto visto in Utilizzare API REST  e in Generare file PDF tramite API Remote e quindi partire da un oggetto Xojo.Net.HTTPSocket per implementare un oggetto base.

Avendo diversi servizi a disposizione creiamo in questo caso una sottoclasse base per gestire le API e delle ulteriori sottoclassi di queste per sfruttare i vari servizi di Watson.

La classe base deve occuparsi di rendere unica la risposta (nel senso di tipologia, poi il contenuto cambia in base al servizio) e gestire in modo semplice l’invio dei dati. Visto che è possibile inviare file e che se questi sono multipli vanno inviati come .zip andrà creata una funzione che faccia la trasformazione dei file multipli in un singolo file di questo tipo.

Creiamo quindi la classe WatsonAPI come sottoclasse di Xojo.Net.HTTPSocket. Come abbiamo visto per la generazione del PDF creiamo la classe in modo da poter essere richiamata in modo autonomo (essendo fondamentalmente asincrona dobbiamo permettere di effettuare anche chiamate diverse) per cui creiamo, ad esempio, un dizionario condiviso, che manterrà in vita gli oggetti fintanto che lavorano e poi li elimina una volta terminato il loro compito.

Definiamo quindi una delegate che avrà come argomento la risposta (positiva, negativa o errore) che avrà come firma un argomento di tipo Xojo.Core.Dictionary

WatsonReplyFunction(d as Xojo.Core.Dictionary)

Definiamo una proprietà private che rappresenta la funzione da richiamare, oltre a id per avere un identificativo dell’oggetto nel dizionario condiviso:

Private Property callback as WatsonReplyFunction

Il costruttore (protetto perché in realtà saranno le sottoclassi a chiamarlo) sarà del tipo:

Protected Sub Constructor( cb as WatsonAPI.WatsonReplyFunction)
//Registro la callback
callback=cb
Super.Constructor
register Me
End Sub

Dove register è una funzione condivisa privata che assegna l’identificativo all’oggetto e salva la coppia identificativo, oggetto nel dizionario condiviso. A questa funzione corrisponde anche deRegister che serve ad eliminare l’oggetto con l’identificativo assegnato.

La scelta di rispondere con un dizionario ci da la libertà di gestire a questo livello la risposta ed eventualmente rimandare l’analisi specifica alle sottoclassi o agli oggetti che utilizzeranno il risultato. Facciamo in modo che il dizionario abbia almeno 3 valori: success (booleano ad indicare se tutto è andato a buon fine o meno), status (testo ad indicare il valore dell’HTTPStatus ricevuto) e result (testo o dizionario che contiene il risultato dell’operazione).

Implementiamo gli eventi:

Sub Error(err as RuntimeException) Handles Error
  //Tutte le risposte avranno la stessa struttura
  //In caso di errore devo rispondere in modo analogo ad una risposta corretta
  Dim d As New Xojo.Core.Dictionary
  d.Value("success")=False
  d.Value("status")="0"
  d.Value("result")=err.Reason
  //Cancello l'oggetto dal dictionary
  deRegister(Me)
  //restituisco la risposta
  callback.Invoke(d)
End Sub
 
Sub PageReceived(URL as Text, HTTPStatus as Integer, Content as xojo.Core.MemoryBlock) Handles PageReceived
  #Pragma Unused url
 
  //Interpreto la risposta
  Dim d As Xojo.Core.Dictionary
  Dim t As Text
  Try
    t=xojo.core.TextEncoding.UTF8.ConvertDataToText(Content)
  Catch
    t=""
  End Try
  If Not t.Empty Then
    Try
      d=xojo.Data.ParseJSON(t)
    Catch
      d=Nil
    End Try
  End If
  Dim reply As New Xojo.Core.Dictionary
  reply.Value("success")=HTTPStatus=200 And d<>Nil
  reply.Value("status")=HTTPStatus
  If d=Nil Then
    reply.Value("result")=t
  Else
    reply.Value("result")=d
  End If
  //Cancello l'oggetto dal dictionary
  deRegister(Me)
  //restituisco la risposta
  callback.Invoke(reply)
End Sub

Creiamo a questo punto la sottoclasse di WatsonAPI per la classificazione: WatsonVisualRecognition

Per la classificazione delle immagini possiamo utilizzare uno o più dei nostri classificatori e/o quello di default o quelli in beta (attualmente Food, per il cibo, o Explicit, per le immagini esplicite)
Quindi definiamo le costanti relative a questi classificatori

Public Const IBMDefault as Text = default
Public Const IBMExplicit as Text = explicit
Public Const IBMFood as Text = food

Aggiungiamo le costante relative al servizio

//La versione corrente del servizio
Private Const version as Text = 2016-05-20
 
//L'indirizzo in realtà dipende dalle impostazioni dell'utente
Private Const kBaseUrl as Text = https://gateway.watsonplatform.net/visual-recognition/api/v3/
 
//La chiave di utilizzo del servizio
Private Const keyVision as Text = •••••••

Definiamo ora un metodo pubblico per analizzare un file immagine present sul web:

Public Shared Sub classifyImage(cb as WastonAPI.WatsonReplyFunction, imageUrl as Text, threshold as single=0.5, paramArray classifiers as Text)
  //Il metodo richiede un metodo da richiamare per restituire i risultati,
  // l'indirizzo dell'immagine da analizzare
  // il valore minimo da considerare per il riconoscimento
  // una lista di classificatori da utilizzare
 
  //Creiamo l'istanza collegandola alla callback
  Dim w As New WatsonVisualRecognition(cb)
 
  //threshold è il valore minimo accettabile per la classificazione
  //  deve essere compreso tra 0 e 1
  If threshold<0.0 Then threshold=0.0 If threshold>1.0 Then threshold=1.0
 
  //Per i classificatori posso usare sia quelli forniti che i miei
  //Devo indicare se e quali uso per cui analizziamo quelli
  //presenti nel parametro
  Dim useIBM As Boolean
  Dim usePersonal As Boolean
  Dim m() As Text
  For i As Integer=0 To classifiers.ubound
    Select Case classifiers(i)
    Case IBMDefault
      useIBM=True
    Case IBMExplicit, IBMFood
      useIBM=True
      //Questi classificatori sono solo in inglese 
      w.RequestHeader("Accept-Language")="en"
    Else
      usePersonal=True
    End Select
    If m.IndexOf(classifiers(i))=-1 Then m.Append classifiers(i)
  Next
  Dim classifier_ids As Text=Text.Join(m, ",")
 
  //Lista della tipologia dei classificatori utilizzati
  Redim m(-1)
  If useIBM Then m.Append "IBM"
  If usePersonal Then m.Append "me"
  Dim owners As Text=Text.Join(m, ",")
 
  //Creo l'URL da richiamare
  Dim url As Text=kBaseUrl+"classify"
 
  //Creo la lista degli argomenti
  Dim args() As Text
  args.Append "api_key="+keyVision
  args.Append w.getReleaseArg
  args.Append "url="+imageUrl
  If Not owners.Empty Then args.Append "owners="+owners
  If Not classifier_ids.Empty Then args.Append "classifier_ids="+classifier_ids
  If threshold>0 Then args.Append "threshold="+threshold.ToText
  Dim parametri As Text=Text.Join(args, "&")
 
  w.send "GET", url+If(parametri.Empty, "", "?"+parametri)  
End Sub

Ora possiamo richiedere la classificazione di una immagine:
Ad esempio possiamo mettere in una Window un pulsante con, nell’evento Action, il codice:

WatsonVisualRecognition.classifyImage(WeakAddressOf analyzeResponse, "https://watson-developer-cloud.github.io/doc-tutorial-downloads/visual-recognition/fruitbowl.jpg", .3)

Dove analyzeResponse è un metodo della Window che traduce il Dictionary in qualcosa di utile (azioni su un db, elenco testuale o semplicemente mostra il risultato come testo).

Partendo da questo semplice metodo è possibile creare tutti gli altri (aggiungendo un po di funzioni di utilità alla classe base WatsonAPI).

 

Nei prossimi articoli vedremo altre funzionalità e come implementarle.

Ad esempio è possibile ottenere il riconoscimento delle informazioni di base dei visi e visualizzare le informazioni

O aggiornare in pochi minuti un database di immagini con le classificazioni per poter poi ritrovare le immagini di una certa tipologia

Creare i propri classificatori

Un aspetto non trascurabile di questa soluzione è che partendo da questo oggetto è semplice creare un’applicazione per generare, aggiornare, verificare un proprio classificatore che sia specifico agli obbiettivi della nostra soluzione.

Certamente è vero che è possibile farlo per mezzo dell’interfaccia Web ma poter avere dei feedback sulle immagini è decisamente più semplice e gestibile sul desktop che in una applicazione web. Inoltre possiamo sempre aggiungere un ulteriore livello di intelligenza che può aiutarci a creare il classificatore con le immagini più adatte a farlo funzionare correttamente.

Conclusioni

I servizi API di Watson permettono di dotare le proprie applicazioni di alcune caratteristiche di intelligenza artificiale, e la semplicità delle classi necessarie per farlo dimostra la notevole versatilità di Xojo.

Il prezzo, non nel senso economico (per quello c’è il listino IBM) è nel tempo di elaborazione, non proprio istantaneo. Ma questo è dovuto in enorme parte al traffico di rete; in genere per l’invio del dato e la ricezione della risposta, a parte nel caso dell’addestramento del classificatore dove si può rimanere anche per lungo tempo in attesa  che termini il “training”.

Una caratteristica importante del servizio è, se si sviluppa per macOS, la possibilità di scaricare il proprio classificatore in formato CoreML e quindi di poterlo utilizzare anche in modalità offline tramite il plugin di MBS CoreML.