GDAL影像重採樣

#include "gdal_priv.h"
#include "ogrsf_frmts.h"
#include "gdalwarper.h"

/*** 
* 遙感影像重採樣	(要求影像必須有投影,否則走不通)
* @param pszSrcFile        輸入文件的路徑 
* @param pszOutFile        寫入的結果圖像的路徑 
* @param eResample		   採樣模式,有五種,具體參見GDALResampleAlg定義,默認爲雙線性內插 
* @param fResX             X轉換採樣比,默認大小爲1.0,大於1圖像變大,小於1表示圖像縮小。數值上等於採樣後圖像的寬度和採樣前圖像寬度的比 
* @param fResY             Y轉換採樣比,默認大小爲1.0,大於1圖像變大,小於1表示圖像縮小。數值上等於採樣後圖像的高度和採樣前圖像高度的比
* @retrieve		0	成功
* @retrieve		-1	打開源文件失敗
* @retrieve		-2	創建新文件失敗
* @retrieve		-3	處理過程中出錯
*/  
int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, float fResX = 1.0 ,float fResY  = 1.0,GDALResampleAlg eResample = GRA_Bilinear)  
{  
	GDALAllRegister();  
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");   
	GDALDataset *pDSrc = (GDALDataset *)GDALOpen(pszSrcFile, GA_ReadOnly);  
	if (pDSrc == NULL)  
	{  
		return -1;  
	}  

	GDALDriver *pDriver = GetGDALDriverManager()->GetDriverByName("GTiff");  
	if (pDriver == NULL)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		return -2;  
	}  
	int width=pDSrc->GetRasterXSize();  
	int height=pDSrc->GetRasterYSize();
	int nBandCount = pDSrc->GetRasterCount();   
	GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType();  

	char *pszSrcWKT = NULL;
	pszSrcWKT = const_cast<char *>(pDSrc->GetProjectionRef());
	
	//如果沒有投影,人爲設置一個  
	if(strlen(pszSrcWKT)<=0)
	{
		OGRSpatialReference oSRS;
		oSRS.SetUTM(50,true);	//北半球  東經120度
		oSRS.SetWellKnownGeogCS("WGS84");
		oSRS.exportToWkt(&pszSrcWKT);
	}

	void *hTransformArg;
	hTransformArg = GDALCreateGenImgProjTransformer((GDALDatasetH) pDSrc,pszSrcWKT,NULL,pszSrcWKT,FALSE,0.0,1);

	//(沒有投影的影像到這裏就走不通了)
	if (hTransformArg == NULL)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		return -3;  
	}

	double dGeoTrans[6] = {0};  
	int nNewWidth=0,nNewHeight=0;
	if(GDALSuggestedWarpOutput((GDALDatasetH)pDSrc,GDALGenImgProjTransform,hTransformArg,dGeoTrans,&nNewWidth,&nNewHeight)!=CE_None)
	{
		GDALClose((GDALDatasetH) pDSrc);  
		return -3; 
	}

	GDALDestroyGenImgProjTransformer(hTransformArg);

	//adfGeoTransform[0] /* top left x */
	//adfGeoTransform[1] /* w-e pixel resolution */
	//adfGeoTransform[2] /* rotation, 0 if image is "north up" */
	//adfGeoTransform[3] /* top left y */
	//adfGeoTransform[4] /* rotation, 0 if image is "north up" */
	//adfGeoTransform[5] /* n-s pixel resolution */

	dGeoTrans[1] = dGeoTrans[1] / fResX;
	dGeoTrans[5] = dGeoTrans[5] / fResY;
	nNewWidth = static_cast<int>(nNewWidth*fResX+0.5);
	nNewHeight = static_cast<int>(nNewHeight*fResY+0.5);

	//創建結果數據集
	GDALDataset *pDDst = pDriver->Create(pszOutFile, nNewWidth, nNewHeight, nBandCount, dataType, NULL);  
	if (pDDst == NULL)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		return -2;  
	}  
	
	pDDst->SetProjection(pszSrcWKT);  
	pDDst->SetGeoTransform(dGeoTrans);     
 
	GDALWarpOptions *psWo = GDALCreateWarpOptions();  

	//psWo->papszWarpOptions = CSLDuplicate(NULL);  
	psWo->eWorkingDataType = dataType;  
	psWo->eResampleAlg = eResample;  

	psWo->hSrcDS = (GDALDatasetH) pDSrc;  
	psWo->hDstDS = (GDALDatasetH) pDDst;  

	psWo->pfnTransformer = GDALGenImgProjTransform;  
	psWo->pTransformerArg = GDALCreateGenImgProjTransformer((GDALDatasetH) pDSrc,pszSrcWKT,(GDALDatasetH) pDDst,pszSrcWKT,FALSE,0.0,1);;  

	psWo->nBandCount = nBandCount;  
	psWo->panSrcBands = (int *) CPLMalloc(nBandCount*sizeof(int));  
	psWo->panDstBands = (int *) CPLMalloc(nBandCount*sizeof(int));  
	for (int i=0; i<nBandCount; i++)  
	{  
		psWo->panSrcBands[i] = i+1;  
		psWo->panDstBands[i] = i+1; 
	}   

	GDALWarpOperation oWo;  
	if (oWo.Initialize(psWo) != CE_None)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		GDALClose((GDALDatasetH) pDDst);  
		return -3;  
	}  

	oWo.ChunkAndWarpImage(0, 0, nNewWidth, nNewHeight);  
	GDALFlushCache( pDDst );

	GDALDestroyGenImgProjTransformer(psWo->pTransformerArg);  
	GDALDestroyWarpOptions( psWo ); 	
	GDALClose((GDALDatasetH) pDSrc);  
	GDALClose((GDALDatasetH) pDDst);  

	return 0;  
} 
用法示例:
	ResampleGDAL("F:\\Work\\\\數據\\spline.tif",
		"F:\\Work\\數據\\Resample_Lanczos.tif",GRA_Lanczos,10,10);

	ResampleGDAL("F:\\Work\\數據\\test.tif",
		"F:\\Work\\數據\\Resample3.tif",GRA_Lanczos,3,3);
缺陷:沒有投影就不能重採樣,關鍵點在於:GDALCreateGenImgProjTransformer取到的是null,根據gdal源代碼,如果沒有投影,dGeoTrans[] = {0,1,0,0,0,1},這個時候GDALCreateGenImgProjTransformer就返回null,因此可以將dGeoTrans[0]或dGeoTrans[3]設置爲非0,這樣GDALCreateGenImgProjTransformer就不返回null了。
改進:
/*** 
* 遙感影像重採樣
* @param pszSrcFile        輸入文件的路徑 
* @param pszOutFile        寫入的結果圖像的路徑 
* @param eResample		   採樣模式,有五種,具體參見GDALResampleAlg定義,默認爲雙線性內插 
							GRA_NearestNeighbour=0		最近鄰法,算法簡單並能保持原光譜信息不變;缺點是幾何精度差,灰度不連續,邊緣會出現鋸齒狀	
							GRA_Bilinear=1				雙線性法,計算簡單,圖像灰度具有連續性且採樣精度比較精確;缺點是會喪失細節;
							GRA_Cubic=2					三次卷積法,計算量大,圖像灰度具有連續性且採樣精度高;
							GRA_CubicSpline=3			三次樣條法,灰度連續性和採樣精度最佳;
							GRA_Lanczos=4				分塊蘭索斯法,由匈牙利數學家、物理學家蘭索斯法創立,實驗發現效果和雙線性接近;
* @param fResX             X轉換採樣比,默認大小爲1.0,大於1圖像變大,小於1表示圖像縮小。數值上等於採樣後圖像的寬度和採樣前圖像寬度的比 
* @param fResY             Y轉換採樣比,默認大小爲1.0,大於1圖像變大,小於1表示圖像縮小。數值上等於採樣後圖像的高度和採樣前圖像高度的比
* @retrieve		0	成功
* @retrieve		-1	打開源文件失敗
* @retrieve		-2	創建新文件失敗
* @retrieve		-3	處理過程中出錯
*/  
int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, float fResX = 1.0 ,float fResY  = 1.0,GDALResampleAlg eResample = GRA_Bilinear)  
{  
	GDALAllRegister();  
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");   
	GDALDataset *pDSrc = (GDALDataset *)GDALOpen(pszSrcFile, GA_ReadOnly);  
	if (pDSrc == NULL)  
	{  
		return -1;  
	}  


	GDALDriver *pDriver = GetGDALDriverManager()->GetDriverByName("GTiff");  
	if (pDriver == NULL)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		return -2;  
	}  
	int width=pDSrc->GetRasterXSize();  
	int height=pDSrc->GetRasterYSize();
	int nBandCount = pDSrc->GetRasterCount();   
	GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType();  


	char *pszSrcWKT = NULL;
	pszSrcWKT = const_cast<char *>(pDSrc->GetProjectionRef());


	double dGeoTrans[6] = {0};  
	int nNewWidth=width,nNewHeight=height;
	pDSrc->GetGeoTransform(dGeoTrans); 


	bool bNoGeoRef = false;
	double dOldGeoTrans0 = dGeoTrans[0];
	//如果沒有投影,人爲設置一個  
	if(strlen(pszSrcWKT)<=0)
	{
		//OGRSpatialReference oSRS;
		//oSRS.SetUTM(50,true);	//北半球  東經120度
		//oSRS.SetWellKnownGeogCS("WGS84");
		//oSRS.exportToWkt(&pszSrcWKT);
		//pDSrc->SetProjection(pszSrcWKT);


		//////////////////////////////////////////////////////////////////////////
		dGeoTrans[0]=1.0;
		pDSrc->SetGeoTransform(dGeoTrans);
		//////////////////////////////////////////////////////////////////////////


		bNoGeoRef = true;
	}	


	//adfGeoTransform[0] /* top left x */
	//adfGeoTransform[1] /* w-e pixel resolution */
	//adfGeoTransform[2] /* rotation, 0 if image is "north up" */
	//adfGeoTransform[3] /* top left y */
	//adfGeoTransform[4] /* rotation, 0 if image is "north up" */
	//adfGeoTransform[5] /* n-s pixel resolution */


	dGeoTrans[1] = dGeoTrans[1] / fResX;
	dGeoTrans[5] = dGeoTrans[5] / fResY;
	nNewWidth = static_cast<int>(nNewWidth*fResX+0.5);
	nNewHeight = static_cast<int>(nNewHeight*fResY+0.5);


	//創建結果數據集
	GDALDataset *pDDst = pDriver->Create(pszOutFile, nNewWidth, nNewHeight, nBandCount, dataType, NULL);  
	if (pDDst == NULL)  
	{  	
		GDALClose((GDALDatasetH) pDSrc);  
		return -2;  
	}  
	
	pDDst->SetProjection(pszSrcWKT);  
	pDDst->SetGeoTransform(dGeoTrans);     


	void *hTransformArg = NULL;
	hTransformArg = GDALCreateGenImgProjTransformer2((GDALDatasetH) pDSrc, (GDALDatasetH) pDDst, NULL); //GDALCreateGenImgProjTransformer((GDALDatasetH) pDSrc,pszSrcWKT,(GDALDatasetH) pDDst,pszSrcWKT,FALSE,0.0,1);


	if (hTransformArg == NULL)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		GDALClose((GDALDatasetH) pDDst);  
		return -3;  
	}
 
	GDALWarpOptions *psWo = GDALCreateWarpOptions();  


	psWo->papszWarpOptions = CSLDuplicate(NULL);  
	psWo->eWorkingDataType = dataType;  
	psWo->eResampleAlg = eResample;  


	psWo->hSrcDS = (GDALDatasetH) pDSrc;  
	psWo->hDstDS = (GDALDatasetH) pDDst;  


	psWo->pfnTransformer = GDALGenImgProjTransform;  
	psWo->pTransformerArg = hTransformArg;


	psWo->nBandCount = nBandCount;  
	psWo->panSrcBands = (int *) CPLMalloc(nBandCount*sizeof(int));  
	psWo->panDstBands = (int *) CPLMalloc(nBandCount*sizeof(int));  
	for (int i=0; i<nBandCount; i++)  
	{  
		psWo->panSrcBands[i] = i+1;  
		psWo->panDstBands[i] = i+1; 
	}   


	GDALWarpOperation oWo;  
	if (oWo.Initialize(psWo) != CE_None)  
	{  
		GDALClose((GDALDatasetH) pDSrc);  
		GDALClose((GDALDatasetH) pDDst);  
		return -3;  
	}  


	oWo.ChunkAndWarpImage(0, 0, nNewWidth, nNewHeight); 


	GDALDestroyGenImgProjTransformer(hTransformArg);  
	GDALDestroyWarpOptions( psWo ); 	
	if(bNoGeoRef) 
	{
		dGeoTrans[0]=dOldGeoTrans0;
		pDDst->SetGeoTransform(dGeoTrans);	
		//pDDst->SetProjection("");
	} 
	GDALFlushCache( pDDst );
	GDALClose((GDALDatasetH) pDSrc);  
	GDALClose((GDALDatasetH) pDDst);  


	return 0;  
} 

改進後:沒有投影也可以過去,但是如果沒有投影,輸出結果會自動帶上一個投影,並且這個投影信息去不掉。

發佈了59 篇原創文章 · 獲贊 58 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章