由於公司基礎軟件一直缺乏影像校正能力,遂基於GDAL寫了一個小程序,可以做小數據的影像校正, 網上搜到的都是驟點校正,速度太慢,本程序使用全內存模式, 校正個幾個G的數據 的效率比原生GDAL提供的gdalWarp.exe還要快,主要代碼如下:
主要函數聲明:
int ImageWarpRCPorGCP2(GDALDatasetH hSrcDS,
const char * pszDstFile,
RasterWarpInfo & info,
int blockw = 256,
int blockh = 256,
int transtype = 0, /*0 RPC, 1 GCP*/
int iOrder = 0,
double dResX = 0.0,
double dResY = 0.0,
GDALRIOResampleAlg eResampleMethod = GRIORA_NearestNeighbour,
const char * pszFormat = "GTiff");
結構體聲明:
///\brief 柵格類基本信息
struct RasterWarpInfo
{
///\brief src X,Y維度範圍
double XYDomain[4] = {0};
///\brief dst X,Y維度範圍
double dstXYDomain[4] = { 0 };
///\brief src X,Y維度範圍
double Transform[6] = { 0 };
///\brief dst X,Y維度範圍
double dstTransform[6] = { 0 };
void* pGDALRPCorGCPTransform = 0;
///\brief 像素寬度
int Width =0;
///\brief 像素高度
int Height = 0;
///\brief 像素寬度
int dstWidth = 0;
///\brief 像素高度
int dstHeight = 0;
///\brief 數據存儲塊寬度大小
int BlockWidth = 0;
///\brief 數據存儲塊高度大小
int BlockHeight =0;
///\brief 波段數據類型
GDALDataType DataType = GDT_Byte;
///\brief 波段的名稱
std::vector<GDALColorInterp> BandTypes = {};;
//空間參考
char * srcRef = 0;;
char * dstRef = 0;;
int nPixelSize = 0;
std::vector<int> m_vBand = {};
};
主要實現:
/**
* @brief 影像幾何校正
* @param GDALDatasetH hSrcDS, 輸入數據集
* @param pszDstFile 輸出文件路徑
* @param RasterWarpInfo 校正信息
* @param int blockw ,分塊大小
* @param int blockh ,分塊大小
* @param int transtype,RPC或者GCP
* @param int iOrder,
* @param double dResX, 分辨率 目前爲原始分辨率
* @param double dResY 分辨率 目前爲原始分辨率
* @param
* @param eResampleMethod 重採樣方式
* @param @param pszFormat 輸出文件格式
* * @return 返回值,返回true或者false
* */
int CImageCorrectionDlg::ImageWarpRCPorGCP2(GDALDatasetH hSrcDS,
const char * pszDstFile,
RasterWarpInfo & info,
int blockw ,
int blockh ,
int transtype,
int iOrder,
double dResX,
double dResY,
GDALRIOResampleAlg eResampleMethod,
const char * pszFormat)
{
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
GDALDataType eDataType = info.DataType;
int nBandCount = info.BandTypes.size();
// 創建幾何多項式座標轉換關係
void *hTransform = info.pGDALRPCorGCPTransform;
if (NULL == hTransform)
{
GDALClose(hSrcDS);
return 0;
}
// 計算輸出圖像四至範圍、大小、仿射變換六參數等信息
double* adfGeoTransform = info.dstTransform;
double* adfExtent = info.dstXYDomain;
int nPixels = info.dstWidth, nLines = info.dstHeight;
// 以下開始依據用戶指定的分辨率來反算輸出圖像的大小和六參數等信息
//double dResXSize = dResX;
//double dResYSize = dResY;
//dResXSize = (info.dstTransform[1]);
//dResYSize = (info.dstTransform[5]);
// 計算輸出圖像的範圍
//double minX = adfGeoTransform[0];
//double maxX = adfGeoTransform[0] + adfGeoTransform[1] * nPixels;
//double maxY = adfGeoTransform[3];
//double minY = adfGeoTransform[3] + adfGeoTransform[5] * nLines;
//nPixels = ceil((maxX - minX) / dResXSize);
//nLines = abs(ceil((minY - maxY) / dResYSize));
//adfGeoTransform[0] = minX;
//adfGeoTransform[3] = maxY;
//adfGeoTransform[1] = dResXSize;
//adfGeoTransform[5] = dResYSize;
// 創建輸出圖像
GDALDriverH hDriver = GDALGetDriverByName(pszFormat);
if (NULL == hDriver)
{
::MessageBox(this->m_hWnd, _T("獲取驅動失敗"), _T("錯誤"),
MB_ICONERROR);
return 0;
}
GDALDatasetH hDstDS = GDALCreate(hDriver, pszDstFile, nPixels, nLines, nBandCount, eDataType, NULL);
if (NULL == hDstDS)
{
::MessageBox(this->m_hWnd, _T("創建目標文件失敗"), _T("錯誤"),
MB_ICONERROR);
return 0;
}
GDALDataset* gsDS = (GDALDataset*)hSrcDS;
char* pszWkt1 = (char*)gsDS->GetProjectionRef();
if (0 == strlen(pszWkt1))
{
pszWkt1 = (char*)gsDS->GetGCPProjection();
if (0 == strlen(pszWkt1))
{
pszWkt1 = "GEOGCS[\"GCS_WGS_1984\", DATUM[\"D_WGS_1984\", SPHEROID[\"WGS_1984\", 6378137, 298.257223563]], PRIMEM[\"Greenwich\", 0], UNIT[\"degree\", 0.0174532925199433]]";
}
}
GDALSetProjection(hDstDS, pszWkt1);
GDALSetGeoTransform(hDstDS, adfGeoTransform);// info.dstTransform);
//獲得原始圖像的行數和列數
int nXsize = GDALGetRasterXSize(hSrcDS);
int nYsize = GDALGetRasterYSize(hSrcDS);
//然後是圖像重採樣
int nFlag = 0;
float dfValue = 0;
CPLErr err = CE_Failure;
//進度
INIT_RASTERIO_EXTRA_ARG(m_Arg);
m_Arg.eResampleAlg = GRIORA_NearestNeighbour;
m_Arg.pfnProgress = RasterIOProgress;
//m_Arg.pProgressData = pClass;
long long srcLen = (long long)info.nPixelSize* info.Width * info.Height;
unsigned char* srcbuff = (unsigned char*)malloc(srcLen);
long long targetLen = (long long)info.nPixelSize * info.dstWidth* info.dstHeight;
unsigned char* tgbuff = (unsigned char*)malloc(targetLen);
memset(tgbuff, 0, sizeof(unsigned char));
GDALDataset* srcDS = (GDALDataset*)hSrcDS;
GDALDataset* tgDS = (GDALDataset*)hDstDS;
for (int i = 0; i < tgDS->GetRasterCount(); i++)
{
tgDS->GetRasterBand(i + 1)->SetNoDataValue(0.);
}
//直接讀取所有原始數據,
err = srcDS->RasterIO(GF_Read, 0, 0, info.Width, info.Height, srcbuff,
info.Width, info.Height, info.DataType, info.BandTypes.size(), &info.m_vBand[0],
info.nPixelSize, info.nPixelSize * info.Width,
info.nPixelSize / info.m_vBand.size(), &m_Arg);
//unsigned char* emptyvalue = (unsigned char*)malloc(info.nPixelSize*8);
//memset(emptyvalue, 0, info.nPixelSize * 8);
//遍歷目標像素值,給目標像素buff賦值
nPixels = info.dstWidth;
nLines = info.dstHeight;
#pragma omp parallel for
for (int nRow = 0; nRow < nLines; nRow++)
{
for (int nCol = 0; nCol < nPixels; nCol++)
{
double dbX = adfGeoTransform[0] + nCol * adfGeoTransform[1]
+ nRow * adfGeoTransform[2];
double dbY = adfGeoTransform[3] + nCol * adfGeoTransform[4]
+ nRow * adfGeoTransform[5];
//由輸出的圖像地理座標系變換到原始的像素座標系
if (0 == transtype)
GDALRPCTransform(hTransform, TRUE, 1, &dbX, &dbY, NULL, &nFlag);
else if (1 == transtype)
GDALGCPTransform(hTransform, TRUE, 1, &dbX, &dbY, NULL, &nFlag);
int nXCol = (int)(dbX );
int nYRow = (int)(dbY);
//超出範圍的用0填充
if (nXCol < 0 || nXCol >= nXsize || nYRow < 0 || nYRow >= nYsize)
{
int tmp = 0;
tgbuff[nRow * nPixels * info.nPixelSize + nCol* info.nPixelSize]=0;
}
else
{
memcpy(&tgbuff[nRow * nPixels * info.nPixelSize + nCol * info.nPixelSize],
&srcbuff[nYRow * nXsize * info.nPixelSize + nXCol * info.nPixelSize],
info.nPixelSize);
//memcpy(&tgbuff[nCol*nLines + nRow], &srcbuff[nXCol * nXsize + nYRow], sizeof(short)*4);
}
}
}
//free(emptyvalue);
//寫好的buff直接IO進文件
tgDS->RasterIO(GF_Write,0,0,info.dstWidth,info.dstHeight, tgbuff,
info.dstWidth, info.dstHeight, info.DataType, info.BandTypes.size(), &info.m_vBand[0],
info.nPixelSize, info.nPixelSize * info.dstWidth,
info.nPixelSize / info.m_vBand.size(), &m_Arg);
//err = tgDS->RasterIO(GF_Write, 0, 0, info.Width, info.Height, tgbuff,
// info.Width, info.Height, info.DataType, info.BandTypes.size(), &info.m_vBand[0],
// 0,0,0, &m_Arg);
if (hTransform != NULL)
{
GDALDestroyGCPTransformer(hTransform);
hTransform = NULL;
}
GDALClose(hSrcDS);
GDALClose(hDstDS);
return 1;
}
RasterWrapInfo 的獲取如下:
int CImageCorrectionDlg::ImageCorrection(const char * pszSrcFile, const char * pszDstFile)
{ //數據集。
GDALDataset* m_pDS = (GDALDataset *)GDALOpen(pszSrcFile, GA_Update);
if (m_pDS == NULL)
{
::MessageBox(this->m_hWnd, _T("打開文件失敗"), _T("錯誤"),
MB_ICONERROR);
return 0;
}
if (m_pDS == NULL)
return 0;
//獲取原始信息
m_pDS->GetGeoTransform(m_GeoTransform);
RasterWarpInfo srcInfo;
//memset(&srcInfo, 1, sizeof(srcInfo));
/// \brief 像素寬度
srcInfo.Width = m_pDS->GetRasterXSize();
/// \brief 像素高度
srcInfo.Height = m_pDS->GetRasterYSize();
for (int i = 0; i < m_pDS->GetRasterCount(); i++)
{
srcInfo.m_vBand.emplace_back(i + 1);
srcInfo.DataType = m_pDS->GetRasterBand(i + 1)->GetRasterDataType();
srcInfo.BandTypes.emplace_back(m_pDS->GetRasterBand(i + 1)->GetColorInterpretation());
m_pDS->GetRasterBand(i + 1)->GetBlockSize(&srcInfo.BlockWidth, &srcInfo.BlockHeight);
srcInfo.nPixelSize += GDALGetDataTypeSize(srcInfo.DataType);
}
srcInfo.nPixelSize /= 8;
char ** datalist = m_pDS->GetMetadataDomainList();
char** papszRPC = m_pDS->GetMetadata("RPC");
if (papszRPC)
{
GDALRPCInfo oInfo;
GDALExtractRPCInfo(papszRPC, &oInfo);
//設置RPC模型中所需的DEM路徑
char** papszTransOption = NULL;
double adfGeoTransform[6] = { 0 };
int nPixels = 0, nLines = 0;
//使用RPC信息,DEM等構造RPC轉換參數
m_pGDALRPCorGCPTransform = GDALCreateRPCTransformer(&oInfo, FALSE, 0, papszTransOption);
if (m_pGDALRPCorGCPTransform != NULL)
{
if (GDALSuggestedWarpOutput2(m_pDS, GDALRPCTransform/*GDALRPCTransform*/, m_pGDALRPCorGCPTransform,
m_RPCorGCPTransform, &m_nPixels, &m_nLines, m_adfExtent, 0) != CE_None)
{
GDALClose(m_pGDALRPCorGCPTransform);
return 0;
}
srcInfo.dstHeight = m_nLines;
srcInfo.dstWidth = m_nPixels;
memcpy(srcInfo.dstXYDomain, m_adfExtent, sizeof(double) * 4);
memcpy(srcInfo.dstTransform, m_RPCorGCPTransform, sizeof(double) * 6);
srcInfo.pGDALRPCorGCPTransform = m_pGDALRPCorGCPTransform;
}
int nGCPCount = m_pDS->GetGCPCount();
const GDAL_GCP *pGCPList = m_pDS->GetGCPs();
if (nGCPCount > 0)
{
m_pGDALRPCorGCPTransform = GDALCreateGCPTransformer(nGCPCount, pGCPList, 0, FALSE);
if (GDALSuggestedWarpOutput2(m_pDS, GDALGCPTransform, m_pGDALRPCorGCPTransform,
m_RPCorGCPTransform, &m_nPixels, &m_nLines, m_adfExtent, 0) != CE_None)
{
GDALClose(m_pDS);
return 0;
}
srcInfo.dstHeight = m_nLines;
srcInfo.dstWidth = m_nLines;
memcpy(srcInfo.dstXYDomain, m_adfExtent, sizeof(double) * 4);
memcpy(srcInfo.dstTransform, m_RPCorGCPTransform, sizeof(double) * 6);
srcInfo.pGDALRPCorGCPTransform = m_pGDALRPCorGCPTransform;
}
}
//如果沒有空間參考則讀取空間參考
const char*pSrsRef = m_pDS->GetProjectionRef();
char* pszWkt1 = (char*)m_pDS->GetGCPProjection();
//ImageWarpRCPorGCP(m_pDS, pszDstFile, srcInfo);
return ImageWarpRCPorGCP2(m_pDS, pszDstFile, srcInfo);
}
此程序未做分塊處理,分塊和這整塊也無太大區別, 因爲是測試程序,所以不做過多代碼優化,源碼下載請到我的資源下載,只不過是個mfc的測試 程序,代碼較亂,請理解