使用GDAL(C++库)从末尾行开始向上读取图像数据

使用GDAL(C++库)从末尾行读取图像数据

OpenCV等图像库默认的读取方式都是从第一行开始,逐行读取数据(自顶向下),填充到内存缓冲区;对于某些特殊应用,需要反行序读取(从末尾行读到起始行)的图像数据结果。GDAL提供了灵活的栅格数据读取方式RasterIO,下面介绍RasterIO的调用方式,以及如何利用它自底向上读取图像数据。

关键函数RasterIO

此函数的参数列表与实现与C语言APIGDALDatasetRasterIO()GDALDatasetRasterIOEx()函数基本相同。

参数意义

RasterIO提供了读写多波段的图像数据的统一接口,功能强大。其函数定义如下:

CPLErr RasterIO(GDALRWFlag   eRWflag,   // 取值GF_Read/GF_Write 读/写数据
    int          nDSXOff,                 // 读取区域的起始列号
    int          nDSYOff,                 // 读取区域的起始行号
    int          nDSXSize,               // 读取区域的宽(列数)
    int          nDSYSize,               // 读取区域的高(行数)
    void*        pBuffer,                // 存放将读取数据的内存指针
    int          nBXSize,                 // 目标内存的宽(列数)
    int          nBYSize,                 // 目标内存的高(行数)
    GDALDataType eBDataType,   // 目标缓存的数据类型
    int          nBandCount,               // 需要读取的波段数
    int*         panBandMap,              // 存放波段序列数组的指针
    GSpacing     nPixelSpace,        // 一个波段中的数据在pBuffer中的列间隔
    GSpacing     nLineSpace,         // 一个波段中的数据在pBuffer中的行间隔
    GSpacing     nBandSpace,        // 波段之间的在pBuffer中的间隔
    GDALRasterIOExtraArg *psExtraArg)

参数的详细含义如下:

参数 含义
eRWFlag GF_Read读取数据区域,或GF_Write写入数据区域。
nXOff 到要访问的频带区域左上角的像素偏移。从左侧开始为零。
nYOff 到要访问的频带区域左上角的线偏移。从顶部开始,这将为零。
nXSize 要访问的频带区域的宽度,以像素为单位。
nYSize 要以直线方式访问的带区区域的高度。
pData 应将数据读取或写入的缓冲区。此缓冲区必须至少包含eBufType类型的nBufXSizenBufYSizenBandCount字。它按从左到右、从上到下的像素顺序组织。间距由nPixelSpace和nLineSpace参数控制。
nBufXSize 将要读取或从中写入所需区域的缓冲区图像的宽度。
nBufYSize 将要读取或从中写入所需区域的缓冲区图像的高度。
eBufType pData数据缓冲区中像素值的类型。根据需要,像素值将自动转换为GDALRasterBand数据类型/从GDALRaster Band转换为数据类型。
nBandCount 正在读取或写入的频带数。
panBandMap 要读/写的nBandCount个波段的编号数组指针(注意,波段编号从1开始)比如{1,2,3}表示RGB,{3,2,1}表示BGR。若设为NULL,则取前nBandCount个波段。
nPixelSpace 从pData中一个像素值的开始到扫描行中下一个像素数值的开始的字节偏移量。默认数据按BSQ组织,该参数取sizeof(eBufType)
nLineSpace 从pData中一条扫描线的开始到下一条扫描行的开始的字节偏移量。默认数据按BSQ组织,该参数取sizeof(eBufType)*nBufXSize
nBandSpace 一个波段数据的起始处到下一个波段数据起始处的字节偏移量。默认数据按BSQ组织,该参数取nLineSpace*nBufYSize
psExtraArg 默认为NULL。(GDAL 2.0后添加的新参数)GDALRasterIOExtraArg类型的指针,该结构体可用于指定重采样方法和进度回调函数等详见官方文档

如果指定的内存缓冲区的数据类型(eBufType)不同于原图的数据类型,则会自动完成数据类型转换。如果缓冲区大小(nBufXSize,nBufYSize)与要读写的目标区域的大小(nXSize,nYSze)不同,则该方法还会自动重采样图像。

nPixelSpacenLineSpacenBandSpace对应的读取方式

nPixelSpacenLineSpacenBandSpace这三个参数控制将图像数据写到内存或从内存读取的方式。对于三通道的jpg格式图像而言,t图像按BIP方式组织,每个像素的色彩值由3个byte类型数据构成.。设其行数为r,列数为c,读取时开辟的内存起始指针记作pImgData,设置:

nPixelSpace为3,表示每3个byte是下一个像素;
nLineSpace为3*列数,即每隔3*c个字节,就是下一行;
nBandSpace为1:RGB三个波段都是紧挨着的。

在这里插入图片描述
如图所示,为实现反行序读取(从末尾行读取),需要将nLineSpace参数设置为-3*c,并且将传入RasterIO的内存缓冲区指针设置为最后一行的起始处pImgData+(r-1)*c*3

示例:使用RasterIO反行序(自底向上)读取图像块数据

在GDAL中,图像中的像素的坐标以左上角为原点,向右为x轴正方向,向下为y轴正方向。
以一张三通道的jpg格式图像MerchDataTest.JPG为例,以图片中坐标(100,100)为起点,读取30列、50行的图块数据,代码示例如下:

#include"gdal_priv.h"
#include<vector>

int main(int argc, char** argv)
{
    GDALAllRegister();
    int nCs = 30;
    int nRs = 50;
    std::vector<BYTE> vData1(nCs * nRs * 3);
    std::vector<BYTE> vData2(nCs * nRs * 3);
    GDALDataset* pdata = (GDALDataset*)GDALOpen("MerchDataTest.JPG", GDALAccess::GA_ReadOnly);
    int panBandMap[] = { 1,2,3 };
    pdata->RasterIO(GDALRWFlag::GF_Read, 100, 400, nCs, nRs, &vData1[0], nCs, nRs, GDALDataType::GDT_Byte, 3, panBandMap, 3, 3 * nCs, 1);
    pdata->RasterIO(GDALRWFlag::GF_Read, 100, 400, nCs, nRs, &vData2[0]+nCs*(nRs-1)*3, nCs, nRs, GDALDataType::GDT_Byte, 3, panBandMap, 3, -3 * nCs, 1);
    GDALClose(pdata);
    /// 将读取到的内容保存为新的tif图像
    GDALDriver* pDriver = (GDALDriver*)GDALGetDriverByName("GTIFF");
    GDALDataset* pOutImg1= pDriver->Create("E:\\Output1.tif",nCs,nRs,3,GDALDataType::GDT_Byte, NULL);
    GDALDataset* pOutImg2= pDriver->Create("E:\\Output2.tif",nCs,nRs,3,GDALDataType::GDT_Byte, NULL);
    GDALDataset* pOutImg3= pDriver->Create("E:\\Output2_row_reversed.tif",nCs,nRs,3,GDALDataType::GDT_Byte, NULL);
    pOutImg1->RasterIO(GDALRWFlag::GF_Write, 0, 0, nCs, nRs, &vData1[0], nCs, nRs, GDALDataType::GDT_Byte, 3, panBandMap, 3, 3 * nCs, 1);
    pOutImg2->RasterIO(GDALRWFlag::GF_Write, 0, 0, nCs, nRs, &vData2[0]+nCs*(nRs-1)*3, nCs, nRs, GDALDataType::GDT_Byte, 3, panBandMap, 3, -3 * nCs, 1);
    pOutImg3->RasterIO(GDALRWFlag::GF_Write, 0, 0, nCs, nRs, &vData2[0], nCs, nRs, GDALDataType::GDT_Byte, 3, panBandMap, 3, 3 * nCs, 1);
    GDALClose(pOutImg1);
    GDALClose(pOutImg2);
    GDALClose(pOutImg3);
}

在这里插入图片描述

所得三张输出图像效果如下:

在这里插入图片描述
Output1是按常规方式读取一块区域并保存的结果;
Output2是按反行序读取,并按反行序方式保存的结果;
Output2_row_reversed是按反行序读取、正常方式保存的结果。
可见,第二种读取方法所读数据在内存中的行序与第一种读取方法所读的是相反的。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 19:34:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 19:34:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 19:34:03       58 阅读
  4. Python语言-面向对象

    2024-07-17 19:34:03       69 阅读

热门阅读

  1. 开发一款数字芯片的流程

    2024-07-17 19:34:03       21 阅读
  2. bignumber.js库,解决前端小数精度问题

    2024-07-17 19:34:03       18 阅读
  3. Developing Secure Software CMP7038B

    2024-07-17 19:34:03       20 阅读
  4. 递推算法及解题套路

    2024-07-17 19:34:03       23 阅读
  5. Next.js 和 React的区别

    2024-07-17 19:34:03       21 阅读
  6. cadence许可管理解决方案

    2024-07-17 19:34:03       24 阅读
  7. Qt Style Sheets-样式表语法

    2024-07-17 19:34:03       18 阅读