MATLAB读取高光谱图像

一、常见高光谱数据格式

格式 扩展名 特点 常用软件
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
相关推荐
2zcode1 小时前
基于MATLAB的肝病风险评估与分期分析系统设计与实现
开发语言·matlab
小小de风呀1 小时前
de风——【从零开始学C++】(五):内存管理
开发语言·c++
ooseabiscuit1 小时前
Laravel6.x核心优化与特性全解析
android·开发语言·javascript
折哥的程序人生 · 物流技术专研1 小时前
Java面试85题图解版(一):基础核心篇
java·开发语言·后端·面试
Hello.Reader2 小时前
算法基础(十)——分治思想把大问题拆成小问题
java·开发语言·算法
一只大袋鼠2 小时前
JavaWeb四种文件上传方式(下篇)
java·开发语言·springmvc·javaweb
TE-茶叶蛋2 小时前
深入研究 yudao-framework 模块:Java 编程能力提升指南
java·开发语言
逻辑驱动的ken2 小时前
Java高频考点场景题24
java·开发语言·面试·职场和发展·求职招聘
兔小盈3 小时前
多线程-(五)线程安全之内存可见性
java·开发语言·多线程