2012-12-12 12 views
16

Używam zestawu danych, w którym znajdują się obrazy, gdzie każdy piksel to 16-bitowy unsigned int przechowujący wartość głębokości tego piksela w mm. Próbuję wyobrazić to jako szarości głębi obrazu, wykonując następujące czynności:OpenCV: jak wizualizować obraz głębokości

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); 

Jednak to pokazuje tylko dwa kolory To dlatego, że wszystkie wartości są blisko siebie, czyli w przedziale 150-175 + małe wartości, które pokazują się w kolorze czarnym (patrz poniżej).

rgb image greyscale image

Czy istnieje sposób, aby znormalizować te dane tak, że pokaże różne poziomy szarości, aby podkreślić te małe różnice głębokości?

Odpowiedz

19

Według documentation The imshow funkcji można korzystać z różnych typów obrazów. To wsparcie 16-bitowych niepodpisanych zdjęć, dzięki czemu można wyświetlać obraz przy użyciu

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

W tym przypadku zakres wartości obraz jest odwzorowany z przedziału [0, 255 * 256] do zakresu [0, 255] .

Jeśli obraz zawiera tylko wartości w dolnej części tego zakresu, można zaobserwować niejasny obraz. Jeśli chcesz korzystać z pełnego zakresu wyświetlacza (od czerni do bieli), należy dostosować obraz do pokrycia oczekiwanego zakresu dynamicznego, jednym ze sposobów na to jest

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

Nie widzę powodu, dla którego skalowanie go przez 255/max (sam jak ja dzieląc każdy element przez max/255) sprawi, że użyje pełnego zakresu. Mam na myśli to, a ja przyjmuję odpowiedź, ale po prostu jej nie rozumiem. Co jeszcze robi ta funkcja? – Aly

+0

The [convertScaleAbs] (http: //docs.opencv.Funkcja org/modules/core/doc/operations_on_arrays.html? highlight = convertscaleabs # cv.ConvertScaleAbs) wykonuje 3 operacje: skalowanie, obliczanie wartości bezwzględnej i konwersję na niepodpisany typ 8-bitowy. Dlatego współczynnik 255/maks. Zapewnia pełny zakres ([0-255] dla niepodpisanego 8-bitowego). Co więcej, jak wspomniał @sammy, dynamiczny zakres dopasowanego obrazu jest lepiej wykorzystywany, biorąc pod uwagę minimalną wartość danych. – samota

2

Jeśli dane wejściowe imshow mają typ danych zmiennoprzecinkowych, funkcja przyjmuje, że wartości pikseli znajdują się w [0; 1] zasięgu. W rezultacie wszystkie wartości wyższe niż 1 są wyświetlane na biało.

więc nie musisz podzielić przez 255. divisor

+0

Po tych linii: 'depthImage = cv :: imread ("coffee_mug_1_1_1_depthcrop.png", CV_LOAD_IMAGE_ANY GŁĘBOKOŚĆ CV_LOAD_IMAGE_ANYCOLOR); depthImage.convertTo (depthImage, CV_32F); 'Jeśli wydrukuję wartości, są one w zakresie [0,1161], więc mój dzielnik ma 1161/255, aby uzyskać wszystkie wartości w zakresie [0,255], być może jeśli następnie przekonwertuję to na CV_8UC1? – Aly

+0

Ach tak, to działało. Plus jeśli użyję equalizera histogramu, to da to znacznie lepszą reprezentację. – Aly

+0

Najpierw funkcja 'imread' odczytuje obraz zachowujący oryginalne wartości, więc 1161 jest OK dla obrazu o 16 bitach na piksel. Po drugie, metoda 'convertTo' nie skaluje wartości domyślnie, zmienia jedynie typ i nasyca. Wyjaśnia to, dlaczego drukowane wartości są tak duże. –

17

Dodawanie do samg”odpowiedzi, można poszerzyć jeszcze większy zasięg wyświetlanego obrazu.

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); 

Wynikiem powinno być coś jak poniżej

enter image description here

+1

jest to możliwe, aby openCV mógł wyświetlać mapę kolorów ze skalą, jak pokazano po prawej? –

+2

Nie. To jest fabuła Matlaba. – Sam

+0

Pozdrowienia Sammy, doceń szybką odpowiedź –

2

dodanie do Sammy odpowiedź, jeśli oryginalna kolorystyka jest [-min, max] i chcesz wykonać wyrównanie histogramu i wyświetlanie koloru głębokość, kod powinien być jak poniżej:

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); 
Powiązane problemy