转载

1. GDAL与OpenCV2.X数据转换(适合多光谱和高光谱等多通道的遥感影像)

一、前言

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);   // GDAL数据集  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;   // 存储数据 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         delete []pBand; 23         tmpMat.release(); 24     } 25     delete []pafScan; 26     cv::Mat img; 27     img.create(tmpRows,tmpCols,CV_32FC(tmpBandSize)); 28     cv::merge(imgMat.toStdVector(),img); 29     //GDALClose((GDALDatasetH)poDataset);
30 imgMat.clear();
31 return img;
32 }

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

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

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

 1 bool Mat2File(std::vector<cv::Mat> imgMat, const QString fileName)  2 {  3     if(imgMat.empty())    //    判断是否为空  4     {  5         QMessageBox::information(this,"Message Error","Data NULL!");  6         return 0;  7     }  8   9     const int nBandCount=imgMat.size(); 10     const int nImgSizeX=imgMat[0].cols; 11     const int nImgSizeY=imgMat[0].rows; 12  13     //  分波段写入文件 14     GDALAllRegister(); 15     GDALDataset *poDataset;   //GDAL数据集 16     GDALDriver *poDriver;      //驱动,用于创建新的文件 17     poDriver = GetGDALDriverManager()->GetDriverByName("ENVI"); 18  19     if(poDriver == NULL) 20         return 0; 21     poDataset=poDriver->Create(fileName.toStdString().c_str(),nImgSizeX,nImgSizeY,nBandCount, 22                                 GDT_Float32,NULL); 23     //  循环写入文件 24     GDALRasterBand *pBand = NULL; 25     float *ppafScan; 26     for(int i = 1;i<=nBandCount;i++) 27     { 28         pBand = poDataset->GetRasterBand(i); 29         cv::Mat tmpMat = cv::Mat(nImgSizeY,nImgSizeX,CV_32FC1); 30         tmpMat = imgMat.at(i-1).clone(); 31         ppafScan = new float[nImgSizeX*nImgSizeY]; 32         if(tmpMat.isContinuous()) 33         { 34            ppafScan = tmpMat.ptr<float>(0); 35         }else 36         { 37             for(int r = 0;r<nImgSizeY;r++) 38             { 39                 int tmpI = r*nImgSizeX; 40                 float *p = tmpMat.ptr<float>(r); 41                 for(int c = 0;c<nImgSizeX;c++) 42                 { 43                     ppafScan[tmpI+c] = p[c]; 44                 } 45             } 46         } 47         pBand->RasterIO(GF_Write,0,0,nImgSizeX,nImgSizeY,ppafScan, 48                         nImgSizeX,nImgSizeY,GDT_Float32,0,0); 49         tmpMat.release(); 50     } 51     delete pBand; 52     delete poDriver; 53     //delete ppafScan; 54     //delete poDataset; 55     return 1; 56 }
 1 bool ChooseSample::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     std::vector<cv::Mat> imgMat(nBandCount); 12     cv::split(img,imgMat); 13  14     //  分波段写入文件 15     GDALAllRegister(); 16     GDALDataset *poDataset;   //GDAL数据集 17     GDALDriver *poDriver;      //驱动,用于创建新的文件 18     poDriver = GetGDALDriverManager()->GetDriverByName("ENVI"); 19  20     if(poDriver == NULL) 21         return 0; 22     poDataset=poDriver->Create(fileName.toStdString().c_str(),nImgSizeX,nImgSizeY,nBandCount, 23                                 GDT_Float32,NULL); 24     //  循环写入文件 25     GDALRasterBand *pBand = NULL; 26     float *ppafScan; 27     for(int i = 1;i<=nBandCount;i++) 28     { 29         pBand = poDataset->GetRasterBand(i); 30         cv::Mat tmpMat = cv::Mat(nImgSizeY,nImgSizeX,CV_32FC1); 31         tmpMat = imgMat.at(i-1).clone(); 32         ppafScan = new float[nImgSizeX*nImgSizeY]; 33         if(tmpMat.isContinuous()) 34         { 35            ppafScan = tmpMat.ptr<float>(0); 36         }else 37         { 38             for(int r = 0;r<nImgSizeY;r++) 39             { 40                 int tmpI = r*nImgSizeX; 41                 float *p = tmpMat.ptr<float>(r); 42                 for(int c = 0;c<nImgSizeX;c++) 43                 { 44                     ppafScan[tmpI+c] = p[c]; 45                 } 46             } 47         } 48         pBand->RasterIO(GF_Write,0,0,nImgSizeX,nImgSizeY,ppafScan, 49                         nImgSizeX,nImgSizeY,GDT_Float32,0,0); 50         tmpMat.release(); 51     } 52     delete pBand; 53     delete poDriver; 54     //delete ppafScan; 55     //delete poDataset; 56     return 1; 57 }

同样有如上的困扰,每当释放内存就会报错(代码中红色字体处)。此外,关于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());
正文到此结束
Loading...