PYTHON + OPENCV + DEEP NEURAL NETWORKS = OBJECT RECOGNITION

In questo post tratteremo un argomento su cui si sta facendo molta luce ultimamente, grazie alla potenza di calcolo delle CPU/GPU e in generale dei calcolatori nella fascia di mercato consumer/prosumer. Parleremo di Object Recognition su immagini (ma il discorso si può tranquillamente applicare ad un flusso video, con un po’ di accorgimenti anche in tempo reale).

Vi sono più metodi per effettuare il riconoscimento di oggetti in una scena, noi ci concentreremo sull’ultilizzo delle reti neurali, in particolare delle DNN (Deep Neural Network, ovvero Reti Neurali Profonde, o Dense).

Nello specifico, i principali metodi di Object Recognition che utilizzano DNN sono 3:

  1. Faster R-CNNs
  2. YOLO (You Only Look Once)
  3. SSDs (Single Shot Detectors)

Le reti R-CNN (Convoluzionali) probabilmente costituiscono il metodo più “primordiale” mai esistito per l’Object Recognition, ma la learning curve può essere piuttosto ostica per chi si avvicina a questo mondo, soprattutto per quanto rigurda il training del modello. Inoltre, anche lavorando bene ed essendo scrupolosi, le performance dell’algoritmo possono essere piuttosto deludenti (difficilmente si superano i 7 FPS).

YOLO è di gran lunga superiore in termine di performances, può arrivare anche a 155 FPS utilizzando GPU evolute, il suo problema però è l’accuratezza, che lascia molto a desiderare.

SSDs, che è un metodo sviluppato originariamente da Google, fa da anello di congiunzione tra R-CNNs e YOLO, inoltre costituisce un ottimo “entry point” per chi si avvicina al mondo del machine/deep learning. Le sue performances variano dai 22 ai 46 FPS.

Le architetture convenzionali, come VGG o ResNet utilizzano delle pipelines molto “pesanti”, si parla dell’ordine dei 200-500Mb, che non è proprio un vero affare in termini di ottimizzazione (e di performances)

MobileNets (spin-off Google) ci consente invece di semplificare l’ordine delle matrici di analisi, al fine di ottimizzare le performances, utilissimo sui dispositivi mobili dove l’ottimizzazione delle risorse è una keyword sacrosanta (da cui “Mobile”).

MobileNets e la sua pipeline prevedono:

  • Una matrice di convoluzione densa 3×3
  • Un vettore di convoluzione 1×1 (magic happens here)

Questo sacrifica sicuramente l’accuratezza del nostro sistema, che però diventa appannaggio dell’efficienza della nostra infrastruttura, specie su devices con una modesta potenza di calcolo.

UTILIZZARE MOBILENET SSD + MODULO DNN DI OPENCV

Dopo questo “bunch of theory”, passiamo al sodo: utilizzeremo Python, OpenCV ed il suo modulo dnn per creare il nostro Object Detector. In questo articolo utilizzeremo il nostro model (OpenCV supporta modelli pre-trained con Caffe, TensorFlow e PyTorch al momento) di cui il pre-training esula dallo scopo di questo articolo (niente paura: more to come!)

[pastacode lang="python" manual="%23%20importo%20i%20packages%20necessari%0Aimport%20numpy%20as%20np%0Aimport%20argparse%0Aimport%20cv2%0A%20%0A%23%20costruisco%20l'argument-parsing%0Aap%20%3D%20argparse.ArgumentParser()%0Aap.add_argument(%22-i%22%2C%20%22--image%22%2C%20required%3DTrue%2C%0A%09help%3D%22percorso%20immagine%22)%0Aap.add_argument(%22-p%22%2C%20%22--prototxt%22%2C%20required%3DTrue%2C%0A%09help%3D%22percorso%20del%20file%20prototxt%20del%20modello%20Caffe%22)%0Aap.add_argument(%22-m%22%2C%20%22--model%22%2C%20required%3DTrue%2C%0A%09help%3D%22percorso%20del%20modello%20Caffe%20pre-trained%22)%0Aap.add_argument(%22-c%22%2C%20%22--confidence%22%2C%20type%3Dfloat%2C%20default%3D0.2%2C%0A%09help%3D%22soglia%20di%20tolleranza%20per%20le%20predizioni%22)%0Aargs%20%3D%20vars(ap.parse_args())%0A" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Nulla di che, ci preoccupiamo di effettuare un paio di import essenziali al nostro scopo e di utilizzare argparse al fine di dotare il nostro script della possibilità di accettare parametri. Un parametro interessante è la “confidence threshold (0.1 ~ 1.0)”, che indica la soglia sotto la quale non terremo conto della predizione effettuata per quel particolare oggetto. in pratica inserendo 0.99 appariranno solo le predizioni degli oggetti delle quali il sistema sarà davvero sicurissimo.

[pastacode lang="python" manual="%23%20inizializzo%20la%20lista%20delle%20classi%2C%20modello%20di%20esempio%20MobileNet%20SSD%0A%23%20pre-trained%20da%20Google%0ACLASSES%20%3D%20%5B%22background%22%2C%20%22aeroplane%22%2C%20%22bicycle%22%2C%20%22bird%22%2C%20%22boat%22%2C%0A%09%22bottle%22%2C%20%22bus%22%2C%20%22car%22%2C%20%22cat%22%2C%20%22chair%22%2C%20%22cow%22%2C%20%22diningtable%22%2C%0A%09%22dog%22%2C%20%22horse%22%2C%20%22motorbike%22%2C%20%22person%22%2C%20%22pottedplant%22%2C%20%22sheep%22%2C%0A%09%22sofa%22%2C%20%22train%22%2C%20%22tvmonitor%22%5D%0ACOLORS%20%3D%20np.random.uniform(0%2C%20255%2C%20size%3D(len(CLASSES)%2C%203))%0A" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Costruisco lista delle Classi (appartenenti al pre-training effettuato da Google, per velocità di dimostrazione) e dei Colori (apparirà un box colorato che attornerà ogni oggetto detectato). Il codice utilizzato è davvero triviale e penso non necessiti di ulteriori commenti.

[pastacode lang="python" manual="%23%20carichiamo%20il%20modello%20dal%20disco%0Aprint(%22%5BINFO%5D%20carico%20il%20modello...%22)%0Anet%20%3D%20cv2.dnn.readNetFromCaffe(args%5B%22prototxt%22%5D%2C%20args%5B%22model%22%5D)%0A" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Carichiamo il nostro modello dal disco

[pastacode lang="python" manual="%23%20carichiamo%20la%20nostra%20immagine%20e%20creiamo%20un%20blob%20per%20la%20nostra%20dnn%0A%23%20effettuiamo%20un%20resize%20300x300%20e%20normalizziamo%0Aimage%20%3D%20cv2.imread(args%5B%22image%22%5D)%0A(h%2C%20w)%20%3D%20image.shape%5B%3A2%5D%0Ablob%20%3D%20cv2.dnn.blobFromImage(cv2.resize(image%2C%20(300%2C%20300))%2C%200.007843%2C%0A%09(300%2C%20300)%2C%20127.5)%0A" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Ci occupiamo di caricare la nostra immagine e di effettuare un Resize (300 * 300) seguito da una normalizzazione, al fine di rendere omogeneo il nostro input con quello che si aspetta la nostra DNN.

A questo punto siamo pronti per effettuare il forward del nostro blob nella rete neurale, al fine di ottenere le predizioni desiderate. Questo passo potrebbe richiedere un po’ di tempo, a seconda della potenza di calcolo dell’elaboratore su cui si esegue lo script.

[pastacode lang="python" manual="print(%22%5BINFO%5D%20eseguo%20le%20predizioni...%22)%0Anet.setInput(blob)%0Adetections%20%3D%20net.forward()%0A" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Ora non ci resta che iterare nell’array delle predizioni al fine di determinare quali oggettisono presenti nella scena e dove sono ubicati.

[pastacode lang="python" manual="%23%20itero%0Afor%20i%20in%20np.arange(0%2C%20detections.shape%5B2%5D)%3A%0A%09%23%20estraggo%20la%20confidence%20della%20predizione%20i-esima%0A%09confidence%20%3D%20detections%5B0%2C%200%2C%20i%2C%202%5D%0A%20%0A%09%23%20filtro%2C%20accettando%20la%20predizione%20se%20%C3%A8%20maggiore%20%0A%09%23%20della%20confidence%20threshold%20in%20input%0A%09if%20confidence%20%3E%20args%5B%22confidence%22%5D%3A%0A%09%09%23%20estraggo%20l'indice%20della%20classe%20dalla%20lista%20delle%20predizioni%0A%09%09%23%20in%20pi%C3%B9%20ho%20cura%20di%20salvare%20le%20coordinate%20(x%2Cy)%0A%09%09%23%20per%20disegnare%20un%20box%20attorno%20all'oggetto%0A%09%09idx%20%3D%20int(detections%5B0%2C%200%2C%20i%2C%201%5D)%0A%09%09box%20%3D%20detections%5B0%2C%200%2C%20i%2C%203%3A7%5D%20*%20np.array(%5Bw%2C%20h%2C%20w%2C%20h%5D)%0A%09%09(startX%2C%20startY%2C%20endX%2C%20endY)%20%3D%20box.astype(%22int%22)%0A%20%0A%09%09%23%20stampo%20la%20predizione%20nell'output%20del%20terminale%0A%09%09%23%20e%20disegno%20il%20box%20attorno%20all'oggetto%0A%09%09label%20%3D%20%22%7B%7D%3A%20%7B%3A.2f%7D%25%22.format(CLASSES%5Bidx%5D%2C%20confidence%20*%20100)%0A%09%09print(%22%5BINFO%5D%20%7B%7D%22.format(label))%0A%09%09cv2.rectangle(image%2C%20(startX%2C%20startY)%2C%20(endX%2C%20endY)%2C%0A%09%09%09COLORS%5Bidx%5D%2C%202)%0A%09%09y%20%3D%20startY%20-%2015%20if%20startY%20-%2015%20%3E%2015%20else%20startY%20%2B%2015%0A%09%09cv2.putText(image%2C%20label%2C%20(startX%2C%20y)%2C%0A%09%09%09cv2.FONT_HERSHEY_SIMPLEX%2C%200.5%2C%20COLORS%5Bidx%5D%2C%202)" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

A questo punto, prompto in output l’immagine, provvista di box di predizione attorno.

[pastacode lang="python" manual="cv2.imshow(%22Output%22%2C%20image)%0Acv2.waitKey(0)" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Per eseguire lo script:

[pastacode lang="python" manual="%24%20python%20object_detection.py%20%5C%0A%09--prototxt%20MobileNetSSD_deploy.prototxt.txt%20%5C%0A%09--model%20MobileNetSSD_deploy.caffemodel%20--image%20images%2Fexample_01.jpg%20%0A%5BINFO%5D%20carico%20immagine...%0A%5BINFO%5D%20carico%20il%20modello...%0A%5BINFO%5D%20effettuo%20le%20predizioni...%0A%5BINFO%5D%20person%3A%2099.82%25%0A%5BINFO%5D%20bottle%3A%2090.85%25%0A" message="Python+OpenCV+DNN" highlight="" provider="manual"/]

Happy Coding!

PYTHON + OPENCV + DEEP NEURAL NETWORKS = OBJECT RECOGNITION ultima modifica: 2017-11-27T16:19:13+00:00 da Mr Bildo
PYTHON + OPENCV + DEEP NEURAL NETWORKS = OBJECT RECOGNITION ultima modifica: 2017-11-27T16:19:13+00:00 da Mr Bildo

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *