OpenCV实现了很多图像处理中的算法,极大的降低了我们研究中码代码的工作量,可以把更多的精力放在算法设计上。

Mat是OpenCV中最常见的数据格式,可以直接用imread函数将图像数据读取并存储为Mat格式。Mat型图像矩阵可以直接应用于OpenCV的大多数算法,例如图像形态学操作、行列号访问像素、仿射变换等。

最近在研究中,我需要读取一些多波段的tiff影像,OpenCV读取tiff的时候,有个波段数≤4的限制,这个在面对多光谱数据的时候,有点不方便。一开始我是将多波段的tiff用ENVI分成多个4波段的tiff文件导出,再多次读取,也将就着完成了研究需求。不过实现方法着实麻烦,也很不优雅。

在完成了研究所需后,再返回来看这个问题本身。我需要的是将多波段的tiff读取为Mat格式。OpenCV不能读取多波段tiff,但是GDAL可以。那我可不可以写个函数,就是用GDAL读取多波段tiff,然后输出给Mat呢?

想法有了,下面就是面向搜索引擎的编程环节了。

网上看了一圈,大概思路是GDAL循环读取tiff的每个波段,然后每个波段存储为一个单波段的Mat,然后存入vector,最后返回一个成员数量与tiff波段数相同的Mat型vector。

这边有个大佬写的特别好,也很详细,不过我还没细啃,我的代码与大佬的相比,相当于从跑车上获得灵感然后造了个自行车。

下面是我的代码,定义了一个函数,并读取一张landsat8影像作为测试:

#include #include #include #include using namespace std;using namespace cv;//gdal读取tiff,转为Mat型Vector,并获取图像左上角坐标与分辨率vector ReadTiffAsMatVector(const char* in_tiff_img, double& map_tie_point_x , double& map_tie_point_y, double& map_pixel_size){  //读取数据千万记得查看数据类型  /***********************************************************/  // GCDataType:GDAL和OpenCV数据类型转换的中间格式  // GC_Byte   =======  GDT_Byte   =======  CV_8U  =======  unsigned char  // GC_UInt16 =======  GDT_UInt16 =======  CV_16U =======  unsigned short  // GC_Int16  =======  GDT_Int16  =======  CV_16S =======  short int  // GC_UInt32 =======  GDT_UInt32 =======  缺失   =======  unsigned long  // GC_Int32  =======  GDT_Int32  =======  CV_32S =======  long  // GC_Float32=======  GDT_Float32=======  CV_32F =======  float  // GC_Float64=======  GDT_Float64=======  CV_64F =======  double  /***********************************************************/  //注册驱动  GDALAllRegister();  //读取tiff图像  GDALDataset* in_tiff_dataset = (GDALDataset*)GDALOpen(in_tiff_img, GA_ReadOnly); // GDAL数据集   //获取行列数、图像左上角坐标、分辨率、波段数等基本信息  int col_num = in_tiff_dataset->GetRasterXSize(); // 列   int rol_num = in_tiff_dataset->GetRasterYSize(); // 行   int band_num = in_tiff_dataset->GetRasterCount();//波段数   double* tiff_img_geoTransform = new double[6];  in_tiff_dataset->GetGeoTransform(tiff_img_geoTransform);  map_tie_point_x = tiff_img_geoTransform[0];  map_tie_point_y = tiff_img_geoTransform[3];  map_pixel_size = tiff_img_geoTransform[1];  // Mat型容器,每个元素用于存储一个波段的数据  vector img_mat_vector;    // 读取每个波段的数据,注意数据类型  unsigned int* tiff_img_band_mat;     // 循环读取每个波段  for (int current_band_num = 0; current_band_num < band_num; current_band_num++)  {    //读取第GDAL波段数从1开始    GDALRasterBand* tiff_img_band_data = in_tiff_dataset->GetRasterBand(current_band_num + 1);    tiff_img_band_mat = new unsigned int[col_num * rol_num];    //读取数据    tiff_img_band_data->RasterIO(GF_Read, 0, 0, col_num, rol_num, tiff_img_band_mat, col_num, rol_num, GDT_UInt16, 0, 0);    //转为Mat    Mat band_mat_temp = Mat(rol_num, col_num, CV_16U, tiff_img_band_mat);    //存入容器    img_mat_vector.push_back(band_mat_temp.clone());    delete[]tiff_img_band_data;    band_mat_temp.release();  }  return img_mat_vector;}int main(){  //新建存放数据的容器  vector cls_img_band_vector;  //新建用于接收图像左上角坐标与分辨率的变量  double cls_img_tie_point_x, cls_img_tie_point_y, cls_img_pixel_size;  //调用函数读取数据  cls_img_band_vector = ReadTiffAsMatVector("landsat8_test.tif", cls_img_tie_point_x, cls_img_tie_point_y, cls_img_pixel_size);  cout << "读取的tiff波段数为:" << cls_img_band_vector.size() << endl;  cout << "图像左上角坐标为:" << cls_img_tie_point_x < out_img_mat(3);  out_img_mat[0] = cls_img_band_vector[2];  out_img_mat[1] = cls_img_band_vector[3];  out_img_mat[2] = cls_img_band_vector[4];  Mat out_img;  merge(out_img_mat, out_img);  //显示  namedWindow("测试", 0);  resizeWindow("测试", 640, 640);  imshow("测试", out_img);  waitKey(36000);  return 0;}

结果如图




opencv获取指定帧 opencv读取tif_opencv获取指定帧


opencv获取指定帧 opencv读取tif_gdal不支持fgdbr格式_02


#科技萌新成长营##编程##OpenCV#

注意事项:注意GDAL与OpenCV的数据格式对应,以及OpenCV的波段顺序B、G、R。