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

参数的详细含义如下:

参数含义
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是按反行序读取、正常方式保存的结果。
可见,第二种读取方法所读数据在内存中的行序与第一种读取方法所读的是相反的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/47171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

朴素模式匹配算法与KMP算法(非重点)

目录 一. 朴素模式匹配算法1.1 什么是字符串的匹配模式1.2 朴素模式匹配算法1.3 通过数组下标实现朴素模式匹配算法 二. KMP算法2.1 算法分析2.2 用代码实现&#xff08;只会出现在选择题&#xff0c;考察代码的概率不大&#xff09; 三. 手算next数组四. KMP算法的进一步优化4…

在AWS创建一台Windows主机并登录

正文共&#xff1a;1111 字 21 图&#xff0c;预估阅读时间&#xff1a;1 分钟 因为之前微软云Azure免费&#xff0c;我们还做了简单的测试&#xff08;白嫖党618福利&#xff01;来Azure领200美刀&#xff01;外加云主机免费用一年&#xff01;&#xff09;&#xff1b;并且通…

k8s核心操作_存储抽象_K8S中使用Secret功能来存储密码_使用免密拉取镜像_k8s核心实战总结---分布式云原生部署架构搭建033

注意在看的时候一定要把 dxxxx中的xxxx换成--o----c----k----e----r 然后我们再来看一个k8s中的secret的功能,这个功能 用来存储密码的,configMap是用来存配置的 比如我们有个pod,他的镜像,如果是需要密码的,那么 我们现在是从公共仓库拉取的,如果我们从私有仓库拉取,有密码…

从 Icelake 到 Iceberg Rust

本文作者丁皓是Databend 研发工程师&#xff0c;也是 ASF Member&#xff0c; Apache OpenDAL PMC Chair &#xff0c;主要研究领域包括存储、自动化与开源。 太长不看 Icelake 已经停止更新&#xff0c;请改用 iceberg-rust。 Iceberg-rust 是一个由社区驱动的项目&#xff0…

《0基础》学习Python——第十六讲

《文件读写》 一、什么是文件读写 文件读写是指在Python程序中对文件进行读取和写入操作。通过文件读写&#xff0c;可以读取文件中的数据&#xff0c;或者向文件中写入数据。 Python提供了多种文件读写的方式&#xff0c;其中最常用的方式是使用open()函数打开一个文件&#…

深入理解Android中的缓存与文件存储目录

&#x1f31f; 引言 在Android应用开发中&#xff0c;合理管理应用的数据存储至关重要。应用可能需要保存各种类型的数据&#xff0c;从简单的配置信息到多媒体文件&#xff0c;甚至是缓存数据以提高性能和用户体验。Android提供了多个内置目录来满足这些需求&#xff0c;但它…

kubernetes集群环境搭建(二)

kubernetes集群类型 kubernetes集群大体上分为两类&#xff1a;一主多从和多主多从 一主多从&#xff1a;一台Master节点和多台Node节点&#xff0c;搭建简单&#xff0c;但有单机故障风险&#xff0c;适合于测试环境部署多主多从&#xff1a;多台Matser节点和多台Node节点&…

策略模式原理与C++实现

定义 定义一些列算法&#xff0c;把他们一个个封装起来&#xff0c;并且使他们可以相互替换&#xff08;变化&#xff09;。该模式使得算法可独立于使用它的客户程序&#xff08;稳定&#xff09;而变化&#xff08;扩展、子类化&#xff09;。 C实现 在不考虑策略模式的情况…

js基础-小数计算,并转换成带两位的百分比

小数计算&#xff0c;并转换成带两位的百分比 1、需求说明2、执行过程2.1 计算 s12.2 计算 s2 1、需求说明 在工作中&#xff0c;有时需要将计算的小数转换成百分比小数&#xff0c;但是在js代码中&#xff0c;计算公式一点点的区别就会影响到最终的结果&#xff0c;如下面代码…

vue视频、图片自动轮播并伴随进度条

废话不多说直接上代 多余没用的部分自己看着删除 <template><div class"showImg"><el-carousel ref"carousel" trigger"hover" :autoplay"false" class"dimControl" :height"${(currenInnerWith*0.37…

spring框架之AOP注解方式(java代码实例)

目录 半注解形式&#xff1a; 业务层接口实现类&#xff1a; 编写切面类&#xff1a; 在配置文件里面唯一需要加的&#xff1a; 测试类&#xff1a; 全注解形式&#xff1a; 不要配置文件&#xff0c;改为配置类&#xff1a; 同样的业务层接口实现类&#xff1a; 同样的…

2024年【天津市安全员C证】免费试题及天津市安全员C证考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 天津市安全员C证免费试题根据新天津市安全员C证考试大纲要求&#xff0c;安全生产模拟考试一点通将天津市安全员C证模拟考试试题进行汇编&#xff0c;组成一套天津市安全员C证全真模拟考试试题&#xff0c;学员可通过…

Java红娘婚恋相亲交友系统小程序源码

红娘婚恋相亲交友小程序&#xff1a;遇见爱情&#xff0c;从指尖开始&#x1f496; &#x1f4f1; 掌中红娘&#xff0c;随时待命 &#x1f48c; 在这个数字化时代&#xff0c;爱情也迎来了它的新舞台——“红娘婚恋相亲交友小程序”。只需轻轻一点&#xff0c;你的专属红娘就…

QT--控件篇四

一、对话框 在软件开发中&#xff0c;对话框&#xff08;Dialog&#xff09;是一种常见的用户界面元素&#xff0c;用于与用户进行交互和获取信息。它通常以模态或非模态的形式出现&#xff0c;模态对话框会阻止用户与应用程序的其他部分交互&#xff0c;直到对话框关闭为止&a…

硕博电子智能控制器、触摸显示屏在集装箱跨运车上的应用

港口跨运车&#xff0c;又称跨运车或轮胎式龙门吊(RTG)&#xff0c;专门用于集装箱码头的装卸和搬运作业&#xff0c;能够迅速完成集装箱在码头前沿、堆场区域以及仓库之间的运输和堆垛&#xff0c;大幅度缩短了装卸周期&#xff0c;提高了港口物流周转效率。 现代跨运车往往配…

C++笔试强训4

文章目录 一、选择题1-5题6-10题 二、编程题题目一题目二 一、选择题 1-5题 %o就是输出八进制的无符号数&#xff0c;0123&#xff0c;&#xff0c;以0开头&#xff0c;本来就是八进制&#xff0c;所以输出为123&#xff0c;123是十进制&#xff0c;转化为八进制就是173. 故选…

【Python基础教程】制作一个宿舍管理系统,数据库宿舍管理系统代码!(完整版,附源码)

今天我们一起学习一个新的小案例——宿舍管理系统。主要涉及列表、字典的初始化、增加、删除、修改和查询操作&#xff0c;以及函数的定义和调用。 一、需求&#xff1a; 有操作指引界面&#xff0c;显示操作号 能添加一个新的入住学生信息&#xff0c;包括学生姓名、宿舍号床…

如何让员工在培训后持续应用六西格玛工具?

要让员工在培训后持续应用六西格玛工具&#xff0c;首先需要明确六西格玛的核心价值及其在企业中的应用意义。六西格玛是一种数据驱动的管理方法论&#xff0c;旨在通过减少变异和浪费&#xff0c;提高流程效率和质量&#xff0c;进而提升企业的竞争力。然而&#xff0c;仅仅通…

JRebelXRebel在线激活(亲测可用)

包含所有新旧版本&#xff0c;包括2023.4.2、2023.4.1、2023.4.0、2023.3.2、2023.3.1、2023.3.0、2023.2.2、2023.2.1、2023.2.0、2023.1.2、2023.1.1 等以及所有2022版本 JRebel&XRebel激活服务器地址 激活服务器地址&#xff08;路线1,推荐&#xff09;&#xff0c;可…

走进NoSql

一、引入 1.1什么是NoSql NoSQL&#xff08;Not Only SQL&#xff09;是一组非关系型数据库&#xff08;或称为非SQL数据库&#xff09;的统称&#xff0c;它们提供了与传统的关系型数据库不同的数据存储和检索方式。NoSQL数据库通常用于处理大量的、分布式的、非结构化或半结…