一、常见高光谱数据格式
| 格式 | 扩展名 | 特点 | 常用软件 |
|---|---|---|---|
| ENVI格式 | .hdr+ .dat/.raw |
行业标准格式,头文件+数据文件 | ENVI, MATLAB |
| TIFF格式 | .tif |
支持多波段,通用性强 | 多数软件 |
| HDF格式 | .hdf/.h5 |
分层数据结构,适合大数据 | NASA工具 |
| MAT格式 | .mat |
MATLAB原生格式,便于处理 | MATLAB |
| BIL/BIP/BSQ | 无扩展名或.bil |
三种存储顺序 | 遥感软件 |
二、MATLAB读取代码
2.1 主程序:read_hyperspectral_image.m
%% 高光谱图像读取主程序
% 功能:读取多种格式的高光谱图像数据
clear; clc; close all;
%% 1. 文件路径设置
file_path = 'D:\HyperspectralData\'; % 修改为你的文件路径
file_name = 'indian_pines'; % 文件名(不带扩展名)
fprintf('=== 高光谱图像读取系统 ===\n');
fprintf('文件路径: %s\n', file_path);
fprintf('文件名: %s\n\n', file_name);
%% 2. 检测文件格式并读取
[hypercube, metadata] = read_hyperspectral_file(file_path, file_name);
%% 3. 显示基本信息
display_hyperspectral_info(hypercube, metadata);
%% 4. 可视化高光谱数据
visualize_hyperspectral_data(hypercube, metadata);
%% 5. 保存为MATLAB格式(可选)
save_hyperspectral_mat(hypercube, metadata, file_path, file_name);
2.2 文件读取核心函数:read_hyperspectral_file.m
function [hypercube, metadata] = read_hyperspectral_file(file_path, file_name)
% 读取高光谱图像文件,自动识别格式
fprintf('检测文件格式...\n');
% 检查常见文件格式
formats = {
'ENVI', [file_path file_name '.hdr'], 'read_envi_format'
'TIFF', [file_path file_name '.tif'], 'read_tiff_format'
'HDF', [file_path file_name '.hdf'], 'read_hdf_format'
'HDF5', [file_path file_name '.h5'], 'read_hdf5_format'
'MAT', [file_path file_name '.mat'], 'read_mat_format'
'BIL', [file_path file_name '.bil'], 'read_bil_format'
};
% 尝试每种格式
for i = 1:size(formats, 1)
format_name = formats{i, 1};
file_full_path = formats{i, 2};
read_function = formats{i, 3};
if exist(file_full_path, 'file')
fprintf(' 检测到%s格式: %s\n', format_name, file_full_path);
try
[hypercube, metadata] = feval(read_function, file_full_path);
fprintf(' %s格式读取成功!\n', format_name);
return;
catch ME
fprintf(' %s格式读取失败: %s\n', format_name, ME.message);
end
end
end
error('未找到支持的高光谱文件格式!请检查文件路径和格式。');
end
2.3 ENVI格式读取:read_envi_format.m(最常用)
function [hypercube, metadata] = read_envi_format(hdr_file)
% 读取ENVI格式高光谱图像
fprintf(' 读取ENVI格式...\n');
% 1. 读取头文件
metadata = read_envi_header(hdr_file);
% 2. 确定数据文件路径
[hdr_path, hdr_name, ~] = fileparts(hdr_file);
if isfield(metadata, 'file_type') && strcmp(metadata.file_type, 'ENVI Standard')
% 查找对应的数据文件
possible_extensions = {'.dat', '.raw', '.img', ''};
data_file = '';
for ext = possible_extensions
test_file = fullfile(hdr_path, [hdr_name ext{:}]);
if exist(test_file, 'file')
data_file = test_file;
break;
end
end
if isempty(data_file)
error('找不到对应的数据文件!');
end
else
data_file = fullfile(hdr_path, [hdr_name '.dat']);
end
fprintf(' 头文件: %s\n', hdr_file);
fprintf(' 数据文件: %s\n', data_file);
% 3. 根据头文件信息读取数据
% 确定数据类型
dtype_map = containers.Map({'1', '2', '3', '4', '5', '6', '9', '12'}, ...
{'uint8', 'int16', 'int32', 'float32', 'float64', 'uint16', 'uint32', 'double'});
if isfield(metadata, 'data_type')
precision = dtype_map(char(metadata.data_type));
else
precision = 'float32'; % 默认
end
% 确定波段顺序
interleave_map = containers.Map({'bsq', 'bil', 'bip'}, {'BandSequential', 'BandInterleavedLine', 'BandInterleavedPixel'});
if isfield(metadata, 'interleave')
interleave = interleave_map(char(metadata.interleave));
else
interleave = 'BandSequential'; % 默认BSQ
end
% 4. 使用multibandread读取
rows = str2double(metadata.lines);
cols = str2double(metadata.samples);
bands = str2double(metadata.bands);
fprintf(' 图像尺寸: %d × %d × %d\n', rows, cols, bands);
fprintf(' 数据类型: %s\n', precision);
fprintf(' 存储顺序: %s\n', interleave);
% 读取数据
hypercube = multibandread(data_file, [rows, cols, bands], precision, 0, interleave, 'ieee-le');
% 5. 处理字节顺序
if isfield(metadata, 'byte_order') && strcmp(metadata.byte_order, '1')
hypercube = swapbytes(hypercube);
end
% 6. 添加元数据
metadata.rows = rows;
metadata.cols = cols;
metadata.bands = bands;
metadata.precision = precision;
metadata.interleave = interleave;
fprintf(' ENVI数据读取完成!\n');
end
function metadata = read_envi_header(hdr_file)
% 读取ENVI头文件
metadata = struct();
% 读取头文件内容
fid = fopen(hdr_file, 'r');
if fid == -1
error('无法打开头文件: %s', hdr_file);
end
header_lines = textscan(fid, '%s', 'Delimiter', '\n');
fclose(fid);
% 解析头文件
for i = 1:length(header_lines{1})
line = strtrim(header_lines{1}{i});
if isempty(line) || startsWith(line, ';')
continue;
end
% 分割键值对
eq_idx = strfind(line, '=');
if ~isempty(eq_idx)
key = strtrim(line(1:eq_idx(1)-1));
value = strtrim(line(eq_idx(1)+1:end));
% 移除引号
value = strrep(value, '"', '');
value = strrep(value, '''', '');
% 存储到元数据
metadata.(matlab.lang.makeValidName(lower(key))) = value;
end
end
end
2.4 TIFF格式读取:read_tiff_format.m
function [hypercube, metadata] = read_tiff_format(tiff_file)
% 读取TIFF格式高光谱图像
fprintf(' 读取TIFF格式...\n');
% 使用MATLAB内置函数读取
info = imfinfo(tiff_file);
% 获取图像信息
metadata = struct();
metadata.format = 'TIFF';
metadata.rows = info.Height;
metadata.cols = info.Width;
metadata.bands = info.SamplesPerPixel;
metadata.precision = info.BitDepth;
metadata.photometric = info.PhotometricInterpretation;
fprintf(' 图像尺寸: %d × %d × %d\n', metadata.rows, metadata.cols, metadata.bands);
fprintf(' 位深度: %d bits\n', metadata.precision);
% 读取数据
if metadata.bands == 1
% 单波段图像
hypercube = imread(tiff_file);
hypercube = reshape(hypercube, [metadata.rows, metadata.cols, 1]);
else
% 多波段图像
hypercube = zeros(metadata.rows, metadata.cols, metadata.bands, 'uint16');
for band = 1:metadata.bands
[~, map] = imread(tiff_file, band);
if isempty(map)
hypercube(:,:,band) = imread(tiff_file, band);
else
% 有颜色映射的情况
hypercube(:,:,band) = ind2gray(imread(tiff_file, band), map);
end
end
end
% 转换为double类型以便处理
hypercube = double(hypercube);
fprintf(' TIFF数据读取完成!\n');
end
2.5 HDF格式读取:read_hdf_format.m
function [hypercube, metadata] = read_hdf_format(hdf_file)
% 读取HDF格式高光谱图像(如AVIRIS数据)
fprintf(' 读取HDF格式...\n');
% 检查HDF工具箱是否可用
if ~license('test', 'hdf_toolbox')
error('需要HDF工具箱来读取HDF文件!');
end
% 打开HDF文件
file_id = hdfopen(hdf_file, 'rdonly');
if file_id == -1
error('无法打开HDF文件: %s', hdf_file);
end
try
% 获取文件信息
info = hdfinfo(hdf_file);
metadata = struct();
metadata.format = 'HDF';
% 查找高光谱数据集
dataset_name = '';
if isfield(info, 'SDS')
% 科学数据集
sds_info = info.SDS;
for i = 1:length(sds_info)
if sds_info(i).Rank == 3
dataset_name = sds_info(i).Name;
break;
end
end
end
if isempty(dataset_name)
error('在HDF文件中未找到3D高光谱数据集!');
end
% 读取数据集
sds_id = hdfsd('select', file_id, dataset_name);
[hypercube, status] = hdfsd('readdata', sds_id, [0 0 0], [info.SDS(1).Dims(1).Count info.SDS(1).Dims(2).Count info.SDS(1).Dims(3).Count], [1 1 1]);
hdfsd('endaccess', sds_id);
% 获取元数据
metadata.rows = size(hypercube, 1);
metadata.cols = size(hypercube, 2);
metadata.bands = size(hypercube, 3);
metadata.dataset_name = dataset_name;
fprintf(' 数据集: %s\n', dataset_name);
fprintf(' 图像尺寸: %d × %d × %d\n', metadata.rows, metadata.cols, metadata.bands);
catch ME
error('HDF读取错误: %s', ME.message);
finally
hdfclose(file_id);
end
fprintf(' HDF数据读取完成!\n');
end
2.6 其他格式读取函数
function [hypercube, metadata] = read_hdf5_format(h5_file)
% 读取HDF5格式
fprintf(' 读取HDF5格式...\n');
% 列出所有数据集
info = h5info(h5_file);
% 查找3D数据集
dataset_name = '';
for i = 1:length(info.Datasets)
if length(info.Datasets(i).Dimensions) == 3
dataset_name = info.Datasets(i).Name;
break;
end
end
if isempty(dataset_name)
error('未找到3D数据集!');
end
% 读取数据
hypercube = h5read(h5_file, ['/' dataset_name]);
% 获取元数据
metadata = struct();
metadata.format = 'HDF5';
metadata.rows = size(hypercube, 1);
metadata.cols = size(hypercube, 2);
metadata.bands = size(hypercube, 3);
metadata.dataset_name = dataset_name;
fprintf(' HDF5数据读取完成!\n');
end
function [hypercube, metadata] = read_mat_format(mat_file)
% 读取MATLAB格式
fprintf(' 读取MAT格式...\n');
data = load(mat_file);
% 查找高光谱数据变量
vars = fieldnames(data);
hypercube = [];
for i = 1:length(vars)
var_data = data.(vars{i});
if ndims(var_data) == 3 && size(var_data, 3) > 3
hypercube = double(var_data);
metadata = struct();
metadata.format = 'MAT';
metadata.rows = size(hypercube, 1);
metadata.cols = size(hypercube, 2);
metadata.bands = size(hypercube, 3);
metadata.variable_name = vars{i};
break;
end
end
if isempty(hypercube)
error('MAT文件中未找到高光谱数据!');
end
fprintf(' MAT数据读取完成!\n');
end
function [hypercube, metadata] = read_bil_format(bil_file)
% 读取BIL格式
fprintf(' 读取BIL格式...\n');
% 通常需要对应的头文件
[bil_path, bil_name, ~] = fileparts(bil_file);
hdr_file = fullfile(bil_path, [bil_name '.hdr']);
if exist(hdr_file, 'file')
% 使用ENVI读取器
[hypercube, metadata] = read_envi_format(hdr_file);
else
error('找不到BIL文件的头文件!');
end
end
2.7 信息显示函数:display_hyperspectral_info.m
function display_hyperspectral_info(hypercube, metadata)
% 显示高光谱图像基本信息
fprintf('\n=== 高光谱图像信息 ===\n');
% 基本尺寸信息
fprintf('图像尺寸:\n');
fprintf(' 行数: %d\n', metadata.rows);
fprintf(' 列数: %d\n', metadata.cols);
fprintf(' 波段数: %d\n', metadata.bands);
fprintf(' 总像素数: %d\n', metadata.rows * metadata.cols);
fprintf(' 数据大小: %.2f MB\n', numel(hypercube) * 8 / 1024 / 1024);
% 数据范围
fprintf('\n数据范围:\n');
fprintf(' 最小值: %.4f\n', min(hypercube(:)));
fprintf(' 最大值: %.4f\n', max(hypercube(:)));
fprintf(' 平均值: %.4f\n', mean(hypercube(:)));
fprintf(' 标准差: %.4f\n', std(hypercube(:)));
% 格式信息
fprintf('\n格式信息:\n');
fprintf(' 文件格式: %s\n', metadata.format);
if isfield(metadata, 'precision')
fprintf(' 数据类型: %s\n', metadata.precision);
end
if isfield(metadata, 'interleave')
fprintf(' 存储顺序: %s\n', metadata.interleave);
end
% 波长信息(如果有)
if isfield(metadata, 'wavelength')
wavelengths = str2num(metadata.wavelength);
if ~isempty(wavelengths)
fprintf('\n波长信息:\n');
fprintf(' 波长范围: %.2f - %.2f nm\n', min(wavelengths), max(wavelengths));
fprintf(' 光谱分辨率: %.2f nm\n', mean(diff(wavelengths)));
end
end
% 空间分辨率
if isfield(metadata, 'pixel_size')
fprintf(' 空间分辨率: %s\n', metadata.pixel_size);
end
end
2.8 数据可视化:visualize_hyperspectral_data.m
function visualize_hyperspectral_data(hypercube, metadata)
% 可视化高光谱数据
figure('Name', '高光谱图像可视化', 'Color', 'white', 'Position', [100, 100, 1400, 800]);
% 1. RGB合成图(假彩色)
subplot(2,3,1);
rgb_image = create_rgb_composite(hypercube, metadata);
imshow(rgb_image);
title('RGB假彩色合成');
colorbar;
% 2. 单波段显示
subplot(2,3,2);
band_idx = round(metadata.bands/2); % 中间波段
band_image = hypercube(:,:,band_idx);
imagesc(band_image);
colormap(gray);
colorbar;
title(sprintf('波段 %d', band_idx));
axis image;
% 3. 光谱曲线
subplot(2,3,3);
[rows, cols, bands] = size(hypercube);
center_pixel = [round(rows/2), round(cols/2)];
spectrum = squeeze(hypercube(center_pixel(1), center_pixel(2), :));
% 获取波长信息
if isfield(metadata, 'wavelength')
wavelengths = str2num(metadata.wavelength);
plot(wavelengths, spectrum, 'b-', 'LineWidth', 2);
xlabel('波长 (nm)');
else
plot(1:bands, spectrum, 'b-', 'LineWidth', 2);
xlabel('波段编号');
end
ylabel('反射率/辐射值');
title(sprintf('像素(%d,%d)光谱曲线', center_pixel(1), center_pixel(2)));
grid on;
% 4. 波段统计直方图
subplot(2,3,4);
band_for_hist = hypercube(:,:,band_idx);
histogram(band_for_hist(:), 100, 'FaceColor', 'cyan', 'EdgeColor', 'black');
xlabel('像素值');
ylabel('频数');
title(sprintf('波段 %d 直方图', band_idx));
grid on;
% 5. 3D数据立方体切片
subplot(2,3,5);
slice_idx = round(bands/3);
slice_image = hypercube(:,:,slice_idx);
surf(slice_image);
shading interp;
colormap jet;
colorbar;
title(sprintf('波段 %d 3D视图', slice_idx));
view(45, 45);
% 6. 波段相关性矩阵
subplot(2,3,6);
% 随机选择几个波段计算相关性
n_sample_bands = min(10, bands);
sample_bands = round(linspace(1, bands, n_sample_bands));
correlation_matrix = zeros(n_sample_bands, n_sample_bands);
for i = 1:n_sample_bands
for j = 1:n_sample_bands
band_i = hypercube(:,:,sample_bands(i));
band_j = hypercube(:,:,sample_bands(j));
correlation_matrix(i,j) = corr2(band_i, band_j);
end
end
imagesc(correlation_matrix);
colormap hot;
colorbar;
set(gca, 'XTick', 1:n_sample_bands, 'XTickLabel', sample_bands);
set(gca, 'YTick', 1:n_sample_bands, 'YTickLabel', sample_bands);
xlabel('波段编号');
ylabel('波段编号');
title('波段相关性矩阵');
end
function rgb_image = create_rgb_composite(hypercube, metadata)
% 创建RGB假彩色合成
[rows, cols, bands] = size(hypercube);
rgb_image = zeros(rows, cols, 3);
% 选择三个波段作为RGB
if bands >= 3
% 简单选择:近红外、红光、绿光
nir_band = round(bands * 0.7); % 近红外波段
red_band = round(bands * 0.5); % 红光波段
green_band = round(bands * 0.3); % 绿光波段
rgb_image(:,:,1) = hypercube(:,:,nir_band); % R通道
rgb_image(:,:,2) = hypercube(:,:,red_band); % G通道
rgb_image(:,:,3) = hypercube(:,:,green_band); % B通道
else
% 单波段复制为RGB
rgb_image(:,:,1) = hypercube(:,:,1);
rgb_image(:,:,2) = hypercube(:,:,1);
rgb_image(:,:,3) = hypercube(:,:,1);
end
% 归一化到0-1
for i = 1:3
band_data = rgb_image(:,:,i);
min_val = min(band_data(:));
max_val = max(band_data(:));
if max_val > min_val
rgb_image(:,:,i) = (band_data - min_val) / (max_val - min_val);
end
end
end
2.9 保存为MAT格式:save_hyperspectral_mat.m
function save_hyperspectral_mat(hypercube, metadata, file_path, file_name)
% 保存为高光谱MAT格式
% 询问是否保存
save_option = questdlg('是否保存为高光谱MAT格式?', '保存选项', '是', '否', '是');
if strcmp(save_option, '是')
mat_file = fullfile(file_path, [file_name '_hyperspectral.mat']);
% 保存数据
save(mat_file, 'hypercube', 'metadata', '-v7.3');
fprintf('\n高光谱数据已保存为: %s\n', mat_file);
fprintf('文件大小: %.2f MB\n', dir(mat_file).bytes / 1024 / 1024);
end
end
参考代码 读取高光谱图像 www.youwenfan.com/contentcsu/60174.html
三、实用工具函数
3.1 高光谱数据预处理
function preprocessed_cube = preprocess_hyperspectral(hypercube, metadata)
% 高光谱数据预处理
fprintf('高光谱数据预处理...\n');
% 1. 去噪
fprintf(' 1. 去噪处理...\n');
preprocessed_cube = denoise_hyperspectral(hypercube);
% 2. 辐射校正(如果有暗电流)
fprintf(' 2. 辐射校正...\n');
preprocessed_cube = radiance_calibration(preprocessed_cube, metadata);
% 3. 大气校正
fprintf(' 3. 大气校正...\n');
preprocessed_cube = atmospheric_correction(preprocessed_cube, metadata);
% 4. 几何校正
fprintf(' 4. 几何校正...\n');
preprocessed_cube = geometric_correction(preprocessed_cube, metadata);
fprintf('预处理完成!\n');
end
function denoised_cube = denoise_hyperspectral(hypercube)
% 高光谱去噪(主成分分析)
[rows, cols, bands] = size(hypercube);
% 重塑为2D矩阵
data_2d = reshape(hypercube, rows*cols, bands);
% PCA去噪
[coeff, score, latent] = pca(data_2d);
% 保留前95%的能量
cum_var = cumsum(latent) / sum(latent);
n_components = find(cum_var >= 0.95, 1);
% 重建
denoised_2d = score(:, 1:n_components) * coeff(:, 1:n_components)';
denoised_cube = reshape(denoised_2d, rows, cols, bands);
end
3.2 批量读取工具
function batch_read_hyperspectral(folder_path, output_folder)
% 批量读取文件夹中所有高光谱文件
fprintf('批量读取高光谱数据...\n');
fprintf('输入文件夹: %s\n', folder_path);
fprintf('输出文件夹: %s\n', output_folder);
% 获取所有文件
files = dir(fullfile(folder_path, '*.hdr'));
if isempty(files)
error('文件夹中没有找到.hdr文件!');
end
% 创建输出文件夹
if ~exist(output_folder, 'dir')
mkdir(output_folder);
end
% 逐个读取
for i = 1:length(files)
fprintf('\n处理文件 %d/%d: %s\n', i, length(files), files(i).name);
[hypercube, metadata] = read_envi_format(fullfile(folder_path, files(i).name));
% 保存为MAT格式
mat_file = fullfile(output_folder, [files(i).name(1:end-4) '_processed.mat']);
save(mat_file, 'hypercube', 'metadata', '-v7.3');
fprintf(' 已保存: %s\n', mat_file);
end
fprintf('\n批量处理完成!共处理 %d 个文件。\n', length(files));
end