在上一篇博客中,大概说了下怎么使用gdal提供的gdalwarp工具来进行校正处理。其实质与envi的glt校正应该是一样的。我把gdalwarp的代码封装了一下,写了一个类来进行geoloc处理。希望对大家有用。
先是头文件,函数的注释很详细,就不多说了。后面的源文件就是从gdalwarp.cpp中摘录出来的,有兴趣的可以看gdalwarp.cpp ,下面的代码只是把这个文件中没有用到的代码删除了,同时有些参数直接写死了。不太清楚的可以直接看原来的代码。
/***************************************************************************
*
* Time: 2013-03-02
* Project: 遥感处理算法
* Purpose: 地理查找表校正
* Author: 李民录
* Copyright (c) 2013, liminlu0314@gmail.com
* Describe: 地理查找表校正,用于HDF数据的校正算法
*
****************************************************************************/
#ifndef IMAGEGEOLOCWARP_H
#define IMAGEGEOLOCWARP_H
#include "ImgCore.h"
/**
* \file ImageGeoLocWarp.h
* @brief 地理查找表校正
*
* 地理查找表校正,主要用于HDF数据的校正。比如海洋卫星数据等,MODIS数据等。
* 一般在该类型的数据中,有两个Latitude和Longitude的32位浮点数的数据集,
* 用来存储数据的经纬度坐标,在校正过程中使用这两个进行处理
*/
class IMGALG_API CImageGeoLocWarp
{
public:
/**
* @brief 构造函数,地理查找表校正
* @param pszSrcFile 原始数据路径
* @param pszDstFile 结果数据路径
* @param pszFormat 结果数据格式
* @param pProcess 进度条指针
*/
CImageGeoLocWarp(const char* pszSrcFile, const char* pszDstFile,
const char* pszFormat = "HFA", CProcessBase* pProcess = NULL);
/**
* @brief 析构函数
*/
~CImageGeoLocWarp();
/**
* @brief 获取输出参数信息
* @param iHeight 输出图像高度
* @param iWidth 输出图像宽度
* @param padfGeoTransform 输出GeoTransform六参数
* @param padfExtent 输出图像四至范围
* @return 是否计算成功,以及错误代码
*/
int GetSuggestedWarpOutput(int &iHeight, int &iWidth, double *padfGeoTransform = NULL, double *padfExtent = NULL);
/**
* @brief 执行校正算法
* @param dResX 输出图像横向分辨率,默认为0,表示自动计算输出象元大小
* @param dResY 输出图像纵向分辨率,默认为0,表示自动计算输出象元大小
* @param resampling 重采样方式,默认为双线性内插
* @return 是否计算成功,以及错误代码
*/
int DoGeoLocWarp(double dResX = 0.0, double dResY = 0.0, ResampleMethod resampling = RM_Bilinear);
private:
//输入参数
const char* m_pszSrcFile; /*! 原始数据路径 */
const char* m_pszDstFile; /*! 结果数据路径 */
const char* m_pszFormat; /*! 结果数据格式 */
CProcessBase* m_pProcess; /*! 进度条指针 */
ResampleMethod m_Resampling; /*! 重采样方式 */
string m_strWkt; /*! 输出文件投影串,这里只能是WGS84经纬度 */
};
#endif //IMAGEGEOLOCWARP_H
下面是源文件,主要是对gdalwarp.cpp进行了精简,去除了和geoloc无关的代码。
/***************************************************************************
*
* Time: 2013-03-02
* Project: 遥感处理算法
* Purpose: 地理查找表校正
* Author: 李民录
* Copyright (c) 2013, liminlu0314@gmail.com
* Describe: 地理查找表校正,用于HDF数据的校正算法
*
****************************************************************************/
#include "ImageGeoLocWarp.h"//上面的头文件
#include "ImageCommon.h"//这个头文件就是之前的那个使用gdal对数据进行管理的博客(用到的函数是删除临时文件)
#include "gdal_priv.h"
#include "gdalwarper.h"
#include "ogr_srs_api.h"
CImageGeoLocWarp::CImageGeoLocWarp(const char* pszSrcFile, const char* pszDstFile,
const char* pszFormat, CProcessBase* pProcess)
{
m_pszSrcFile = pszSrcFile; /*! 原始数据路径 */
m_pszDstFile = pszDstFile; /*! 结果数据路径 */
m_pszFormat = pszFormat; /*! 结果数据格式 */
m_pProcess = pProcess; /*! 进度条指针 */
m_Resampling = RM_Bilinear; /*! 重采样方式,默认为双线性 */
m_strWkt = SRS_WKT_WGS84; //投影只能是WGS84
}
CImageGeoLocWarp::~CImageGeoLocWarp()
{
}
int CImageGeoLocWarp::GetSuggestedWarpOutput(int &iHeight, int &iWidth, double *padfGeoTransform, double *padfExtent)
{
if(m_pszSrcFile == NULL || m_pszDstFile == NULL)
return RE_PARAMERROR;
GDALAllRegister();
GDALDatasetH hSrcDS = GDALOpen( m_pszSrcFile, GA_ReadOnly ); //打开文件
if(hSrcDS == NULL )
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("打开待纠正影像失败!");
return RE_FILENOTEXIST;
}
if(m_strWkt.empty()) //目标投影不存在
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("目标投影不存在!");
GDALClose( hSrcDS );
return RE_PARAMERROR;
}
// 创建坐标转换参数
char** papszWarpOptions = NULL;
papszWarpOptions = CSLSetNameValue( papszWarpOptions, "METHOD", "GEOLOC_ARRAY" );
papszWarpOptions = CSLSetNameValue( papszWarpOptions, "DST_SRS", m_strWkt.c_str() );
void *hTransformArg = GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszWarpOptions );
if(hTransformArg == NULL )
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("坐标转换参数错误!");
CSLDestroy( papszWarpOptions );
GDALClose( hSrcDS );
return RE_PARAMERROR;
}
GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg;
// 获取目标文件大小以及转换参数信息
double adfDstGeoTransform[6] = {0};
double adfExtent[4];
int nPixels = 0, nLines = 0;
CPLErr eErr = GDALSuggestedWarpOutput2( hSrcDS, psInfo->pfnTransform, hTransformArg,
adfDstGeoTransform, &nPixels, &nLines, adfExtent, 0 );
iWidth = nPixels;
iHeight = nLines;
if(padfGeoTransform != NULL)
memcpy(padfGeoTransform, adfDstGeoTransform, sizeof(double)*6);
if(padfExtent != NULL)
memcpy(padfExtent, adfExtent, sizeof(double)*4);
GDALDestroyGenImgProjTransformer(hTransformArg);
CSLDestroy( papszWarpOptions );
GDALClose( hSrcDS );
if(eErr != CE_None)
return RE_PARAMERROR;
else
return RE_SUCCESS;
}
int CImageGeoLocWarp::DoGeoLocWarp(double dResX, double dResY, ResampleMethod resampling)
{
m_Resampling = resampling;
if(m_pszSrcFile == NULL || m_pszDstFile == NULL)
return RE_PARAMERROR;
if(FileIsUsed(m_pszDstFile, m_pProcess))
return RE_FILEISUESED;
if(m_pProcess != NULL)
{
m_pProcess->ReSetProcess();
m_pProcess->SetMessage("正在执行影像地理校正...");
}
GDALAllRegister();
GDALDatasetH hSrcDS = GDALOpen( m_pszSrcFile, GA_ReadOnly ); //打开文件
if(hSrcDS == NULL )
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("打开待纠正影像失败!");
return RE_FILENOTEXIST;
}
if(m_strWkt.empty()) //目标投影不存在
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("目标投影不存在!");
GDALClose( hSrcDS );
return RE_PARAMERROR;
}
// 创建坐标转换参数
char** papszWarpOptions = NULL;
papszWarpOptions = CSLSetNameValue( papszWarpOptions, "METHOD", "GEOLOC_ARRAY" );
papszWarpOptions = CSLSetNameValue( papszWarpOptions, "DST_SRS", m_strWkt.c_str() );
void *hTransformArg = GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszWarpOptions );
if(hTransformArg == NULL )
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("坐标转换参数错误!");
CSLDestroy( papszWarpOptions );
GDALClose( hSrcDS );
return RE_PARAMERROR;
}
GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg;
// 获取目标文件大小以及转换参数信息
double adfDstGeoTransform[6] = {0};
double adfExtent[4];
int nPixels = 0, nLines = 0;
CPLErr eErr = GDALSuggestedWarpOutput2( hSrcDS, psInfo->pfnTransform, hTransformArg,
adfDstGeoTransform, &nPixels, &nLines, adfExtent, 0 );
if(eErr != CE_None)
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("获取目标文件大小以及转换参数信息错误!");
GDALDestroyGenImgProjTransformer(hTransformArg);
CSLDestroy( papszWarpOptions );
GDALClose( hSrcDS );
return RE_PARAMERROR;
}
// 如果用户指定了输出图像的分辨率
if ( dResX != 0.0 || dResY != 0.0 )
{
// 如果只指定了一个,使用自动计算的结果
if ( dResX == 0.0 ) dResX = adfDstGeoTransform[1];
if ( dResY == 0.0 ) dResY = adfDstGeoTransform[5];
// 确保分辨率符号正确
if ( dResX < 0.0 ) dResX = -dResX;
if ( dResY > 0.0 ) dResY = -dResY;
// 计算输出图像的范围
double minX = adfDstGeoTransform[0];
double maxX = adfDstGeoTransform[0] + adfDstGeoTransform[1] * nPixels;
double maxY = adfDstGeoTransform[3];
double minY = adfDstGeoTransform[3] + adfDstGeoTransform[5] * nLines;
// 按照用户指定的分辨率来计算图像的输出大小以及范围
nPixels = ( int )((( maxX - minX ) / dResX ) + 0.5 );
nLines = ( int )((( minY - maxY ) / dResY ) + 0.5 );
adfDstGeoTransform[0] = minX;
adfDstGeoTransform[3] = maxY;
adfDstGeoTransform[1] = dResX;
adfDstGeoTransform[5] = dResY;
}
// 获得波段数目
int nBandCount = GDALGetRasterCount(hSrcDS);
// 创建输出文件数据类型与源文件相同
GDALDataType eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDS, 1));
// 创建输出结果文件
GDALDriverH hDriver = GDALGetDriverByName( m_pszFormat);
if(hDriver == NULL )
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("不支持该种类型数据!");
GDALDestroyGenImgProjTransformer(hTransformArg);
CSLDestroy( papszWarpOptions );
GDALClose( hSrcDS );
return RE_FILENOTSUPPORT;
}
GDALDatasetH hDstDS = GDALCreate( hDriver, m_pszDstFile, nPixels, nLines, nBandCount, eDT, NULL );
if(hDstDS == NULL)
{
if(m_pProcess != NULL)
m_pProcess->SetMessage("创建输出文件失败!");
GDALDestroyGenImgProjTransformer(hTransformArg);
CSLDestroy( papszWarpOptions );
GDALClose( hSrcDS );
return RE_CREATEFAILED;
}
// 设置投影等信息
GDALSetProjection( hDstDS, m_strWkt.c_str() );
GDALSetGeoTransform( hDstDS, adfDstGeoTransform );
if (hTransformArg != NULL)
GDALSetGenImgProjTransformerDstGeoTransform( hTransformArg, adfDstGeoTransform);
// 逐个波段获取颜色表
GDALColorTableH hCT;
for (int i=1; i<=nBandCount; i++)//band从1开始算
{
hCT = GDALGetRasterColorTable( GDALGetRasterBand(hSrcDS, i) );
if( hCT != NULL )
GDALSetRasterColorTable( GDALGetRasterBand(hDstDS, i), hCT );
}
// 创建转换选项
CSLDestroy( papszWarpOptions ); //先释放之前的
papszWarpOptions = NULL;
papszWarpOptions = CSLSetNameValue(papszWarpOptions, "INIT_DEST", "0");
GDALTransformerFunc pfnTransformer = NULL;
pfnTransformer = GDALGenImgProjTransform; //坐标转换函数
GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();
psWarpOptions->papszWarpOptions = CSLDuplicate(papszWarpOptions);
psWarpOptions->hSrcDS = hSrcDS;
psWarpOptions->hDstDS = hDstDS;
psWarpOptions->nBandCount = nBandCount;
// 申请内存
psWarpOptions->panSrcBands = (int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
psWarpOptions->panDstBands = (int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
for (int j=0; j<nBandCount; j++)
{
psWarpOptions->panSrcBands[j] = j + 1;
psWarpOptions->panDstBands[j] = j + 1;
}
psWarpOptions->eResampleAlg = (GDALResampleAlg)resampling;
psWarpOptions->pfnProgress = ALGTermProgress; //进度条回调函数;
psWarpOptions->pProgressArg = m_pProcess; //进度条指针
psWarpOptions->papszWarpOptions = papszWarpOptions;
psWarpOptions->pfnTransformer = pfnTransformer;
psWarpOptions->pTransformerArg = hTransformArg;
CPLErr Err = CE_None;
GDALWarpOperation oOperation;
if( oOperation.Initialize( psWarpOptions ) == CE_None )
Err = oOperation.ChunkAndWarpImage( 0, 0, nPixels, nLines);
else
{
CSLDestroy( papszWarpOptions );
GDALDestroyGenImgProjTransformer( hTransformArg );
GDALClose( hDstDS );
GDALClose( hSrcDS );
RasterDelete(m_pszDstFile); //删除结果数据
return RE_FAILED;
}
CSLDestroy( papszWarpOptions );
GDALDestroyGenImgProjTransformer( hTransformArg );
GDALClose( hDstDS );
GDALClose( hSrcDS );
if (m_pProcess && !m_pProcess->m_bIsContinue)
{
RasterDelete(m_pszDstFile); //删除结果数据
return RE_USERCANCEL;
}
if (Err != CE_None)
return RE_FAILED;
return RE_SUCCESS;
}
调用代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <boost/progress.hpp> //boost计时函数
int main()
{
int iRev = RE_SUCCESS;
CConsoleProcess *pPro = new CConsoleProcess();
progress_timer *pTime = new progress_timer(); // 开始计时
// 对HDF数据中的一个字数据进行处理,下面分别是子数据集的路径和输出文件路径
const char* pszSrc = "HDF4_SDS:UNKNOWN:\"D:\\Data\\hdf\\H1BCLR101106020418636.L2C.HDF\":12";
const char* pszDst = "D:\\Data\\hdf\\H1BCLR101106020418636_12.tif";
CImageGeoLocWarp warp(pszSrc, pszDst, "HFA", pPro);
iRev = warp.DoGeoLocWarp(0.0, 0.0, RM_NearestNeighbour);
if(iRev == RE_SUCCESS)
printf("success!\n");
else
printf("failed!\n");
delete pPro;
delete pTime;
::system("pause");
return 0;
}
最后再说一下,代码中的返回值,RE_开头的去我之前的博客中去找,就是一些常量,用于标记返回的信息。还有那个进度条的类,也在我之前的博客都有说明的。上面的代码中用到的第三方库就是BOOST和GDAL,算法中只有GDAL一个,BOOST库只在main函数中用来计时用的。其他的在我之前的博客都有说明的。
不要指望把我的代码拿过去直接编译就能过去,那样的话,我觉得对你也没有啥进步。如果一个人看懂我的代码的话,那些不认识的函数也就大概能猜出是个啥意思了,自己写一个也很简单的。学习别人的代码,不要指望直接就能用,关键是还要看别人的思路,然后结合自己的项目(工程)来进行改造来达到自己的目的,这才是一种对自己有利的学习方式。废话有点多,觉得说的没道理的后面这些话就当没有吧。