程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 1. GDAL與OpenCV2.X數據轉換(適合多光譜和高光譜等多通道的遙感影像),gdalopencv2.x

1. GDAL與OpenCV2.X數據轉換(適合多光譜和高光譜等多通道的遙感影像),gdalopencv2.x

編輯:C++入門知識

1. GDAL與OpenCV2.X數據轉換(適合多光譜和高光譜等多通道的遙感影像),gdalopencv2.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());

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved