2012-12-12 17 views
16

Sto usando un set di dati in cui sono presenti immagini in cui ogni pixel è un int unsigned di 16 bit che memorizza il valore di profondità di quel pixel in mm. Sto cercando di visualizzare questa come immagine in scala di grigi di profondità nel modo seguente:OpenCV: Come visualizzare un'immagine di profondità

cv::Mat depthImage; 
depthImage = cv::imread("coffee_mug_1_1_1_depthcrop.png", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // Read the file 
depthImage.convertTo(depthImage, CV_32F); // convert the image data to float type 
namedWindow("window"); 
float max = 0; 
for(int i = 0; i < depthImage.rows; i++){ 
    for(int j = 0; j < depthImage.cols; j++){ 
     if(depthImage.at<float>(i,j) > max){ 
      max = depthImage.at<float>(i,j); 
     } 
    } 
} 
cout << max << endl; 


float divisor = max/255.0; 
cout << divisor << endl; 
for(int i = 0; i < depthImage.rows; i++){ 
    for(int j = 0; j < depthImage.cols; j++){ 
     cout << depthImage.at<float>(i,j) << ", "; 
     max = depthImage.at<float>(i,j) /= divisor; 
     cout << depthImage.at<float>(i,j) << endl; 
    } 
} 


imshow("window", depthImage); 
waitKey(0); 

Tuttavia, è solo mostrando due colori Questo perché tutti i valori sono vicini cioè nella gamma di 150-175 + i piccoli valori che appaiono in nero (vedi sotto).

rgb image greyscale image

C'è un modo per normalizzare questi dati in modo tale che mostrerà vari livelli di grigio per evidenziare queste piccole differenze di profondità?

risposta

19

Secondo il documentation, la funzione imshow può essere utilizzato con una varietà di tipi di immagine. E 'il supporto a 16 bit le immagini senza segno, in modo da poter visualizzare la propria immagine utilizzando

cv::Mat map = cv::imread("image", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH); 
cv::imshow("window", map); 

In questo caso, il campo di valori immagine viene mappata dalla gamma [0, 255 * 256] alla gamma [0, 255] .

Se l'immagine contiene solo valori nella parte bassa di questo intervallo, si osserverà un'immagine oscura. Se si desidera utilizzare il range di display (da nero a bianco), si dovrebbe regolare l'immagine per coprire la gamma dinamica prevista, un modo per farlo è

double min; 
double max; 
cv::minMaxIdx(map, &min, &max); 
cv::Mat adjMap; 
cv::convertScaleAbs(map, adjMap, 255/max); 
cv::imshow("Out", adjMap); 
+0

Non capisco perché ridimensionarlo di 255/max (sam come me che divide ogni elemento di max/255) lo farà usare l'intera gamma. Voglio dire, lo fa, e accetterò la risposta, ma non capisco. Cos'altro sta facendo quella funzione? – Aly

+0

Il [convertScaleAbs] (http: //docs.opencv.La funzione org/modules/core/doc/operations_on_arrays.html? highlight = convertscaleabs # cv.ConvertScaleAbs) esegue 3 operazioni: ridimensiona, calcola il valore assoluto e converti in un tipo a 8 bit senza segno. Ecco perché viene utilizzato il fattore 255/max per l'intero intervallo ([0-255] per unsigned 8 bit). Inoltre, come menzionato da @sammy, la gamma dinamica dell'immagine regolata viene utilizzata meglio tenendo conto del valore minimo dei dati. – samota

2

Se l'ingresso imshow ha un tipo di dati in virgola mobile, la funzione presuppone che i valori dei pixel siano in [0; 1] gamma. Come risultato, tutti i valori superiori a 1 vengono visualizzati in bianco.

Quindi non c'è bisogno di dividere il divisor da 255.

+0

Dopo queste righe: 'depthImage = cv :: imread ("coffee_mug_1_1_1_depthcrop.png", CV_LOAD_IMAGE_ANY PROFONDITÀ | CV_LOAD_IMAGE_ANYCOLOR); depthImage.convertTo (depthImage, CV_32F); 'Se stampo i valori sono compresi nell'intervallo [0,1161], quindi il mio divisore è 1161/255 per ottenere tutti i valori nell'intervallo [0,255], forse se poi convertirò è CV_8UC1? – Aly

+0

Ah sì, questo ha funzionato. Inoltre se utilizzo l'istogramma di equalizzazione offre una rappresentazione molto migliore – Aly

+0

Innanzitutto, la funzione 'imread' legge l'immagine preservando i valori originali, quindi 1161 è Ok per un'immagine a 16 bit per pixel. Secondo, il metodo 'convertTo' non scala i valori per impostazione predefinita, cambia solo il tipo e satura. Quindi questo spiega perché i valori stampati sono così grandi. –

17

Aggiungendo a samg' risposta, è possibile espandere ancora di più la gamma della tua immagine visualizzata.

double min; 
double max; 
cv::minMaxIdx(map, &min, &max); 
cv::Mat adjMap; 
// expand your range to 0..255. Similar to histEq(); 
map.convertTo(adjMap,CV_8UC1, 255/(max-min), -min); 

// this is great. It converts your grayscale image into a tone-mapped one, 
// much more pleasing for the eye 
// function is found in contrib module, so include contrib.hpp 
// and link accordingly 
cv::Mat falseColorsMap; 
applyColorMap(adjMap, falseColorsMap, cv::COLORMAP_AUTUMN); 

cv::imshow("Out", falseColorsMap); 

Il risultato dovrebbe essere qualcosa di simile a quello qui sotto

enter image description here

+1

è possibile che openCV emetta una mappa colori con la scala, come mostrato a destra? –

+2

No. Questa è una trama di Matlab. – Sam

+0

Saluti Sammy, apprezzare la risposta rapida –

2

Aggiunta di Sammy risposta, se il colore gamma originale è [-min, max] e si desidera eseguire equalizzazione e visualizzare il colore di profondità, il codice dovrebbe essere come di seguito:

double min; 
double max; 
cv::minMaxIdx(map, &min, &max); 
cv::Mat adjMap; 
// Histogram Equalization 
float scale = 255/(max-min); 
map.convertTo(adjMap,CV_8UC1, scale, -min*scale); 

// this is great. It converts your grayscale image into a tone-mapped one, 
// much more pleasing for the eye 
// function is found in contrib module, so include contrib.hpp 
// and link accordingly 
cv::Mat falseColorsMap; 
applyColorMap(adjMap, falseColorsMap, cv::COLORMAP_AUTUMN); 

cv::imshow("Out", falseColorsMap); 
Problemi correlati