OpenCV: как визуализировать изображение глубины

Я использую набор данных, в котором он имеет изображения, где каждый пиксель представляет собой 16-битный беззнаковый int, сохраняющий значение глубины этого пикселя в мм. Я пытаюсь визуализировать это как изображение глубины серого, делая следующее:

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

Однако он показывает только два цвета, потому что все значения близки друг к другу, то есть в диапазоне 150-175 + небольшие значения, которые отображаются черным (см. ниже).

rgb imagegreyscale image

Есть ли способ нормализовать эти данные, чтобы он отображал различные уровни серого, чтобы выделить эти небольшие различия в глубинах?

Ответы

Ответ 1

Согласно documentation, функция imshow может использоваться с различными типами изображений. Он поддерживает 16-битные неподписанные изображения, поэтому вы можете отображать свое изображение с помощью

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

В этом случае диапазон значений изображения отображается из диапазона [0, 255 * 256] в диапазон [0, 255].

Если ваше изображение содержит только значения в нижней части этого диапазона, вы увидите неясное изображение. Если вы хотите использовать полный диапазон отображения (от черного до белого), вы должны отрегулировать изображение, чтобы покрыть ожидаемый динамический диапазон, один из способов сделать это -

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

Ответ 2

Добавив в ответ samg, вы можете расширить диапазон отображаемого изображения.

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

Результат должен быть чем-то вроде ниже

enter image description here

Ответ 3

Если вход imshow имеет тип данных с плавающей запятой, тогда функция предполагает, что значения пикселей находятся в [0; 1]. В результате все значения, превышающие 1, отображаются белыми.

Поэтому вам не нужно разделить ваш divisor на 255.

Ответ 4

Добавление в ответ Sammy, если исходный цвет диапазона [-min, max] и вы хотите выполнить выравнивание гистограммы и отобразить цвет глубины, код должен выглядеть следующим образом:

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