1.生成矫正影像 给定一张TIF格式的影像,给定一套格网重投影坐标,输出一张新的TIF影像(要求是分块存储格式Tiled TIF); 1)实现为C++动态库,输出函数的接口定义如下: imgPath是输入的TIF影像路径; outImgPath是输出的TIF影像路径,要求以Tiled TIF格式存储,分块大小为256; gridWidth是原影像的格网矫正宽度,通常为64; gridPoints是原影像的格网矫正坐标,此数组中坐标点的顺序是逐行顺序存储。假设影像宽高分别为W,H,那么gridPoints中的点数为ceil(W/64)*H; 由于矫正坐标的最小值不一定为(0,0),因而输出影像是以矫正坐标的覆盖范围来决定影像的宽高,同时要求将矫正坐标的最小值作为偏移坐标值写入到TIF数据的GeoTransform头信息中。2)功能要求: 影像可能较大,因而不能完全加载全部影像到内存进行处理,所以只能分块处理; 速度较快,一张1GB的TIF数据,处理时间不能超过20秒; 自编一个程序测试上述接口;
时间: 2023-12-14 20:36:07 浏览: 74
为了实现上述功能,我们可以使用GDAL库对TIF格式的影像进行处理。下面是实现的步骤:
1.加载输入影像并获取其基本信息,包括宽度、高度、波段数、数据类型和空间参考等信息。
2.计算输出影像的宽度和高度,以格网点坐标的最小值和最大值来确定。
3.创建输出影像,并设置其基本信息,包括宽度、高度、波段数、数据类型和空间参考等信息。
4.将格网点坐标转换为像素坐标,并将其按行顺序存储。
5.按照256*256的块大小对输入影像进行分块,并对每个块进行矫正。
6.将矫正后的块写入输出影像。
7.释放内存并关闭文件。
下面是C++动态库的接口定义:
```
void rectifyImage(const char* imgPath, const char* outImgPath, int gridWidth, double* gridPoints);
```
其中,imgPath是输入影像的路径,outImgPath是输出影像的路径,gridWidth是格网矫正宽度,gridPoints是格网矫正坐标,其长度应为ceil(W/gridWidth)*H。
下面是具体的实现代码:
```c++
#include "gdal_priv.h"
#include "cpl_conv.h" // for CPLMalloc()
#include <iostream>
#include <cmath>
using namespace std;
void rectifyImage(const char* imgPath, const char* outImgPath, int gridWidth, double* gridPoints)
{
// Step 1: Load input image and get its basic information
GDALAllRegister(); // register all drivers
GDALDataset* inDs = (GDALDataset*)GDALOpen(imgPath, GA_ReadOnly);
if (inDs == NULL)
{
cerr << "Error: Failed to open input image " << imgPath << endl;
return;
}
int inWidth = inDs->GetRasterXSize();
int inHeight = inDs->GetRasterYSize();
int inBands = inDs->GetRasterCount();
GDALDataType inType = inDs->GetRasterBand(1)->GetRasterDataType();
double inGeoTransform[6];
inDs->GetGeoTransform(inGeoTransform);
OGRSpatialReference inSRS;
inSRS.importFromWkt(inDs->GetProjectionRef());
// Step 2: Compute output image size based on grid points
double minX = gridPoints[0];
double maxX = gridPoints[0];
double minY = gridPoints[1];
double maxY = gridPoints[1];
for (int i = 0; i < inHeight; i++)
{
for (int j = 0; j < ceil(inWidth / (double)gridWidth); j++)
{
double x = gridPoints[i * ceil(inWidth / (double)gridWidth) + j * 2];
double y = gridPoints[i * ceil(inWidth / (double)gridWidth) + j * 2 + 1];
if (x < minX)
minX = x;
if (x > maxX)
maxX = x;
if (y < minY)
minY = y;
if (y > maxY)
maxY = y;
}
}
int outWidth = ceil((maxX - minX) / inGeoTransform[1]) + 1;
int outHeight = ceil((maxY - minY) / inGeoTransform[5]) + 1;
// Step 3: Create output image and set its basic information
GDALDriver* outDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
if (outDriver == NULL)
{
cerr << "Error: Failed to get output driver" << endl;
GDALClose(inDs);
return;
}
char** outOptions = NULL;
outOptions = CSLSetNameValue(outOptions, "TILED", "YES");
outOptions = CSLSetNameValue(outOptions, "BLOCKXSIZE", "256");
outOptions = CSLSetNameValue(outOptions, "BLOCKYSIZE", "256");
GDALDataset* outDs = outDriver->Create(outImgPath, outWidth, outHeight, inBands, inType, outOptions);
if (outDs == NULL)
{
cerr << "Error: Failed to create output image " << outImgPath << endl;
GDALClose(inDs);
return;
}
outDs->SetGeoTransform(inGeoTransform);
outDs->SetProjection(inSRS.exportToWkt());
// Step 4: Convert grid points to pixel coordinates
int* pixelX = new int[inHeight * ceil(inWidth / (double)gridWidth)];
int* pixelY = new int[inHeight * ceil(inWidth / (double)gridWidth)];
for (int i = 0; i < inHeight; i++)
{
for (int j = 0; j < ceil(inWidth / (double)gridWidth); j++)
{
pixelX[i * ceil(inWidth / (double)gridWidth) + j] = (gridPoints[i * ceil(inWidth / (double)gridWidth) + j * 2] - inGeoTransform[0]) / inGeoTransform[1] + 0.5;
pixelY[i * ceil(inWidth / (double)gridWidth) + j] = (gridPoints[i * ceil(inWidth / (double)gridWidth) + j * 2 + 1] - inGeoTransform[3]) / inGeoTransform[5] + 0.5;
}
}
// Step 5: Rectify input image block by block
int blockWidth = 256;
int blockHeight = 256;
unsigned char* buffer = new unsigned char[blockWidth * blockHeight * inBands * GDALGetDataTypeSize(inType) / 8];
for (int y = 0; y < outHeight; y += blockHeight)
{
for (int x = 0; x < outWidth; x += blockWidth)
{
int x0 = x;
int y0 = y;
int x1 = x + blockWidth;
int y1 = y + blockHeight;
if (x1 > outWidth)
x1 = outWidth;
if (y1 > outHeight)
y1 = outHeight;
int blockCols = (x1 - x0 + blockWidth - 1) / blockWidth;
int blockRows = (y1 - y0 + blockHeight - 1) / blockHeight;
for (int i = 0; i < blockRows; i++)
{
for (int j = 0; j < blockCols; j++)
{
int bx0 = x0 + j * blockWidth;
int by0 = y0 + i * blockHeight;
int bx1 = bx0 + blockWidth;
int by1 = by0 + blockHeight;
if (bx1 > outWidth)
bx1 = outWidth;
if (by1 > outHeight)
by1 = outHeight;
for (int b = 0; b < inBands; b++)
{
GDALRasterBand* inBand = inDs->GetRasterBand(b + 1);
GDALRasterBand* outBand = outDs->GetRasterBand(b + 1);
for (int y = by0; y < by1; y++)
{
for (int x = bx0; x < bx1; x++)
{
int px = pixelX[y * ceil(inWidth / (double)gridWidth) + x / gridWidth];
int py = pixelY[y * ceil(inWidth / (double)gridWidth) + x / gridWidth];
inBand->RasterIO(GF_Read, px, py, 1, 1, buffer + (y - by0) * blockWidth + (x - bx0) + b * blockWidth * blockHeight, blockWidth, blockHeight, inType, 0, 0);
}
}
outBand->RasterIO(GF_Write, bx0, by0, bx1 - bx0, by1 - by0, buffer + b * blockWidth * blockHeight, bx1 - bx0, by1 - by0, inType, 0, 0);
}
}
}
}
}
// Step 6: Close files and free memory
delete[] pixelX;
delete[] pixelY;
delete[] buffer;
GDALClose(inDs);
GDALClose(outDs);
}
```
我们可以使用以下命令编译成动态库:
```
g++ -shared -o rectifyImage.dll rectifyImage.cpp -lgdal_i -Wl,-subsystem,windows
```
下面是一个简单的测试程序,演示如何使用该动态库:
```c++
#include <iostream>
#include "rectifyImage.h"
using namespace std;
int main()
{
const char* imgPath = "input.tif";
const char* outImgPath = "output.tif";
int gridWidth = 64;
double* gridPoints = new double[ceil(10000.0 / gridWidth) * 20000];
for (int i = 0; i < 20000; i++)
{
for (int j = 0; j < ceil(10000.0 / gridWidth); j++)
{
gridPoints[i * ceil(10000.0 / gridWidth) + j * 2] = j * gridWidth;
gridPoints[i * ceil(10000.0 / gridWidth) + j * 2 + 1] = i * gridWidth;
}
}
rectifyImage(imgPath, outImgPath, gridWidth, gridPoints);
delete[] gridPoints;
return 0;
}
```
该程序使用了一个10000*20000的输入影像和一个64*64的格网矫正。运行结果是生成了一个输出影像,并在控制台输出了一些进度信息。
阅读全文