Realizziamo una Tela Virtuale con OpenCV per Python

In questo articolo andremo ad utilizzare la libreria OpenCV in Python per realizzare un progetto che chiameremo "Tela virtuale". Tale applicazione consente di disegnare, virtualmente, sullo schermo del nostro computer utilizzando soltanto una webcam ed un pennarello. In realtà, invece del pennarello, può essere utilizzato qualsiasi oggetto di colore uniforme e che si distingua dallo sfondo. Questo perché l'applicazione sfrutta la tecnica del rilevamento del contorno basata su una maschera dell'oggetto utilizzato. Grazie ai dati in tempo reale della webcam, questa applicazione è in grado di tracciare un oggetto specifico, consentendo all'utente di disegnare sullo schermo nella posizione tracciata.

Introduzione

OpenCV (Open Source Computer Vision Library) è una libreria software open source per la visione artificiale e l'apprendimento automatico. OpenCV è stata progettata per essere multipiattaforma. La libreria è stata scritta in C rendendola portabile su quasi tutti i sistemi commerciali. Per la maggior parte, i nuovi algoritmi OpenCV sono ora sviluppati in C ++. Sono stati sviluppati anche wrapper per linguaggi come Python e Java per incoraggiarne l'adozione da parte di un pubblico sempre più ampio. OpenCV funziona sia su sistemi operativi desktop (Windows, Linux, MacOS, FreeBSD, OpenBSD) che su dispositivi mobili (Android, Maemo, iOS). In questo nostro progetto useremo il linguaggio Python e quindi la libreria OpenCV corrispondente. La libreria presenta più di 2500 algoritmi ottimizzati, sia per la visione artificiale che per l'apprendimento automatico. Questi algoritmi possono essere utilizzati per rilevare e riconoscere volti, identificare oggetti, classificare azioni umane nei video, tracciare i movimenti della telecamera, tracciare oggetti in movimento, estrarre modelli 3D di oggetti, unire immagini insieme per produrre un'immagine ad alta risoluzione di un'intera scena, trovare immagini simili in un database di immagini, rimuovere gli occhi rossi dalle immagini scattate con il flash, seguire i movimenti degli occhi, riconoscere lo scenario e stabilire marcatori per sovrapporlo alla realtà aumentata, etc.

Il progetto

Sebbene si tratti di un progetto non particolarmente complicato, prima di iniziare con la descrizione, vogliamo consigliare a chi fosse a digiuno degli argomenti che affronteremo nell'articolo alcune letture di supporto. In particolare:

Dopo questa premessa possiamo tuffarci nella descrizione del progetto. Le fasi principali per la realizzazione dell'applicazione sono le seguenti:

  • Fase 1 - Trovare l'intervallo di valori nello spazio di colore HSV relativo all'oggetto usato come marker (il pennarello nel nostro caso).
  • Fase 2 - Creare una maschera del marker utilizzando la gamma di valori nello spazio di colore HSV trovati nella Fase 1.
  • Fase 3 - Utilizzare il rilevamento del contorno per tracciare la posizione del marker. In poche parole, ottenere le coordinate x, y del pennarello all'interno della "tela virtuale".
  • Fase 4 - Disegnare un punto colorato alle coordinate x, y della posizione trovata.

Oltre ad implementare queste quattro fasi, nel nostro codice abbiamo inserito alcune funzionalità aggiuntive come la possibilità per l'utente di scegliere la forma, la dimensione ed il colore del pennello virtuale, grazie ad una finestra ospitante dei cursori di selezione.

Passiamo ora alla descrizione dell'implementazione delle quattro fasi principali.

Fase 1

Il tracciamento video è il processo di localizzazione di un oggetto in movimento nel tempo utilizzando una telecamera. Ha una varietà di usi, alcuni dei quali sono: interazione uomo-computer, sicurezza e sorveglianza, comunicazione e compressione video, realtà aumentata, controllo del traffico, imaging medico e montaggio video. Nel nostro progetto dobbiamo tracciare la posizione di un marker (pennarello). Per farlo cercheremo di filtrare il marker in uno spazio di colore appropriato in modo da separarlo da tutto ciò che si trova nella scena. Occorre cioè trovare un intervallo ristretto di valori in cui è compreso il colore del nostro marker.

Figura 1: Operando sui cursori nella finestra "Track", l'immagine sulla destra viene filtrata nello spazio di colore HSV estraendo così solo i pixel relativi al marker di interesse

Dal momento che stiamo cercando di rilevare il colore, convertiremo la nostra immagine dal formato RGB (o BGR in OpenCV) al formato HSV (tonalità, saturazione, valore) poiché è molto più facile manipolare i colori in tale modello. Lo script presente al seguente LINK ti consentirà di utilizzare i vari cursori presenti nella finestra "Track" per regolare i canali min e max relativi a tonalità (H), saturazione (S) e valore (V) dell'immagine. Si tratta di giocare con i cursori nella finestra affinché solo il marker (pennarello nel nostro caso) sia visibile, lasciando il resto dello schermo nero. In Figura 1 abbiamo riportato l'esempio del pennarello. Il marker scelto è un pennarello con il tappo verde e il corpo di altri colori. Quello che ci interessa è mettere in evidenza il tappo verde, poiché all'interno della scena quel colore non è presente e quindi risulta più facile da tracciare. I valori trovati ci serviranno nella Fase 2 per la creazione della maschera. I valori possono essere pensati come due array: uno contenente i valori dei cursori con _min [H_min, S_min, V_min], e l'altro contenente i valori dei cursori con _max [H_max, S_max, V_max].

Fase 2

Una volta trovati i valori che evidenziano il nostro marker, oscurando il resto della scena, possono essere utilizzati per creare la maschera. Per mezzo della funzione cv.inRange(img, bordoinf, bordosup) possiamo controllare se gli elementi di un'immagine (img) si trovano compresi tra gli elementi di due array (bordoinf, bordosup). In parole semplici, quello che faremo è convertire img nello spazio di colore HSV. Quindi filtreremo l'immagine per estrapolare solo i pixel il cui valore HSV rientra tra i valori espressi da bordoinf e bordosup. La funzione fornirà in uscita un'immagine delle stesse dimensioni di img ma con valore 1 nelle posizioni dei pixel estrapolati e 0 altrimenti. Nel nostro caso img è dato dai fotogrammi catturati dalla webcam e convertiti in formato HSV, e gli array di riferimento sono i valori trovati nella Fase 1, ovvero [H_min, S_min, V_min] e [H_max, S_max, V_max].

Fase 3

L'intera applicazione si basa fondamentalmente sul rilevamento dei contorni. Una volta ottenuta la maschera binaria del nostro marker, possiamo utilizzare il rilevamento del contorno per trovare la posizione del marker nella scena. Tracciato il marker, possiamo localizzare il punto effettivo da cui partirà la pittura sulla tela virtuale. La Figura 2 dimostra il tracciamento del marker tramite il rettangolo verde intorno al tappo del pennarello, e la valutazione della punta del pennello virtuale con il punto blu.

Figura 2: Dopo aver ottenuto la maschera è possibile tracciare il movimento del marker nella scena

Queste operazioni sono eseguite dalla funzione getContorno() che verrà descritta più nel dettaglio proseguendo nell'articolo.

Fase 4

Una volta che il marker è stato tracciato si può cominciare a dipingere, grazie alla funzione drawOC(). Anche questa funzione verrà analizzata più nel dettaglio durante la descrizione del codice. Per rendere l'applicazione più divertente, sono state inserite delle funzioni che permettono di selezionare il colore, la forma e la dimensione del pennello virtuale attraverso una barra selezionatrice (Figura 3).

Figura 3: La finestra "Palette" permette all'utente di selezionare il colore, la forma e la dimensione del pennello virtuale

Il codice

Passiamo quindi all'analisi del codice in Python per implementare l'applicazione. Analizzeremo il codice suddividendolo in piccole porzioni.

import cv2 as cv
import numpy as np

Come al solito, per prima cosa importiamo le librerie che utilizzeremo nello script. In particolare cv2 è il nome della libreria OpenCV per Python mentre numpy è la libreria Python che ci permette di manipolare array e matrici.

L=960
AR=4/3
H=int(L/AR)
cap = cv.VideoCapture(0)
cap.set(3,L) #id=3 larghezza
cap.set(4,H) #id=4 altezza 
cap.set(10,150) #id=10 luminosità

myPs = []

Nella seconda porzione di codice impostiamo alcuni parametri di configurazione come la larghezza (L), il rapporto d'aspetto (AR) e l'altezza (H) della tela virtuale su cui vogliamo dipingere. Adesso dobbiamo catturare lo streaming live con la webcam. OpenCV fornisce un'interfaccia molto semplice per farlo. Per acquisire un video, è necessario creare un oggetto VideoCapture(). Il suo argomento può essere l'indice del dispositivo o il nome di un file video. L'indice di un dispositivo è solo il numero per specificare quale telecamera selezionare. Passando semplicemente 0 o -1, richiediamo la webcam integrata. Per selezionare altre telecamere basta passare il valore 1, 2 e così via. Una volta creata un'istanza che abbiamo denominato cap, possiamo utilizzare il metodo set() per impostare alcuni parametri come larghezza, altezza e luminosità. Ogni parametro viene impostato, indicando il relativo identificativo (id) e il valore. Passiamo quindi a definire alcune funzioni che verranno poi chiamate nel ciclo principale.

###Colore dello spot###
def on_trackbar():
 B = cv.getTrackbarPos("Blu", "Palette")
 V = cv.getTrackbarPos("Verde", "Palette")
 R = cv.getTrackbarPos("Rosso", "Palette")
 spotColore =[B, V, R]
 return spotColore

Questa funzione serve per ottenere il colore scelto dall'utente attraverso la barra selezionatrice. Ogni cursore rappresenta uno dei tre colori primari, combinando insieme diverse quantità di rosso, verde e blu è possibile ottenere una grande varietà di colori.

###Dimensione dello spot###
def on_trackbar2():
 spotSize = cv.getTrackbarPos("Dimens.", "Palette")
 return spotSize
###Forma dello spot###
def on_trackbar3():
 spotShape= cv.getTrackbarPos("Forma", "Palette")
 return spotShape

Queste due funzioni servono per ottenere la dimensione della punta (spot) del pennello virtuale e la forma, scelte dall'utente attraverso la barra selezionatrice. Esse ritornano un valore che verrà poi passato alla funzione findColor().

###Impostazioni della Barra###
cv.namedWindow("Palette")
cv.createTrackbar("Blu", "Palette" , 0, 255, on_trackbar)
cv.createTrackbar("Verde", "Palette" , 255, 255, on_trackbar)
cv.createTrackbar("Rosso", "Palette" , 0, 255, on_trackbar)
cv.createTrackbar("Dimens", "Palette" , 5, 20, on_trackbar)
cv.createTrackbar("Forma", "Palette" , 0, 1, on_trackbar)

In questo pezzo di codice avvengono le impostazioni della barra selezionatrice. Si definisce il nome della finestra namedWindow("Palette") che ospiterà i vari cursori. Vengono quindi aggiunti i selezionatori createTrackbar() relativi ai tre colori primari, alla dimensione del pennello e alla sua forma. [...]

ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 2250 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.

Scarica subito una copia gratis

6 Commenti

  1. Giuseppe Garofalo 17 Febbraio 2022
    • Giuseppe Garofalo 17 Febbraio 2022
      • Andrea Garrapa 18 Febbraio 2022
        • Giuseppe Garofalo 18 Febbraio 2022
          • Andrea Garrapa 19 Febbraio 2022
  2. Giuseppe Garofalo 20 Febbraio 2022

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend