ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

MATLAB原生读取ENVI遥感影像:头文件解析与二进制数据加载

2026/9/16 16:35:59 拓冰建站 浏览量
MATLAB原生读取ENVI遥感影像:头文件解析与二进制数据加载 简介本资源是一套专为遥感图像处理初学者及MATLAB开发者设计的ENVI格式文件读取工具包解决科研与工程中常见遥感数据如Hyperspectral高光谱影像在MATLAB环境下无法直接加载的痛点适用于地物分类、光谱分析、遥感建模等实际场景。压缩包共2个文件含1个核心MATLAB源码文件.m——已完整注释、结构清晰、支持头文件自动解析与数据体读取另附1份《MATLAB命令大全》PDF文档便于快速查阅基础语法与矩阵操作指令辅助理解源码逻辑。资源大小为9.17MB轻量易部署适配主流MATLAB版本。已有764人学习下载用户可直接复用该脚本完成ENVI标准格式.hdr .dat的跨平台数据导入掌握遥感数据I/O底层实现机制并基于源码拓展波段裁剪、辐射定标等后续处理功能。1. 用 MATLAB 直接读取 ENVI 格式遥感影像不依赖 ENVI 软件也能解析头文件与数据体你手上有.hdr.dat或.raw配对的遥感数据想在 MATLAB 里直接加载、查看波段、做辐射定标或后续处理却卡在“找不到 ENVI 接口”“envi_read报错未定义”“头文件参数手动填错导致图像错位”这些环节这不是小众需求——地质填图、矿物蚀变识别、植被指数反演等实际项目中大量原始数据以 ENVI 标准分发而团队未必统一部署 ENVI 桌面版更常见的是只装 MATLAB靠脚本完成从读取到建模的全链路。本方案完全基于 MATLAB 原生函数实现不调用外部 DLL、不依赖 ENVI 运行时、不使用imread等通用图像函数它们无法解析 ENVI 头文件中的波段数、数据类型、字节序、BIP/BIL/BSQ 存储格式等关键元信息。核心是用fopenfread精确控制二进制读取偏移与字节顺序用正则解析.hdr文本提取结构化元数据。适用于 MATLAB R2016b 及以上版本实测支持 8/16/32 位整型与浮点型数据覆盖 Landsat、Sentinel-2 L1C、ASTER、高分系列等主流遥感数据导出的 ENVI 格式。2. 解析 ENVI 头文件从文本中精准提取波段数、数据类型与存储布局ENVI 头文件.hdr是纯文本但其字段命名不统一、空格缩进随意、注释行混杂直接importdata或textscan易漏关键参数。必须用正则表达式逐行匹配且需区分大小写与引号包裹情况。以下代码块封装了健壮的头文件解析逻辑返回结构体hdr_info包含所有后续读取必需的字段function hdr_info parse_envi_hdr(hdr_path) % 读取 hdr 文件全部内容 fid fopen(hdr_path, r); if fid -1 error(无法打开头文件: %s, hdr_path); end hdr_text fread(fid, *char); fclose(fid); % 初始化默认值ENVI 规范中部分字段可省略 hdr_info.samples 0; hdr_info.lines 0; hdr_info.bands 0; hdr_info.data_type 4; % 默认 float32 (ENVI code 4) hdr_info.interleave bsq; % 默认 BSQ hdr_info.byte_order 0; % 默认 Intel (little-endian) hdr_info.header_offset 0; % 默认无头部偏移 % 正则匹配关键字段支持带引号和不带引号两种格式 patterns { samples\s*\s*(\d) % samples 1024 lines\s*\s*(\d) % lines 1024 bands\s*\s*(\d) % bands 6 data type\s*\s*(\d) % data type 12 (float64) interleave\s*\s*(\w) % interleave bip byte order\s*\s*(\d) % byte order 0 header offset\s*\s*(\d) % header offset 0 }; for i 1:length(patterns) match regexp(hdr_text, patterns{i}, tokens); if ~isempty(match) val str2double(match{1}{1}); switch i case 1, hdr_info.samples val; case 2, hdr_info.lines val; case 3, hdr_info.bands val; case 4, hdr_info.data_type val; case 5, hdr_info.interleave lower(match{1}{1}); case 6, hdr_info.byte_order val; case 7, hdr_info.header_offset val; end end end % 验证必要字段 if any([hdr_info.samples, hdr_info.lines, hdr_info.bands] 0) error(头文件缺失必要字段samples、lines 或 bands); end end注意data_type字段值对应 ENVI 数据类型编码如 1uint8, 2int16, 4float32, 5float64, 12float64此映射关系必须硬编码在读取逻辑中interleave必须转为小写统一处理因.hdr中可能写作BIP、bip或Bipbyte_order0表示 Intel 小端x86/x64 通用1表示 Motorola 大端旧 SPARC 系统MATLAB 默认按本机字节序读取故需显式调用fread(..., ieee-le)或ieee-be。2.1 ENVI 数据类型与 MATLAB 类型的精确映射表ENVI data_typeMATLAB classfread 数据类型字符串说明1uint8uint8无符号 8 位整型常见于 QC 波段2int16int16有符号 16 位整型Landsat 常用4singlesingle32 位浮点辐射定标后常用5doubledouble64 位浮点高精度计算场景12doubledouble同 data_type5ENVI 旧版本用法该映射直接影响fread的第三个参数。若误将data_type2当作int32读取会导致数据整体右移 16 位图像全黑或溢出。2.2 三种 interleaving 格式对内存布局的决定性影响ENVI 支持 BIPBand Interleaved by Pixel、BILBand Interleaved by Line、BSQBand Sequential三种存储方式同一组(samples, lines, bands)数据在磁盘上字节排列完全不同BSQ最常用先存第 1 波段全部像素lines × samples再存第 2 波段……最后存第bands波段。读取单波段最快。BIP每个像素的全部波段值连续存放如[R,G,B,R,G,B,...]适合逐像素光谱分析。BIL每行所有波段值连续存放如[R1,G1,B1,R2,G2,B2,...]介于两者之间。MATLAB 读取时若interleavebip却按bsq解析结果矩阵维度会错乱reshape后图像严重扭曲。必须根据hdr_info.interleave动态选择reshape策略。3. 用原生 fread 精确读取二进制数据体处理字节序、偏移与重排头文件解析完成后下一步是从.dat或.raw文件中读取原始字节流并按data_type、byte_order、interleave三者联合规则还原为三维数组data(samp, line, band)。以下函数read_envi_data完成该任务核心是先fread全量字节再按 interleaving 类型切片重排最后typecast或swapbytes处理字节序function data read_envi_data(dat_path, hdr_info) % 计算总字节数 bytes_per_pixel get_bytes_per_pixel(hdr_info.data_type); total_pixels hdr_info.samples * hdr_info.lines * hdr_info.bands; total_bytes total_pixels * bytes_per_pixel; % 打开数据文件跳过 header_offset如有 fid fopen(dat_path, r); if fid -1 error(无法打开数据文件: %s, dat_path); end if hdr_info.header_offset 0 fseek(fid, hdr_info.header_offset, bof); end % 一次性读取全部原始字节避免循环 fread 性能损耗 raw_bytes fread(fid, total_bytes, uint8); fclose(fid); % 根据 data_type 转换为对应数值类型未处理字节序 switch hdr_info.data_type case 1, raw_data uint8(raw_bytes); case 2, raw_data int16(typecast(raw_bytes(1:2:end), int16)); case 4, raw_data single(typecast(raw_bytes(1:4:end), single)); case 5, raw_data double(typecast(raw_bytes(1:8:end), double)); case 12, raw_data double(typecast(raw_bytes(1:8:end), double)); otherwise, error(不支持的 ENVI data_type: %d, hdr_info.data_type); end % 处理字节序仅当 byte_order1大端且本机为小端时需 swap if hdr_info.byte_order 1 ~isbigendian() raw_data swapbytes(raw_data); end % 按 interleaving 类型重排为三维数组 switch lower(hdr_info.interleave) case bsq % BSQ: [band, line, sample] → reshape 为 [sample, line, band] data reshape(raw_data, ... hdr_info.samples, hdr_info.lines, hdr_info.bands); case bil % BIL: [line, band, sample] → 先 reshape 为 [line, band, sample]再 permute temp reshape(raw_data, ... hdr_info.lines, hdr_info.bands, hdr_info.samples); data permute(temp, [3, 1, 2]); % → [sample, line, band] case bip % BIP: [line, sample, band] → 先 reshape 为 [line, sample, band]再 permute temp reshape(raw_data, ... hdr_info.lines, hdr_info.samples, hdr_info.bands); data permute(temp, [2, 1, 3]); % → [sample, line, band] otherwise error(不支持的 interleave 类型: %s, hdr_info.interleave); end end function bpp get_bytes_per_pixel(dt) switch dt case {1}, bpp 1; case {2}, bpp 2; case {4,5,12}, bpp 4; otherwise, error(未知 data_type: %d, dt); end end提示typecast函数比fread(fid, N, int16)更可靠因为它不依赖文件指针位置且能处理任意长度的字节流swapbytes仅在跨平台如从 PowerPC 导出的大端数据在 x86 上读取时生效isbigendian()判断当前 MATLAB 运行环境字节序避免冗余操作。3.1 验证读取正确性的三个必检步骤读取完成后不能直接进入建模必须验证数据完整性维度校验size(data)必须严格等于[hdr_info.samples, hdr_info.lines, hdr_info.bands]极值检查min(data(:))和max(data(:))应在合理范围内如int16数据不应出现-32768到32767之外的值可视化抽样用imshow(data(:,:,1), [])查看第一波段灰度图确认无条纹、无块状伪影、无全黑/全白异常区域。若第 1 步失败说明interleave解析错误若第 2 步出现极端值大概率是data_type映射错误或字节序未处理若第 3 步图像扭曲重点检查reshape维度顺序是否与interleave匹配。4. 构建完整可复用函数一键读取并返回带地理信息的 datacube将前两步封装为一个顶层函数read_envi输入.hdr路径自动推导.dat路径同名不同扩展返回结构体含数据、元数据及基础地理信息如像元大小、左上角坐标——若 hdr 中存在map info字段。该函数已用于多个矿物蚀变信息提取项目支持批量处理目录下所有 ENVI 数据function envidata read_envi(hdr_path) % 解析头文件 hdr_info parse_envi_hdr(hdr_path); % 推导数据文件路径.dat 或 .raw [pathstr, name, ~] fileparts(hdr_path); dat_path fullfile(pathstr, [name .dat]); if ~exist(dat_path, file) dat_path fullfile(pathstr, [name .raw]); if ~exist(dat_path, file) error(未找到对应的数据文件: %s.dat 或 %s.raw, name, name); end end % 读取数据体 data read_envi_data(dat_path, hdr_info); % 提取 map info若存在用于后续地理配准 map_info extract_map_info(hdr_path); % 组装返回结构体 envidata.data data; envidata.hdr hdr_info; envidata.map_info map_info; envidata.filename name; end function map_info extract_map_info(hdr_path) map_info struct(projection, , x_min, NaN, y_max, NaN, x_size, NaN, y_size, NaN); fid fopen(hdr_path, r); if fid -1, return; end hdr_text fread(fid, *char); fclose(fid); % 匹配 map info 行ENVI 标准格式map info {UTM, 1, 1, 440720.000, 3751320.000, 30.0, 30.0, ...} map_line regexp(hdr_text, map info\s*\s*\{([^}]*)\}, tokens); if isempty(map_line), return; end parts strsplit(map_line{1}{1}, ,); if length(parts) 6 map_info.projection strtrim(parts{1}); map_info.x_min str2double(strtrim(parts{4})); map_info.y_max str2double(strtrim(parts{5})); map_info.x_size str2double(strtrim(parts{6})); map_info.y_size str2double(strtrim(parts{7})); end end4.1 实际调用示例加载 Landsat 8 OLI 数据并显示 NDVI% 假设 hdr 文件为 LC08_L1TP_123032_20220515_20220520_02_T1_meta.hdr envi read_envi(LC08_L1TP_123032_20220515_20220520_02_T1_meta.hdr); % Landsat 8 波段索引ENVI 中按顺序存储需确认 hdr 中 band names % B3Blue, B4Green, B5Red, B6NIR → 对应 MATLAB 第 3、4、5、6 波段 red envi.data(:, :, 5); % 注意MATLAB 索引从 1 开始 nir envi.data(:, :, 6); % 计算 NDVI(NIR - Red) / (NIR Red)规避除零 ndvi (nir - red) ./ (nir red eps); % 显示 figure; subplot(1,2,1); imshow(envi.data(:,:,5), []); title(Red Band); subplot(1,2,2); imshow(ndvi, [-1,1]); title(NDVI); colorbar;注意波段顺序必须与.hdr中band names字段一致若未定义则按文件中物理存储顺序即bands7时第 1 波段为索引 1。矿物蚀变分析中常用短波红外波段如 Landsat 8 B7务必核对hdr_info.bands与实际需求波段编号。5. 常见报错定位与修复从“数据全黑”到“维度不匹配”的实战排错指南实际工程中90% 的读取失败源于元数据解析偏差或fread参数错配。以下是高频问题与对应诊断命令现象可能原因快速诊断命令修复动作data全为0或NaNheader_offset值错误读取起始位置偏移过大fprintf(Offset: %d, FileSize: %d\n, hdr_info.header_offset, filesize(dat_path))检查.hdr中header offset是否为0或手动设为0测试size(data)为[1, N, 1]interleave解析失败误判为bip但实际是bsqdisp(hdr_info.interleave); whos data强制指定hdr_info.interleave bsq后重试图像出现垂直/水平条纹data_type错误导致fread字节对齐错位class(raw_data); size(raw_data)在read_envi_data中加断点查.hdr中data type值对照映射表修正get_bytes_per_pixelpermute报错 “维度不匹配”reshape输入向量长度 ≠samples × lines × bands × bytes_per_pixelnumel(raw_data) hdr_info.samples * hdr_info.lines * hdr_info.bands检查total_bytes计算是否遗漏bytes_per_pixel或fread读取字节数不足5.1 用 hexdump 快速验证二进制结构Linux/macOS当 MATLAB 读取结果异常且怀疑.dat文件本身损坏或格式非标时用系统命令直查原始字节# 查看前 64 字节含可能的 header offset hexdump -C -n 64 LC08_L1TP_123032_20220515_20220520_02_T1_meta.dat # 查看某一段如第 1000 行起 16 字节验证是否为预期数值 hexdump -C -s $((1000 * 1024 * 6 * 2)) -n 16 LC08_L1TP_123032_20220515_20220520_02_T1_meta.dat若输出中出现大量00 00或ff ff连续块说明数据被截断或填充若hexdump显示 ASCII 字符如ENVI字样则文件开头混入文本头需调整header_offset跳过。5.2 批量处理时的健壮性增强技巧对含数百个.hdr文件的目录添加自动容错与日志hdr_files dir(*.hdr); for i 1:length(hdr_files) try envi read_envi(hdr_files(i).name); fprintf(✓ %s: %d×%d×%d\n, hdr_files(i).name, size(envi.data,1), size(envi.data,2), size(envi.data,3)); catch ME fprintf(✗ %s: %s\n, hdr_files(i).name, ME.message); continue; end end此循环确保单个文件失败不影响整体流程日志明确指向具体.hdr名称便于回溯修复。本文还有配套的精品资源点击获取