首页 > 编程语言 >使用GDAL(C++库)从末尾行开始向上读取图像数据

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

时间:2024-07-20 19:00:10浏览次数:14  
标签:读取 int nCs C++ RasterIO 图像 nRs GDAL

使用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)

参数的详细含义如下:

参数含义
eRWFlagGF_Read读取数据区域,或GF_Write写入数据区域。
nXOff到要访问的频带区域左上角的像素偏移。从左侧开始为零。
nYOff到要访问的频带区域左上角的线偏移。从顶部开始,这将为零。
nXSize要访问的频带区域的宽度,以像素为单位。
nYSize要以直线方式访问的带区区域的高度。
pData应将数据读取或写入的缓冲区。此缓冲区必须至少包含eBufType类型的nBufXSizenBufYSizenBandCount字。它按从左到右、从上到下的像素顺序组织。间距由nPixelSpace和nLineSpace参数控制。
nBufXSize将要读取或从中写入所需区域的缓冲区图像的宽度。
nBufYSize将要读取或从中写入所需区域的缓冲区图像的高度。
eBufTypepData数据缓冲区中像素值的类型。根据需要,像素值将自动转换为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是按反行序读取、正常方式保存的结果。
可见,第二种读取方法所读数据在内存中的行序与第一种读取方法所读的是相反的。

标签:读取,int,nCs,C++,RasterIO,图像,nRs,GDAL
From: https://blog.csdn.net/qq_42679415/article/details/139969898

相关文章

  • 在VS2022中通过Nuget将vcpkg环境集成/卸载到c++项目
    在VS2022中通过Nuget将vcpkg环境集成/卸载到c++项目vcpkg是微软和C++社区维护的免费开源C/C++包管理器。利用它,可以一条命令编译安装用户所需的库;提供CMake配置文件;并且对于Windows开发者,在VisualStudio中集成后还可以自动链接静态库,非常方便易用。一般而言,开发者仅需要......
  • kettle从入门到精通 第七十九课 ETL之kettle kettle读取数据库BLOB字段转换为文件
     上一课我们讲解了如何将文件以二进制流的方式写入数据库,本节课我们一起学习下如何将二进制数据读取为文件。 1、将二进制流转换为文件这里主要用到了步骤【文本文件输出】。表输入步骤从表中读取blob字段,java代码定义二进制流转换为文件的全路径,文本文件输出步骤根据全路径和......
  • C++的输入输出(ACM模式)
    原文1.输入首先,在C++语言中,要使用标准的输入,需要包含头文件<iostream>1.1cincin是c++中标准的输入流对象,cin有两个用法,单独读入和批量读入cin的原理:简单来讲,有一个缓冲区,键盘输入的数据会先存到缓冲区,用cin可以从缓冲区中读取数据。注意:cin可以连续从键盘读入数据cin......
  • 如何编写一个C++程序来整蛊你的好基友
    如何编写一个C++程序来整蛊你的好基友如何编写一个C++程序来整蛊你的好基友整蛊按照危险性来排序3星类1.每行输出一句2.一直输出,不换行3.给控制台换一个颜色(较有威慑力)颜色代码4.扫盘(配上第三个效果更好,可以用来装B)4星类(含部分解药)弹窗类弹窗代码按下反馈键判定另......
  • pyodbc库读取.xlsx的Sheet内容
    pyodbc库实现直接读取.xlsx数据库中的Sheet内容#导入数据库importpyodbcimportos#获取.xlsx绝对路径file_path=os.path.abspath('XXX.xlsx') print(file_path)#r表示非转义的原始字符串conn_info=r'DRIVER={MicrosoftExcelDriver(*.xls,*.xlsx,*.xlsm,*.xls......
  • c++里数的存储
    hello,大家好啊,这里是文宇,不是文字,是文宇哦。C++中的数的存储方式涵盖了整数、浮点数、字符等多种类型。每种类型的数有不同的位数和存储规则。下面将详细介绍C++中数的存储。首先,整数类型的存储通常使用二进制来表示。C++中提供了多种整数类型,包括char、short、int、longlon......
  • C++生化危机2.0.yl.3已更新
    本版本修复了一个BUG,邻居家无法进入已修复一些小BUG也修复完成(作者体验游戏时发现的)下载链接:生化危机2.0.yl.3.rar-蓝奏云代码如下(建议下载,因为rar解压包内内容更全):#include<bits/stdc++.h>#include<windows.h>#include<time.h>#include<conio.h>usingnamespacestd......
  • C++学习笔记
    第一章预备知识C++融合了三种不同的编程方式:过程性编程(C语言代表的)、面向对象编程(C语言基础上添加的类代表的)、泛型编程(C++模板支持)。Linux上源代码文件编译完后生成后缀.o的目标代码文件,然后执行链接后生成文件名为a.out(默认取名)的可执行程序。C++源文件名的后缀有.cpp......
  • FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
    ​《FFmpeg开发实战:从零基础到短视频上线》一书的“第11章 FFmpeg的桌面开发”介绍了如何在Windows环境对Qt结合FFmpeg实现桌面程序,那么Windows系统通过VisualStudio开发桌面程序也是很常见的,下面就介绍如何在VisualStudio的C++工程中集成FFmpeg库和SDL2库。首先按照《FFmpe......
  • c++零基础知识要点整理(5)
    1.位与运算符:& (位与:代表把二进制的每个数的每一位从低到高进行运算(有0必0))逻辑与:&&(有假必假)(1)位与的定义:inta=0b1001;//0b1001是二进制表示法,0b代表用二进制表示,0b1001对应十进制数为:9intb=0b0101;//对应十进制数为:5a&b=0b0001;//12.位或运算符:| (有1即1)逻辑或:||......