1. 程式人生 > >改動GDAL庫支持RPC像方改正模型

改動GDAL庫支持RPC像方改正模型

src 經緯度坐標 token create 校正 slc ons ogr parameter

近期在做基於RPC的像方改正模型。方便對數據進行測試,改動了GDAL庫中的RPC糾正模型,使之能夠支持RPC像方改正參數。

以下是RPC模型的公式,rn,cn為歸一化之後的圖像行列號坐標,PLH為歸一化後的經度緯度高程。

技術分享

將上面的公式變形,使用偏移系數和縮放系數帶入,能夠得到圖像的行列號坐標與經緯度坐標之間的坐標轉換關系。整理後的公式例如以下所看到的。下標帶s的為縮放系數,下標為0的表示偏移系數,rc為圖像行列號,此處的PLH為地面經緯度坐標。P1~P4為有理函數的多項式系數。

技術分享

使用像方改正模型的公式例如以下所看到的,Line和Sample為圖像的行列號,rc為通過RPC模型將地面點經緯度高程計算得到的行列號,deltaR和DeltaC為像方改正數。

技術分享

deltaR和DeltaC像方改正數使用仿射變換模型,詳細公式例如以下,A0~A2為行方向的改正系數,B0~B2為列方向改正系數。無改正時這六個系數均為0.

技術分享

將上面兩個公式合並之後,再將DeltaR和DeltaC移向等式坐標,合並同類項之後。就得到了終於的一個仿射變換系數。此時無改正時。六個系數變為0 1 0 0 0 1。該系數為以下是用的終於系數。

改動的代碼非常少,在GDAL源代碼中的alg目錄裏面的gdal_rpc.cpp中,詳細改動三處地方。

第一處。GDALRPCTransformInfo結構體,在結構體中添加兩個double [6]的數組。用於保存RPC像方改正系數。

改動後的代碼例如以下。最後兩個參數adfAffineTransform和adfReverseAffineTransform分別表示RPC像方改正系數及其逆變換系數。

typedef struct {

    GDALTransformerInfo sTI;

    GDALRPCInfo sRPC;

    double      adfPLToLatLongGeoTransform[6];

    int         bReversed;

    double      dfPixErrThreshold;

    double      dfHeightOffset;

    double      dfHeightScale;

    char        *pszDEMPath;

    DEMResampleAlg eResampleAlg;

    int         bHasTriedOpeningDS;
    GDALDataset *poDS;

    OGRCoordinateTransformation *poCT;

    double      adfGeoTransform[6];
    double      adfReverseGeoTransform[6];

	double		adfAffineTransform[6];	//RPC adjustment affine transform
	double		adfReverseAffineTransform[6];	//RPC adjustment reverse affine transform
} GDALRPCTransformInfo;
第二處。在函數GDALCreateRPCTransformer()中,主要是將參數papszOptions中的像方改正系數進行解析,然後給結構體中新加的兩個數組賦值。

便於興許進行坐標轉換的時候使用。改動後的代碼例如以下,因為代碼太長,僅僅貼出我改動的部分代碼。以下代碼中The Affine transform parameters部分的代碼由我新加,主要是通過一個RPC_AFFINE來指定像方改正的六個系數,六個系數中間用空格隔開。然後將解析後的六個系數計算逆變換系數。默認系數是0 1 0 0 0 1,表示不進行像方改正。

//前面的代碼省略
/* -------------------------------------------------------------------- */
/*                      The DEM interpolation                           */
/* -------------------------------------------------------------------- */
    const char *pszDEMInterpolation = CSLFetchNameValueDef( papszOptions, "RPC_DEMINTERPOLATION", "bilinear" );
    if(EQUAL(pszDEMInterpolation, "near" ))
        psTransform->eResampleAlg = DRA_NearestNeighbour;
    else if(EQUAL(pszDEMInterpolation, "bilinear" ))
        psTransform->eResampleAlg = DRA_Bilinear;
    else if(EQUAL(pszDEMInterpolation, "cubic" ))
        psTransform->eResampleAlg = DRA_Cubic;
    else
        psTransform->eResampleAlg = DRA_Bilinear;
       
/* -------------------------------------------------------------------- */
/*                     The Affine transform parameters                  */
/* -------------------------------------------------------------------- */
	const char *pszRpcAffine = CSLFetchNameValueDef( papszOptions, "RPC_AFFINE", "0 1 0 0 0 1" );
	if(pszRpcAffine != NULL)	//解析RPC像方改正仿射變換參數
	{
		char** papszTokens = CSLTokenizeString2( pszRpcAffine, " ", 0 );
		int nTokens = CSLCount(papszTokens);
		if(nTokens == 6)	//must be 6
		{
			for (int i=0; i<6; i++)
				psTransform->adfAffineTransform[i] = atof(papszTokens[i]);
		}
		else
		{
			psTransform->adfAffineTransform[1] = 1;
			psTransform->adfAffineTransform[5] = 1;
		}

		GDALInvGeoTransform( psTransform->adfAffineTransform, psTransform->adfReverseAffineTransform );
		CSLDestroy(papszTokens);
	}

/* -------------------------------------------------------------------- */
/*      Establish a reference point for calcualating an affine          */
/*      geotransform approximate transformation.                        */
/* -------------------------------------------------------------------- */
//後面的代碼省略
第三處改動的地方就是在進行坐標轉換的函數中。即函數GDALRPCTransform()中,這裏面主要改動兩部分。第一個部分就是坐標正變換的時候,第二個是坐標逆變換的時候,在坐標正變換的時候,也就是從經緯度坐標換算到原始圖像行列號坐標時,等使用RPC模型轉換完畢後。再使用仿射變換的逆變換系數進行改正。在坐標逆變換的時候,也就是從原始圖像行列號換算到經緯度坐標時,先使用仿射變換的正變換系數進行改正,然後將改正後的行列號帶入RPC模型進行轉換到經緯度。改動的代碼就兩行。可是原始的代碼太多。就貼出來我新增的部分。

//此處是坐標正變換的時候新增的代碼
	GDALApplyGeoTransform(psTransform->adfReverseAffineTransform, padfX[i], padfY[i], padfX + i, padfY + i );
	panSuccess[i] = TRUE;

//此處是坐標逆變換的時候新增的代碼
	GDALApplyGeoTransform(psTransform->adfAffineTransform, padfX[i], padfY[i], padfX + i, padfY + i );
        double dfResultX, dfResultY;
改動完之後,保存,然後又一次編譯GDAL庫就可以。

之後我們就能夠使用gdalwarp.exe這個超牛的工具來進行校正了。詳細的命令就是在原來使用-rpc的命令基礎上,添加一個-to “RPC_AFFINE=0 1 0 0 0 1”就可以。當然這六個系數須要自己敲代碼使用控制點來進行反算,僅僅要三個控制點就可以,使用1個或兩個控制點僅僅能計算一個平移模型,即上面公式中的A0和B0。完整的命令行為:

gdalwarp.exe -rpc -to "RPC_AFFINE=-32.714672501057066 0.999199897235577 0.000158731686899 28.720843336473692 0.000589585516339 1.000068008511035" D:\rpctest\banda.tif D:\rpctest\banda_affine.tif

改動GDAL庫支持RPC像方改正模型