Grafici con OpenCV
OpenCV si presta molto bene all’elaborazione di grafici provenienti da dati digitali.
In questa lezione vedremo come creare un grafico ad istogrammi a partire da un set di dati.
Elaborazione dei dati
Come esempio useremo una lista di voti, su scala decimale, proveniente da un CSV, come questo:
Nome,Voto
Alessandro,6
Beatrice,5
Carlo,7
Davide,6
Elena,4
Francesco,6
Giulia,9
Luca,6
Martina,5
Nicola,8
Olivia,8Trasformare il CSV in un array di struct, seguendo questa guida. Alla fine otterremo un array di voti (rappresentati da una struct Vote).
Obiettivo dell’elaborazione è quello di mostrare in una diagramma ad istogrammi la distribuzione dei voti (ovvero quanti 3, quanti 4, quanti 5, ecc. ci sono).
Quindi prima di tutto bisogna calcolare la distribuzione dei voti:
void calc_distribution(Vote votes[], int len, int distribution[11]) {
for (int i=0; i<len; i++) {
distribution[votes[i].vote]++;
}
for (int i=0; i<11; i++) {
cout << i << ": " << distribution[i] << endl;
}
}che darà il seguente output di esempio:
0: 0
1: 0
2: 1
3: 1
4: 3
5: 4
6: 8
7: 4
8: 3
9: 1
10: 1Questa è la base dati per la rappresentazione grafica.
Il risultato che vogliamo ottenere è questo:

Creazione grafico
Inizializziamo il canvas:
int width = 800;
int height = 400;
Mat canvas(height, width, CV_8UC3, Scalar(255, 255, 255));width ed height possono essere variate a piacere.
Definiamo poi la linea base del grafico:
line(canvas, Point(0, height*0.9), Point(width, height*0.9), Scalar(0,0,0), 2);A questo punto definiamo alcune variabili fondamentali:
- w_slot: larghezza di ciascun slot orizzontale in cui dividiamo il grafico (sono 11 valori possibili, quindi sarà 1/11 della width);
- b_width: la larghezza del singolo istogramma, che qui fissiamo all’80% dello slot;
- max: indica il valore massimo tra i valori possibili, cioè la distribuzione massima di studenti per singolo voto;
- h_unit: l’altezza unitaria dell’istogramma, che andrà moltiplicata per il numero degli studenti per calcolare l’altezza del singolo istogramma;
- offset_x: siccome useremo un ciclo, ci serve sapere l’offset orizzontale da cui disegnare l’istogramma attuale ad ogni iterazione.
In codice:
int w_slot = width/11;
int b_width = w_slot * 0.8;
int max = 0;
for (int i=0; i<11; i++) {
max = max < distribution[i] ? distribution[i] : max;
}
int h_unit = height*0.9 / max;
int offset_x = 0;A questo punto entriamo nel ciclo principale, dove:
- inseriamo la label sotto la linea base;
- calcoliamo l’altezza del singolo istogramma e la posizione y (offset_y) da cui disegnarlo;
- disegnamo l’istogramma;
- aggiorniamo l’offset_x
for (int i=0; i<11; i++) {
char label[3];
sprintf(label, "%d", i);
putText(canvas, label, Point(offset_x+w_slot/3, height-h_unit/3),
FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0,0,0), 2);
int b_height = h_unit * distribution[i];
int offset_y = height*0.9 - b_height;
rectangle(canvas, Point(offset_x, offset_y), Point(offset_x+b_width, offset_y+b_height), Scalar(255, 0, 0), -1);
offset_x += w_slot;
}A questo punto è sufficiente mostrare il canvas:
imshow("Istogramma distribuzione", canvas);
waitKey(0);Conclusioni
La rappresentazione grafica dei dati è uno degli obiettivi più importanti nei progetti di analisi dati. Questo significa non solo saper elaborare e memorizzare dati da fonti esterne, ma anche rappresentarli, qui con la libreria OpenCV.
Per realizzare grafici di altro tipo (per punti, a istogramma orizzontale, a torta) si lascia alle esercitazioni.
