9.将数组存储为带坐标的tif文件

1 将numpy数组存储为带坐标的tif文件

将numpy数组存储为带坐标的tif文件
def write_img(read_path, img_array):
    """
    read_path:原始文件路径
    img_array:numpy数组, 数组形状必须是(4, 36786, 37239) ,波段,行,列
    """
    read_pre_dataset = gdal.Open(read_path)
    img_transf = read_pre_dataset.GetGeoTransform()  # 仿射矩阵
    img_proj = read_pre_dataset.GetProjection()  # 地图投影信息
    print("1读取数组形状", img_array.shape,img_array.dtype.name) # (4, 36786, 37239)

    # GDT_Byte = 1, GDT_UInt16 = 2, GDT_UInt32 = 4, GDT_Int32 = 5, GDT_Float32 = 6,
    if 'uint8' in img_array.dtype.name:
        datatype = gdal.GDT_Byte
    elif 'int16' in img_array.dtype.name:
        datatype = gdal.GDT_UInt16
    else:
        datatype = gdal.GDT_Float32

    if len(img_array.shape) == 3:
        img_bands, im_height, im_width = img_array.shape
    else:
        img_bands, (im_height, im_width) = 1, img_array.shape

    filename = read_path[:-4] + '_unit8' + ".tif"
    driver = gdal.GetDriverByName("GTiff")  # 创建文件驱动
    # 注意这里先写宽再写高,对应数组的高和宽,这里不对应才对
    # https://vimsky.com/examples/detail/python-method-gdal.GetDriverByName.html
    dataset = driver.Create(filename, im_width, im_height, img_bands, datatype)
    dataset.SetGeoTransform(img_transf)  # 写入仿射变换参数
    dataset.SetProjection(img_proj)  # 写入投影

    # 写入影像数据
    if img_bands == 1:
        dataset.GetRasterBand(1).WriteArray(img_array)
    else:
        for i in range(img_bands):
            dataset.GetRasterBand(i + 1).WriteArray(img_array[i])
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是C++动态库的接口定义: ```cpp /** * 生成矫正影像 * * @param imgPath 输入的TIF影像路径 * @param outImgPath 输出的TIF影像路径,要求以Tiled TIF格式存储,分块大小为256 * @param gridWidth 原影像的格网矫正宽度,通常为64 * @param gridPoints 原影像的格网矫正坐标,此数组坐标点的顺序是逐行顺序存储。假设影像宽高分别为W,H,那么gridPoints中的点数为ceil(W/64)*H * @return true表示成功,false表示失败 */ bool generateCorrectedImage(const std::string& imgPath, const std::string& outImgPath, int gridWidth, const std::vector<cv::Point2f>& gridPoints); ``` 实现思路: 1. 打开输入影像,读取影像的宽度和高度。 2. 根据输入的格网矫正宽度和影像宽度计算出格网行数。 3. 构建一个二维数组,表示格网点的坐标。 4. 遍历格网点的坐标,计算出每个格网单元的仿射变换矩阵,并将其存储到一个 vector 中。 5. 打开输出影像,设置影像的宽度、高度、波段数和数据类型,设置 GeoTransform 信息,并创建 Tiled TIF 文件。 6. 分块处理,对每个块进行矫正,将矫正后的块写入输出影像中。 7. 关闭输入和输出影像。 以下是实现的代码: ```cpp #include <iostream> #include <vector> #include <opencv2/opencv.hpp> #include <gdal_priv.h> #include <cpl_conv.h> // 定义分块大小 const int TILE_SIZE = 256; // 生成仿射变换矩阵 cv::Mat getAffineTransformMatrix(const std::vector<cv::Point2f>& srcPoints, const std::vector<cv::Point2f>& dstPoints) { cv::Mat srcMat = cv::Mat(srcPoints); cv::Mat dstMat = cv::Mat(dstPoints); return cv::getAffineTransform(srcMat, dstMat); } // 获取瓦片坐标系下的坐标范围 void getTileRange(int& xStart, int& yStart, int& xEnd, int& yEnd, int width, int height) { xStart = std::max(0, xStart); yStart = std::max(0, yStart); xEnd = std::min(width / TILE_SIZE, xEnd); yEnd = std::min(height / TILE_SIZE, yEnd); } bool generateCorrectedImage(const std::string& imgPath, const std::string& outImgPath, int gridWidth, const std::vector<cv::Point2f>& gridPoints) { GDALAllRegister(); GDALDataset* pSrcDs = static_cast<GDALDataset*>(GDALOpen(imgPath.c_str(), GA_ReadOnly)); if (pSrcDs == nullptr) { std::cerr << "Failed to open source image " << imgPath << std::endl; return false; } int width = pSrcDs->GetRasterXSize(); int height = pSrcDs->GetRasterYSize(); // 计算格网矫正行数 int gridRowCount = static_cast<int>(std::ceil(static_cast<double>(width) / gridWidth)); // 构建格网点坐标数组 std::vector<cv::Point2f> srcPoints, dstPoints; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int row = y / gridWidth; int col = x / gridWidth; int idx = row * gridRowCount + col; // 如果 idx 超出了范围,说明该像素不在格网上,跳过 if (idx >= gridPoints.size()) continue; cv::Point2f srcPoint(x, y); cv::Point2f dstPoint = gridPoints[idx]; srcPoints.push_back(srcPoint); dstPoints.push_back(dstPoint); } } // 计算仿射变换矩阵 cv::Mat affineMat = getAffineTransformMatrix(srcPoints, dstPoints); // 打开输出影像 GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); char** pOptions = nullptr; pOptions = CSLSetNameValue(pOptions, "TILED", "YES"); pOptions = CSLSetNameValue(pOptions, "BLOCKXSIZE", std::to_string(TILE_SIZE).c_str()); pOptions = CSLSetNameValue(pOptions, "BLOCKYSIZE", std::to_string(TILE_SIZE).c_str()); GDALDataset* pDstDs = pDriver->Create(outImgPath.c_str(), width, height, pSrcDs->GetRasterCount(), GDT_Byte, pOptions); CSLDestroy(pOptions); // 设置 GeoTransform 信息 double adfGeoTransform[6] = { 0 }; pSrcDs->GetGeoTransform(adfGeoTransform); adfGeoTransform[0] += affineMat.at<double>(0, 2); adfGeoTransform[3] += affineMat.at<double>(1, 2); pDstDs->SetGeoTransform(adfGeoTransform); pDstDs->SetProjection(pSrcDs->GetProjectionRef()); // 分块处理 for (int y = 0; y < height; y += TILE_SIZE) { for (int x = 0; x < width; x += TILE_SIZE) { // 获取当前块的范围 int xStart = x / TILE_SIZE; int yStart = y / TILE_SIZE; int xEnd = (x + TILE_SIZE) / TILE_SIZE; int yEnd = (y + TILE_SIZE) / TILE_SIZE; getTileRange(xStart, yStart, xEnd, yEnd, width, height); // 读取源块 cv::Rect roi(x, y, TILE_SIZE, TILE_SIZE); if (roi.x + roi.width > width) roi.width = width - roi.x; if (roi.y + roi.height > height) roi.height = height - roi.y; cv::Mat srcMat; pSrcDs->RasterIO(GF_Read, roi.x, roi.y, roi.width, roi.height, srcMat.data, roi.width, roi.height, GDT_Byte, pSrcDs->GetRasterCount(), nullptr, 0, 0, 0); // 矫正块 cv::Mat dstMat; cv::warpAffine(srcMat, dstMat, affineMat, cv::Size(TILE_SIZE, TILE_SIZE), cv::INTER_LINEAR, cv::BORDER_REFLECT); // 写入目标块 for (int ty = yStart; ty < yEnd; ++ty) { for (int tx = xStart; tx < xEnd; ++tx) { int tileX = tx * TILE_SIZE; int tileY = ty * TILE_SIZE; cv::Rect tileRoi(tileX, tileY, TILE_SIZE, TILE_SIZE); if (tileRoi.x + tileRoi.width > width) tileRoi.width = width - tileRoi.x; if (tileRoi.y + tileRoi.height > height) tileRoi.height = height - tileRoi.y; pDstDs->RasterIO(GF_Write, tileRoi.x, tileRoi.y, tileRoi.width, tileRoi.height, dstMat.data, tileRoi.width, tileRoi.height, GDT_Byte, pDstDs->GetRasterCount(), nullptr, 0, 0, 0); } } } } // 关闭数据集 GDALClose(pSrcDs); GDALClose(pDstDs); return true; } ``` 测试代码: ```cpp int main(int argc, char** argv) { std::string imgPath = "/path/to/input/image.tif"; std::string outImgPath = "/path/to/output/image.tif"; int gridWidth = 64; std::vector<cv::Point2f> gridPoints = { /* 格网点坐标数组 */ }; generateCorrectedImage(imgPath, outImgPath, gridWidth, gridPoints); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓码bigdata

如果文章给您带来帮助,感谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值