zoukankan      html  css  js  c++  java
  • 使用GDAL对HDF数据进行geoloc校正

    在上一篇博客中,大概说了下怎么使用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函数中用来计时用的。其他的在我之前的博客都有说明的。

    不要指望把我的代码拿过去直接编译就能过去,那样的话,我觉得对你也没有啥进步。如果一个人看懂我的代码的话,那些不认识的函数也就大概能猜出是个啥意思了,自己写一个也很简单的。学习别人的代码,不要指望直接就能用,关键是还要看别人的思路,然后结合自己的项目(工程)来进行改造来达到自己的目的,这才是一种对自己有利的学习方式。废话有点多,觉得说的没道理的后面这些话就当没有吧。

  • 相关阅读:
    Tomcat修改端口号
    如何修改localhost为自己指定的域名
    Tomcat启动时启动窗口中文乱码问题的解决方案
    Java Web 项目jsp页面无法加载样式
    vue 父传子(通过属性传递)
    vue 父传子 讲解
    表白小爱心
    响应式开发
    组件的重复调用
    reduce
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6313974.html
Copyright © 2011-2022 走看看