Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
N2:
Video-Analysis: Circle Detection
Autore:
Valerio Colamatteo
Sommario:
Descrizione dellesercitazione
Questa seconda esercitazione, come immediatamente evidente dallintestazione, evidenzia
un netto scollamento teorico/didattico dalla precedente muovendo dalle tematiche di pi diretta e
naturale argomentazione del corso di insegnamento afferente. Onde abbracciare dunque spazi di pi
ampia operativit, la stessa si sofferma su tematiche di approfondimento collaterali per la materia in
esame ma che, stante lindubbia componente ludica di cui risultano intrinsecamente portatrici, si
dimostrano comunque tali da suscitare, nei pi, vivo apprezzamento e rappresentare cos fonte di
curiosit didattica 1.
Di riflesso, dunque, stante la diversa architettura teorica di base, il taglio argomentativo caratterizzante la prima di
questo ciclo di relazioni dedicate agli approfondimenti didattici non trover, in questa sede, uguale accoglimento,
ritenendo pleonastico per le finalit della presente fornire gli approfondimenti teorici altrimenti dovuti. Ci detto, la
trattazione evolver ugualmente in maniera da potersi ritenere certamente non eccessivamente liquidatoria di alcuni
degli aspetti pi delicati per loggetto di analisi.
2
dstCn=0);
Prototipo della funzione utilizzata: double cvThreshold(const CvArr* src, CvArr* dst, double threshold,
double max_value, int threshold_type);
Tale funzione opera solo su immagini binarie di input che abbiano le cui componenti connesse siano bianche su sfondo
nero, ci ha allora indotto, previa corretto utilizzo di tale funzione, la generazione preventiva del negativo della stessa
immagine.
5
Maggiori e pi puntali riferimenti, come al solito, sono rimandati alla sezione tre della relazione o direttamente al
codice sorgente in allegato.
6
In questa prima parte si deliberatamente deciso di non fornire ulteriori e pi profondi riferimenti a quanto fatto
poich tali primi passaggi sono in parte da ritenersi frutto sia di un comune convenire di idee e proposte in aula con il
docente, sia in parte frutto delle preziose linee di indirizzamento fornite in allegato al testo dellesercitazione. Gli aspetti
ritenuti invece core dellesercitazione sono quelli immediatamente seguenti, alla cui, si spera esaustiva, argomentazione
si dedicher tutta la parte rimanente di tale lavoro.
Oggetto di intensa attivit elaborativa stata, in questa fase, lideazione di un metodo efficace di
discernimento dei contorni delle diverse forme geometriche raffigurate sulla apposita stampa
campione.
Nella successiva sezione si analizzeranno invece i risultati effettivamente ottenuti.
Le specifiche dellesercitazione richiedevano esplicitamente solo lidentificazione della figura di
forma circolare. Una volta ottenuto il tracciamento della stessa, si cercato di trovare una
metodologia unica che permettesse di identificare correttamente anche le altre figure polinomiali
della stampa campione. In merito a ci la soluzione tentata stata quella di affidare
lidentificazione della figura al geometrica al numero di vertici da essa posseduta (le immagini sulla
stampa hanno tutte un diverso numero di vertici e questo un elemento di semplificazione a mio
parere 7). Per identificare il numero di vertici si fatto della funzione approxPolyDP() 8. Essa, in
realt, risulta implementata allinterno della libreria OpenCV con finalit differenti da quelle con cui
stata invece impiegata in tale lavoro. Essa sostanzialmente si occupa di approssimare i contorni di
una immagine a quelli di una figura polinomiale secondo un margine di tolleranza prefissabile. I
contorni approssimati vengono salvati in una struttura dati vector (approx) appositamente creata.
Allora, inserendo tale funzione in un ciclo for( ) e ciclandone lazione in base al numero di
contorni individuati, si riesce a determinare il numero di contorni di volta in volta approssimati
dalla funzione semplicemente ispezionando le dimensioni di approx (approx.size( )).
Successivamente si pu procedere allidentificazione del centroide e alla stampa delle informazioni
richieste dalla traccia, cercando comunque di mantenere sempre degli elementi di differenziazione
per la figura circolare. Tale discorso verr ripreso e ultimato nelle seguenti sezioni.
Ulteriore problema a questo punto stata la caratterizzazione del centroide dei vari poligoni. A tal
proposito si sfruttata la funzione (suggerita dal testo dellesercitazione) boundingRect() per
trovare il rettangolo che meglio circoscrivesse di volta in volta i vari poligoni. La stessa funzione
restituisce un oggetto di classe Rect. possibile accedere alle informazioni specifiche di tale
oggetto attraverso gli appositi metodi boundingRect(.).x e boundingRect(.).y. Con ci
vengono, rispettivamente restituite in uscita le coordinate x e y dellestremo superiore sinistro del
rettangolo. A questo punto, attraverso i metodi boundingRect(.).windth
e
boundingRect(.).height si ricavano anche le lunghezze delle due dimensioni del rettangolo. Le
stesse allora, se divise per 2 e sommate alle coordinate dellestremo superiore sinistro del
rettangolo, consentono di determinare univocamente le coordinate del punto centrale per ogni
poligono che venga circoscritto dal rettangolo di boundingRect(.).
In caso di pi poligoni con lo stesso numero di vertici si sarebbe dovuto probabilmente implementare un meccanismo
di valutazione degli angoli interni di ogni figura, aumentando cos non di poco la complessit analitica del tutto.
8
Prototipo della funzione utilizzata : void approxPolyDP ( InputArray curve, OutputArray approxCurve, double epsilon,
bool closed );
Utilizzando una apposita funziona per la determinazione del perimetro di una curva chiusa
(quale sono considerabili in effetti i poligoni in questione). La funzione di specie la
seguente: double arcLength(InputArray curve, bool closed);
Il valore restituito da arcLength() stato poi ponderato per un fattore di riduzione <0. Il
prodotto dei due termini costituisce allora nellesercitazione il parametro 3 cercato.
Vista la preannunciata alternanza di una esercitazione a carattere prettamente teorico e una a carattere pi
specificatamente volta allimplementazione di meccanismi di inseguimento di traiettorie video, certamente si ritorner
su tali problematiche, proponendo sperabilmente, a tempo debito, nuove pi efficienti soluzioni.
char s5[20];
sprintf(s5," PENT.");
eiid::p2::Draw(out2,countours,i,s5);
}
if (approx.size() == 4){
printf("QUADRATO\n");
cv::drawContours(out2,countours,i,cv::Scalar(255,0,0),2);
char s5[20];
sprintf(s5," QUADR.");
eiid::p2::Draw(out2,countours,i,s5);
}
else{
double area = cv::contourArea(countours[i]);
cv::Rect r = cv::boundingRect(countours[i]);
int radius = r.width / 2;
return out2;
Praticamente quello che faccio semplicemente, ad ogni passo del ciclo for( ), controllare il numero
di vertici approssimati. Ci mi consente di poter gestire individualmente i vari poligoni,
richiamando una ulteriore funzione, appositamente definita, che sar commentata nel prossimo
listato. Allinterno delle varie sezioni (if( )) di codice dedicate ai singoli poligoni, si disegnano
opportunamente i contorni (drawContours() 10) e viene poi definita una stringa di caratteri da passare
alla funzione draw() che sar poi visualizzata in real-time sullo schermo nei pressi del relativo
centroide. La procedura differisce leggermente solo per il cerchio, per il quale il controllo prima se
il raggio dei due poligoni (quello del contorno originale e quello approssimato) coincidono a meno
dellerrore 3. In particolare per il calcolo dellarea si usato lapposita funzione contourArea() 11.
Infine il listato della funzione Draw() e, con esso, si si conclude anche questa seconda relazione.
pointX=cv::boundingRect(countours[i]).x;
pointY=cv::boundingRect(countours[i]).y;
sumX=alt+pointX;
sumY=alt+pointY;
cv::Point pt5;
pt5.x=sumX;
pt5.y=sumY;
if(std::strcmp(s," CERCHIO.")){
cv::circle(m,pt5,1,cv::Scalar(0,255,0),8);
sprintf(s+strlen(s),", area= %d",(int)area);
cv::putText(m,s, pt5, 2, 0.4, cv::Scalar(0,255,0), 1);
}
else {
cv::circle(m,pt5,1,cv::Scalar(255,0,0),8);
sprintf(s+strlen(s),", area= %d",(int)area);
cv::putText(m,s, pt5, 2, 0.4, cv::Scalar(255,0,0), 1);
}
}
11
Prototipo della funzione utilizzata : double contourArea( InputArray contour, bool oriented=false );
La funzione riceve in ingresso limmagine video su cui operare, il vettore dei contorni, lindice
relativo al contorno di interesse e un puntatore alla stringa da stampare a video.
Per prima cosa, allinterno di essa, mi determino le coordinate del centroide secondo le modalit gi
ispezionate nelle precedenti sezioni, e poi, a seconda della stringa ricevuta in ingresso, stampo le
informazioni richieste dallesercitazione (area della figura) in maniera particolareggiata (per colore)
unicamente se si tratta del cerchio. Tale funzione viene continuamente richiamata ad ogni avvenuta
individuazione di uno dei poligoni ricercati.