一、前言

GDAL具有强大的图像读写功能,但是对常用图像处理算法的集成较少,OpenCV恰恰具有较强的图像处理能力,因此有效的结合两者对图像(遥感影像)的处理带来了极大的方便。那么如何实现GDAL与openCV间的数据交换成为影像处理中的关键步骤。接下来我将记录下:1 如何将GDAL读取的影像转化为openCV支持的的MAT格式?2 如何将处理后MAT数据转化为合适的图像格式存储?(PS:本人也是初次使用GDAL和openCV,代码很水。。。只是记录下自己学的,和大家交流下)

二、GDAL数据到openCV的MAT格式

关于GDAL数据到openCV的格式转化,网上已有部分资源,但是大多是针对单或者三通道的数据而言,对多通道图像(遥感的多光谱和高光谱影像)的转化不多,话不多说,先上代码:

 1 cv::Mat GDAL2Mat(const QString fileName)
2 {
3 GDALAllRegister(); // 注册。。。
4 GDALDataset *poDataset = (GDALDataset *)GDALOpen(fileName.toStdString().c_str(),GA_ReadOnly);
5 int tmpCols = poDataset->GetRasterXSize();
6 int tmpRows = poDataset->GetRasterYSize();
7 int tmpBandSize = poDataset->GetRasterCount();
8 double *tmpadfGeoTransform = new double[6];
9 poDataset->GetGeoTransform(tmpadfGeoTransform);
10
11 QVector <cv::Mat> imgMat; // 每个波段
12 float *pafScan = new float[tmpCols*tmpRows]; // 存储数据
13
14 for(int i = 0;i< tmpBandSize;i++)
15 {
16 GDALRasterBand *pBand = poDataset->GetRasterBand(i+1);
17 //pafScan = new float[tmpCols*tmpRows];
18 pBand->RasterIO(GF_Read,0,0,tmpCols,tmpRows,pafScan,
19 tmpCols,tmpRows,GDT_Float32,0,0);
20 cv::Mat tmpMat = cv::Mat(tmpRows,tmpCols,CV_32FC1,pafScan);
21 imgMat.push_back(tmpMat.clone());
22 }
23 delete []pafScan;
24 pafScan = NULL;
25
26 cv::Mat img;
27 img.create(tmpRows,tmpCols,CV_32FC(tmpBandSize));
28 cv::merge(imgMat.toStdVector(),img);
29 imgMat.clear();
30 GDALClose((GDALDatasetH)poDataset);
31 return img;
32 }

思路就是:根据文件名获得其GDALDataset数据集,然后分波段(波段相当于通道)存储在格式为Vector<cv::Mat>的容器内,最后利用MAT的Merge函数,对通道数据进行组合。以上方法适合任意波段数据,对多通道影像,如遥感影像中多光谱和高光谱数据比较实用。但,存在一个问题:代码中红色部分,目的为释放poDataset的内存,但总会报错,注释后就没有问题了,不知道为啥,哪位大侠如果知道原因并且也恰巧路过此地,请给予帮助,谢谢!(问题解决了,GDALDataset数据集前不能释放其每个波段的指针,否则报错,代码已修改,下同)

三、MAT格式数据转化为GDAL数据集格式后并保存合适文件

思路是上面第二部分的逆过程。首先创建一个数据集和文件驱动,根据相关参数创建文件,并将多通道MAT数据通过CV::split函数进行通道分离,最后将通道数据与GDAL数据集的波段数据对应,一一写入数据集中。代码如下:

 1 bool Mat2File(cv::Mat img, const QString fileName)
2 {
3 if(img.empty()) // 判断是否为空
4 return 0;
5
6 const int nBandCount=img.channels();
7 const int nImgSizeX=img.cols;
8 const int nImgSizeY=img.rows;
9
10 // 将通道分开
11 // imgMat每个通道数据连续
12 std::vector<cv::Mat> imgMat(nBandCount);
13 cv::split(img,imgMat);
14
15 // 分波段写入文件
16 GDALAllRegister();
17 GDALDataset *poDataset; //GDAL数据集
18 GDALDriver *poDriver; //驱动,用于创建新的文件
19 poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
20
21 if(poDriver == NULL)
22 return 0;
23 poDataset=poDriver->Create(fileName.toStdString().c_str(),nImgSizeX,nImgSizeY,nBandCount,
24 GDT_Float32,NULL);
25 // 循环写入文件
26 GDALRasterBand *pBand = NULL;
27 float *ppafScan = new float[nImgSizeX*nImgSizeY];
28 cv::Mat tmpMat;// = cv::Mat(nImgSizeY,nImgSizeX,CV_32FC1);
29
30 int n1 = nImgSizeY;
31 int nc = nImgSizeX;
32
33 for(int i = 1;i<=nBandCount;i++)
34 {
35 pBand = poDataset->GetRasterBand(i);
36 tmpMat = imgMat.at(i-1);
37 if(tmpMat.isContinuous())
38 {
39 nc = n1*nc;
40 n1 = 1;
41 }
42 for(int r = 0;r<n1;r++)
43 {
44 int tmpI = r*nImgSizeX;
45 float *p = tmpMat.ptr<float>(r);
46 for(int c = 0;c<nc;c++)
47 {
48 ppafScan[tmpI+c] = p[c];
49 }
50 }
51 pBand->RasterIO(GF_Write,0,0,nImgSizeX,nImgSizeY,ppafScan,
52 nImgSizeX,nImgSizeY,GDT_Float32,0,0);
53 }
54 delete []ppafScan;
55 ppafScan = NULL;
56 GDALClose(poDataset);
57 return 1;
58 }
 60 bool ChooseSample::Mat2File(std::vector<cv::Mat> imgMat, const QString fileName)
61 {
62 if(imgMat.empty()) // 判断是否为空
63 {
64 QMessageBox::information(this,"Message Error","Data NULL!");
65 return 0;
66 }
67
68 const int nBandCount=imgMat.size();
69 const int nImgSizeX=imgMat[0].cols;
70 const int nImgSizeY=imgMat[0].rows;
71
72 // 分波段写入文件
73 GDALAllRegister();
74 GDALDataset *poDataset; //GDAL数据集
75 GDALDriver *poDriver; //驱动,用于创建新的文件
76 poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
77
78 if(poDriver == NULL)
79 return 0;
80 poDataset=poDriver->Create(fileName.toStdString().c_str(),nImgSizeX,nImgSizeY,nBandCount,
81 GDT_Float32,NULL);
82 // 循环写入文件
83 GDALRasterBand *pBand = NULL;
84 float *ppafScan = new float[nImgSizeX*nImgSizeY];
85 cv::Mat tmpMat;// = cv::Mat(nImgSizeY,nImgSizeX,CV_32FC1);
86
87 int n1 = nImgSizeY;
88 int nc = nImgSizeX;
89
90 for(int i = 1;i<=nBandCount;i++)
91 {
92 pBand = poDataset->GetRasterBand(i);
93 tmpMat = imgMat.at(i-1);
94 if(tmpMat.isContinuous())
95 {
96 nc = n1*nc;
97 n1 = 1;
98 }
99 for(int r = 0;r<n1;r++)
100 {
101 int tmpI = r*nImgSizeX;
102 float *p = tmpMat.ptr<float>(r);
103 for(int c = 0;c<nc;c++)
104 {
105 ppafScan[tmpI+c] = p[c];
106 }
107 }
108 pBand->RasterIO(GF_Write,0,0,nImgSizeX,nImgSizeY,ppafScan,
109 nImgSizeX,nImgSizeY,GDT_Float32,0,0);
110 }
111 delete []ppafScan;
112 ppafScan = NULL;
113 GDALClose(poDataset);
114 return 1;
115 }

同样有如上的困扰,每当释放内存就会报错(代码中红色字体处)。此外,关于cv::split函数有一个小的细节问题,如下:

1     //    将通道分开
2 // imgMat每个通道数据连续
3 std::vector<cv::Mat> imgMat(nBandCount);
4 cv::split(img,imgMat);
5
6 // imgMat每个通道数据不连续
7 QVector<cv::Mat> imgMat(nBandCount);
8 cv::split(img,imgMat.toStdVector());

最新文章

  1. [Erlang 0104] 当Erlang遇到Solr
  2. 最全的运营推广方案,教你如何从零开始运营APP
  3. TCP连接建立系列 — 服务端接收ACK段(一)
  4. Linux服务器管理: 系统的进程管理终止进程kill命令
  5. HttpWebRequest 和HttpWebResponse总结
  6. 【gradle】之maven主库找不到Could not find org.restlet.jee:org.restlet:2.1.1
  7. MVC4.0 WebApi如何自定义返回数据类型
  8. eclipse打开一闪而过,环境安装正确
  9. EL表达式复习
  10. ubuntu菜单面板丢了怎么找回
  11. iOS开发中地图开发的简单应用
  12. c++ try throw catch
  13. 解决Centos crontab没有按时运行的问题
  14. Query DSL(2)----Full text queries
  15. sql sever基本命令
  16. 使用vue实现tab栏的点击切换样式
  17. Linux设置虚拟内存教学和实战
  18. Mac 安装、卸载JDK 1.6
  19. Study 5 —— CSS概述
  20. 每天进步一点点-序列化和反序列(将对象写入硬盘文件and从硬盘文件读出对象)

热门文章

  1. 【python学习笔记01】python的数据类型
  2. 大端模式&amp;小端模式、主机序&amp;网络序、入栈地址高低问题
  3. Ubuntu14.0.4 64位 ADT 连接手机调试问题
  4. C#操作XML文档(XmlDocument、XmlNode、XmlAttribute、SelectSingleNode、SelectNodes、XmlNodeList)
  5. Unattended Setup Software Components (无人值守安装软件组件)
  6. Curvy unity
  7. Yeslab现任明教教主数据中心第二门课程UCS 视频教程下载
  8. 多线程中的lua同步问题
  9. javascript 判断系统设备
  10. C#入门(一):IDE