1. GDAL and OpenCV2.X data conversion (suitable for multi-spectral and high-Spectral Multi-Channel Remote Sensing Images), gdalopencv2.x
I. Preface
GDAL has powerful image reading and writing functions, but has little integration with common image processing algorithms. OpenCV has a strong image processing capability. Therefore, it effectively integrates the two functions for images (remote sensing images) processing brings great convenience. Therefore, how to implement data exchange between GDAL and openCV becomes a key step in image processing. Next I will record: 1. How do I convert the images read by GDAL to the MAT format supported by openCV? 2. How can we convert the processed MAT data into an appropriate image format for storage? (PS: I used GDAL and openCV for the first time. The code is very watery... I just recorded what I learned and communicated with you)
II. The MAT format for GDAL data to openCV
There are some resources on the Internet for converting GDAL data to openCV, but most of them are for single-or three-channel data, and there is not much conversion for multi-channel images (multi-spectral and high-spectral images of remote sensing, let's not talk much about it. first go to the Code:
1 cv: Mat GDAL2Mat (const QString fileName) 2 {3 GDALAllRegister (); // register... 4 GDALDataset * poDataset = (GDALDataset *) GDALOpen (fileName. toStdString (). c_str (), GA_ReadOnly); // GDAL dataset 5 int tmpCols = poDataset-> GetRasterXSize (); // column 6 int tmpRows = poDataset-> GetRasterYSize (); // line 7 int tmpBandSize = poDataset-> GetRasterCount (); 8 double * tmpadfGeoTransform = new double [6]; 9 poDataset-> GetGeoTransform (tmpadfGeoTransform); 10 11 QVector <cv:: Mat> imgMat; // 12 float * pafScan for each band; // stores data 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}
The idea is: Get the GDALDataset dataset Based on the file name, store the sub-band (band is equivalent to channel) in the container in the format of Vector <cv: Mat>, and finally use the Merge function of MAT, combines channel data. The above method is suitable for any band data and is more practical for multi-channel images, such as remote sensing images with multi-spectral and high-spectral data. However, there is a problem: the red part in the Code is designed to release the poDataset memory, but there will always be an error. After the annotation, there will be no problem. I don't know why, if you know the reason and happen to pass by, please help. Thank you!
Iii. convert data in MAT format to GDAL dataset format and save appropriate files
The idea is the inverse process in the second part above. First, create a dataset and a file driver, create a file based on the relevant parameters, and separate the multi-channel MAT data using the CV: split function, finally, the channel data corresponds to the band data of the GDAL dataset and is written to the data set one by one. The Code is as follows:
1 bool Mat2File (std: vector <cv: Mat> imgMat, const QString fileName) 2 {3 if (imgMat. empty () // determines whether it is NULL 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 // Write File 14 GDALAllRegister (); 15 GDALDataset * poDataset; // GDAL dataset 16 GDALDriver * poDriver; // driver, used to create a new file 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 // cyclically written file 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} else36 {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, nImgSizeX, nImgSizeY, ppafScan, 48 nImgSizeX, nImgSizeY, GDT_Float32,); 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 () // determines whether it is null 4 return 0; 5 6 const int nBandCount = img. channels (); 7 const int nImgSizeX = img. cols; 8 const int nImgSizeY = img. rows; 9 10 // separate channels 11 std: vector <cv: Mat> imgMat (nBandCount); 12 cv: split (img, imgMat ); 13 14 // Write File 15 GDALAllRegister (); 16 GDALDataset * poDataset; // GDAL dataset 17 GDALDriver * poDriver; // driver, used to create a new file 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 // cyclically written file 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} else37 {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, nImgSizeX, nImgSizeY, ppafScan, 49 nImgSizeX, nImgSizeY, GDT_Float32,); 50 tmpMat. release (); 51} 52 delete pBand; 53 delete poDriver; 54 // delete ppafScan; 55 // delete poDataset; 56 return 1; 57}
Similarly, when memory is released, an error is reported (in the red font of the Code ). In addition, there is a small detail about the cv: split function, as shown below:
1 // separate channels 2 // imgMat data for each channel 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 ());