使用OpenCV对视差图/深度图(CV_16S/CV_32S)进行保存和显示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YunLaowang/article/details/86583351

OpenCV默认的图像格式为CV_8UC3,此时图像为3通道、8位RGB图像,每个通道所能表达的灰度阶为 2 8 = 256 2^8=256 。而视差图常为CV_16S或CV_32S等,如果直接使用cv::imwrite()保存视差图或深度图,则图像将被转成CV_8U格式,而像素值大于255将会被转成255。

可选图像格式

首先来看一下,OpenCV有哪些可选的数据类型

Unsigned 8bits uchar 0~255
Mat: CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4

Signed 8bits char -128~127
Mat: CV_8SC1,CV_8SC2,CV_8SC3,CV_8SC4

Unsigned 16bits ushort 0~65535
Mat: CV_16UC1,CV_16UC2,CV_16UC3,CV_16UC4

Signed 16bits short -32768~32767
Mat: CV_16SC1,CV_16SC2,CV_16SC3,CV_16SC4

Signed 32bits int -2147483648~2147483647
Mat: CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4

Float 32bits float -1.18*10-38~3.40*10-38 
Mat: CV_32FC1,CV_32FC2,CV_32FC3,CV_32FC4

Double 64bits double 
Mat: CV_64FC1,CV_64FC2,CV_64FC3,CV_64FC4

如上数据类型,在访问图像像素时可用于确定像素类型(如确定.at< type >中的type)。

显示

OpenCV提供的接口函数:cv::imwrite()、cv::imshow()都只能对像素值处于0-255范围内的图像进行存储和显示,其他范围内的图像,则会被转成0-255范围进行存储、显示。也就是说,无法使用OpenCV提供的接口函数存储和显示诸如CV_16S格式的视差图/深度图,只能转换成CV_8U格式进行操作。

其实,人眼对灰度级的敏感度比较低、根本无法分辨256级灰度值。而对视差图/深度图进行显示,也只是为了比较直观的验证视差图/深度图的准确性(如颜色随距离逐层变化),所以说完全没必要对 2 16 = 65536 2^{16}=65536 级灰度进行显示,转换成CV_8U格式就能完全满足需求,这也许就是为什么OpenCV没有提供这样接口的原因之一吧。

如果非要进行显示,Windows系统可以使用Visual Studio的Image Watch插件,通过设置断点来显示视差图/深度图。不过,因为存在的灰度级数较多、视觉对比不强烈,导致图片看起来很费眼力。

存储

图像的显示可以说是为了直观的判断视差图/深度图的效果,但是在对深度值进行存储时,则必须要求像素值的精确性,此时CV_8U格式显然无法满足需求。

理论上来说,我们处理的图像作为数字矩阵,可以按照任何自定义的规则进行存储和读入,而不会影响使用,但缺点是不能直观的显示、规则的自定义导致了可移植性较差。

但存储成大家普遍使用的格式,相对来说开发起来会容易很多,比如存储成XML/YML格式。XML/YML作为互联网通用的文件格式,可以跨平台、跨系统,同时不受编程语言的限制,好处多多,而且OpenCV还为这两种格式文件的读写提供了相关的API函数,实现起来简单快捷,而不用“自己造轮子”了。

  • 代码
    这里给出XML读写的简单Demo,起到抛砖引玉的作用,更多复杂、丰富的功能留待大家自行探索。
/*
cv::FileStorage:
	XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or reading data to/from a file
*/
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

int main(int argc, char* argv[])
{
	// write
	Mat src = (Mat_<double>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
	FileStorage fswrite("test.xml", FileStorage::WRITE);// 新建文件,覆盖掉已有文件
	fswrite << "src1" << src;
	fswrite.release();

	cout << "Write Fineshed!" << endl;

	// read
	FileStorage fsread("test.xml", FileStorage::READ);
	Mat dst;
	fsread["src1"] >> dst; // 读出src1节点里的数据
	cout << dst << endl;
	fsread.release();

	cout << "Read Finishied" << endl;
	
	waitKey();
	return 0;
}
  • 结果
    xml文件有其特殊存储格式,如下图可见一斑。

猜你喜欢

转载自blog.csdn.net/YunLaowang/article/details/86583351