【问题标题】:OpenCV: How to visualize a depth imageOpenCV:如何可视化深度图像
【发布时间】:2012-11-30 04:07:54
【问题描述】:

我正在使用一个数据集,其中包含图像,其中每个像素都是一个 16 位无符号整数,以毫米为单位存储该像素的深度值。我试图通过执行以下操作将其可视化为灰度深度图像:

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 的范围内 + 显示为黑色的小值(见下文)。

有没有办法对这些数据进行归一化,使其显示各种灰度以突出这些小的深度差异?

【问题讨论】:

    标签: c++ opencv visualization kinect depth


    【解决方案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);
    

    【讨论】:

    • 我不明白为什么将其缩放 255/max(就像我将每个元素除以 max/255 一样)会使其使用整个范围。我的意思是确实如此,我会接受答案,但我就是不明白。该函数还有什么作用?
    • convertScaleAbs 函数执行 3 个操作:缩放、计算绝对值和转换为无符号 8 位类型。这就是为什么因子 255/max 确保使用全范围(无符号 8 位为 [0-255])。此外,正如@sammy 所提到的,通过考虑数据的最小值,可以更好地使用调整后图像的动态范围。
    【解决方案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);
    

    结果应该类似于下面的结果

    【讨论】:

    • openCV是否可以输出带有比例的颜色图,如右图所示?
    • 没有。这是一个 Matlab 绘图。
    • 干杯 Sammy,感谢您的及时回复
    • 第四个参数应该是-255*min/(max-min)而不是-min。我花了半个小时来调试这个。请更正。
    • 当我为 CV_32FC3 执行此操作时,我遇到了一个致命异常,该异常在 extern "C" LONG WINAPI __scrt_unhandled_exception_filter(LPEXCEPTION_POINTERS const pointers) { auto const exception_record = reinterpret_cast&lt;EHExceptionRecord*&gt;(pointers-&gt;ExceptionRecord); if (PER_IS_MSVC_PURE_OR_NATIVE_EH(exception_record)) { terminate(); } return EXCEPTION_CONTINUE_SEARCH; } 上中断,它是否也适用于 CV_32FC3 类型的 cv::Mat?
    【解决方案3】:

    如果imshow 输入具有浮点数据类型,则该函数假定像素值在 [0; 1]范围。结果所有大于 1 的值都显示为白色。

    因此,您无需将您的 divisor 除以 255。

    【讨论】:

    • 在这些行之后:depthImage = cv::imread("coffee_mug_1_1_1_depthcrop.png", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); depthImage.convertTo(depthImage, CV_32F); 如果我打印它们在 [0,1161] 范围内的值,那么我的除数是 1161/255 以获取 [0,255] 范围内的所有值,也许如果我然后转换为 CV_8UC1 ?
    • 啊,是的,这行得通。另外,如果我使用均衡直方图,它会提供更好的表示
    • 首先,imread 函数会读取保留原始值的图像,因此对于每像素 16 位的图像,1161 是可以的。其次,convertTo 方法默认不缩放值,它只会改变类型并饱和。所以这就解释了为什么打印的值这么大。
    【解决方案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);
    

    【讨论】:

    • 亲,是直方图均衡还是对比度增强?
    猜你喜欢
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-03
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    相关资源
    最近更新 更多