Generated banner for Matlab Analyze Spectral Images
Generated logo for Matlab Analyze Spectral Images

Matlab Analyze Spectral Images

MathWorksOfficialCreated by MathWorks

  • Skill
  • Tool integration
  • Science and research
  • BSD-2-Clause
  • No issues found

From the author

Work with hyperspectral and multispectral images in MATLAB. Covers reading/writing (ENVI, NITF, TIFF, Sentinel-2, Landsat, ASTER), ECOSTRESS spectral libraries, processing (calibration, atmospheric correction, denoising, sharpening, dimensionality reduction, endmember extraction, unmixing, target/anomaly detection, spectral indices, segmentation), labeling (Spectral Image Labeler app, ground truth objects, automation algorithms), and deep learning (pixel classification CNNs, unmixing autoencoders, transfer learning). Use when reading, writing, processing, analyzing, classifying, labeling, or applying deep learning to hyperspectral or multispectral images.
— the description by MathWorks

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a comprehensive interface for working with hyperspectral and multispectral data within the MATLAB environment. It covers the entire lifecycle of spectral imaging, including data ingestion from various formats (ENVI, NITF, TIFF, Sentinel-2, Landsat, ASTER), radiometric calibration, atmospheric correction, and advanced analytical techniques such as spectral unmixing, anomaly detection, and spectral index calculation. The skill also supports modern deep learning workflows, including pixel classification with 3D CNNs and semantic segmentation, as well as interactive labeling via the Spectral Image Labeler app.

What it does

  • Reads and writes industry-standard spectral image formats like ENVI, NITF, and GeoTIFF.
  • Performs radiometric calibration and atmospheric correction on raw spectral data.
  • Executes advanced spectral analysis including endmember extraction, unmixing, and target detection.
  • Computes standard and custom spectral indices like NDVI and EVI using optimized built-in functions.
  • Facilitates spectral-aware image segmentation and clustering.
  • Supports deep learning pipelines for pixel classification and semantic segmentation of spectral cubes.

When to use it

  • When processing hyperspectral or multispectral satellite or airborne imagery.
  • When performing quantitative analysis on spectral signatures using ECOSTRESS libraries.
  • When building deep learning models for spectral image classification or unmixing.
  • When needing to compute spectral indices or perform anomaly detection on hypercubes.
  • When managing large-scale spectral data with block processing requirements.

Advantages

  • Optimized built-in functions for spectral indices and processing, avoiding manual computation errors.
  • Seamless integration with MATLAB's deep learning and image processing toolboxes.
  • Native support for complex spectral data structures and metadata management.
  • Includes specialized apps for interactive labeling and visualization of high-dimensional data.

Usage examples

“Read a hyperspectral image from an ENVI file and calculate the NDVI.”
The agent provides code to load the file using imhypercube and compute the index using the built-in ndvi function.
“How do I perform anomaly detection on my hyperspectral cube?”
The agent provides the syntax for anomalyRX to identify anomalous pixels within the spectral data.
“Extract endmembers from my hyperspectral data.”
The agent provides a workflow using countEndmembersHFC to determine the number of endmembers followed by nfindr for extraction.
“How can I visualize my multispectral cube as a true-color image?”
The agent provides the colorize function syntax with the appropriate method parameter for multicube visualization.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/matlab/matlab-analyze-spectral-images/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip matlab-analyze-spectral-images.zip -d .agents/skills

Documentation by MathWorks

Spectral Imaging Skill

Generate MATLAB code for working with hyperspectral and multispectral data using the Hyperspectral Imaging Library for Image Processing Toolbox. Requires desktop MATLAB (not MATLAB Online or MATLAB Mobile) and the Hyperspectral Imaging Library add-on.

When to Use

  • Reading/writing hyperspectral or multispectral images (ENVI, NITF, GeoTIFF, TIFF, ASTER, Sentinel-2, Landsat)

  • Reading ECOSTRESS spectral library signatures (readEcostressSig)

  • Creating hypercube/multicube objects, band selection, cropping, block processing

  • Radiometric calibration, atmospheric correction, spectral correction

  • Denoising, sharpening, dimensionality reduction (PCA, MNF)

  • Endmember extraction, spectral unmixing, abundance estimation

  • Spectral matching, target detection, anomaly detection

  • Computing spectral indices (NDVI, EVI, custom)

  • Segmentation (spectral clustering, superpixels, ISODATA)

  • Labeling with the Spectral Image Labeler app

  • Creating ground truth objects for spectral labeling

  • Deep learning classification or unmixing of spectral images

  • Semantic segmentation of multispectral satellite imagery (DeepLabV3+ with multi-channel input)

When NOT to Use

  • General image reading/writing (use imread/imwrite)

  • Non-spectral 3-D volume data (use Medical Imaging or Image Processing Toolbox)

  • General image classification not involving spectral cubes (use Deep Learning Toolbox)

  • Non-spectral semantic segmentation of RGB/grayscale images (use Computer Vision Toolbox)

  • Point spectra or spectral libraries without spatial dimensions

Prerequisite Check

If you suspect the Hyperspectral Imaging Library might not be installed (e.g., user reports errors), verify with exist('imhypercube','file'). If not installed, suggest installing via Add-On Explorer and fall back to multibandread/imread. Do NOT run this check if you are confident the library is available.

Quick Start

% Read hyperspectral data
hcube = imhypercube("scene.hdr");

% Visualize — colorize syntax (NO name-value for basic usage):
falseColor = colorize(hcube);              % false-colored image (default, 3 most informative bands)
rgb = colorize(hcube, Method="rgb");       % true RGB (hypercube ONLY — needs R/G/B wavelengths)
cir = colorize(hcube, Method="cir");       % color infrared (hypercube ONLY)
custom = colorize(hcube, [30 20 10]);      % false color from specific band INDICES (not wavelengths)
imshow(falseColor)

% Radiometric pipeline
hcube = dn2radiance(hcube);
hcube = radiance2Reflectance(hcube);
hcube = fastInScene(hcube);

% Compute NDVI
ndviMap = ndvi(hcube);

% Endmember extraction and unmixing
numEM = countEndmembersHFC(hcube);
endmembers = nfindr(hcube, numEM);
abundance = estimateAbundanceLS(hcube, endmembers, Method="fcls");

% Anomaly detection
rxScore = anomalyRX(hcube);

% Segmentation
L = hyperseganchor(hcube, 8);

% Launch viewer app
hyperspectralViewer(hcube)

% Launch labeler app (Since R2026a)
spectralImageLabeler(hcube)

Essential Syntax (use without reading reference files)

colorize — Visualization
% HYPERCUBE (supports Method, 2 outputs, ContrastStretching default=false)
falseColor = colorize(hcube)                        % false-colored (default)
rgb = colorize(hcube, Method="rgb")                 % true color RGB
cir = colorize(hcube, Method="cir")                 % color infrared
custom = colorize(hcube, [b1 b2 b3])               % 3 band indices
[img, indices] = colorize(hcube)                    % also get band indices used
img = colorize(hcube, ContrastStretching=true)      % with CLAHE

% MULTICUBE (NO Method param, 1 output, ContrastStretching default=true)
rgb = colorize(mcube)                               % true RGB (auto-selects by wavelength)
custom = colorize(mcube, [b1 b2 b3])               % false color from band indices
img = colorize(mcube, ContrastStretching=false)     % disable contrast stretching
I/O and Band Management
hcube = imhypercube("file.hdr");                    % read ENVI/NITF/TIFF
mcube = immulticube("MTL.txt");                     % read Landsat (pass *_MTL.txt file)
mcube = immulticube("manifest.safe");              % read Sentinel-2 (pass manifest.safe file, NOT .SAFE folder)
mcube = immulticube("AST_L1T.hdf");                % read ASTER HDF
cropped = cropData(hcube, 30:110, 30:110);          % row indices, col indices (NOT [x y w h])
vnir = selectBands(hcube, Wavelength=[400 1000]);   % by wavelength range
subset = selectBands(hcube, BandNumber=[1 10 20]);  % by band index
cleaned = removeBands(hcube, Wavelength=[1350 1450]); % remove wavelength range
data = gather(hcube);                               % get M-by-N-by-C numeric array

% ACCESSING DIMENSIONS — NO NumRows/NumColumns/NumBands properties exist:
height = hcube.Metadata.Height;                     % number of rows (M)
width  = hcube.Metadata.Width;                      % number of columns (N)
bands  = hcube.Metadata.Bands;                      % number of spectral bands (C)
% For multicube: use mcube.BandSize(1,1) for height, mcube.BandSize(1,2) for width

% RESAMPLING vs SELECTING (multicube only):
mcubeUniform = resampleBands(mcube, 30);                       % RESAMPLE all bands TO 30m (keeps ALL bands, changes spatial size)
mcubeUniform = resampleBands(mcube, 30, Method="bilinear");    % interpolation: "nearest"(default),"bilinear","cubic"
mcube30m = selectBands(mcube, "DataResolution", 30);           % KEEP only bands already at 30m (DISCARDS others)
% When asked to "resample" or "match resolution" → use resampleBands
% When asked to "select" or "filter" bands by resolution → use selectBands
Spectral Indices (NEVER compute manually — use built-in functions)
% NDVI — use built-in ndvi() function (supports block processing natively)
ndviMap = ndvi(spcube);                             % direct numeric M-by-N output, range [-1,1]
ndviMap = ndvi(spcube, BlockSize=[512 512]);        % with block processing for large data

% Standard indices — use spectralIndices() (returns struct with .IndexName and .IndexImage)
indices = spectralIndices(spcube, "NDVI");          % single index → struct
indices = spectralIndices(spcube, ["NDVI","EVI"]);  % multiple → struct array
indices = spectralIndices(spcube, "all");           % all 16 supported indices
indices = spectralIndices(spcube, "NDVI", BlockSize=[512 512]);  % with block processing
% Supported: "NDVI","EVI","NDBI","NBR","MNDWI","MSI","GVI","OSAVI","SR","CMR","MCARI","MTVI","PRI","NDNI","NDMI","CAI"

% Custom formula — use customSpectralIndex() (3 required args: cube, wavelengths, @func)
indexImage = customSpectralIndex(spcube, [800 670], @(nir,red) (nir-red)./(nir+red));
indexImage = customSpectralIndex(spcube, [800 670 475], @(nir,red,blue) 2.5*(nir-red)./(nir+6*red-7.5*blue+1));
indexImage = customSpectralIndex(spcube, [560 1650], @(g,swir) (g-swir)./(g+swir), BlockSize=[512 512]);
% DO NOT manually extract bands and compute — always use these built-in functions
Detection, Matching, and Processing
% Target detection — method is POSITIONAL (3rd arg, not Name=Value)
target = resampleSignature(libData(1), hcube.Wavelength); % resample library spectrum to cube wavelengths
score = detectTarget(hcube, target, "ACE");         % "CEM","ACE","SignedACE","MF","GLRT","AMSD","OSP"
rxScore = anomalyRX(hcube);                         % higher = more anomalous

% Similarity scores — cube first, reference second (lower = better match)
score = sam(hcube, refSpectrum);                    % spectral angle mapper [0, pi]
score = sid(hcube, refSpectrum);                    % spectral information divergence

% spectralMatch — UNUSUAL ARG ORDER: library struct FIRST, then cube/spectrum
% DO NOT pass numeric vectors — first arg MUST be a struct with .Reflectance and .Wavelength fields
libData = readEcostressSig("vegetation.txt");       % returns 1-by-K struct array
score = spectralMatch(libData, hcube);              % returns M-by-N-by-K (one score map per signature)
score = spectralMatch(libData, hcube, Method="sam");% "sam"(default),"sid","sidsam","jmsam","ns3"
score = spectralMatch(libData, reflectance, wavelength); % compare against single spectrum (returns K-vector)
% Lower score = stronger match. Returns NaN when bandwidth overlap < MinBandWidth (default 300nm)
% For direct numeric comparison without library: use sam(hcube, target) or sid(hcube, target)

% Spectral clustering / segmentation (use INSTEAD of kmeans for spectral data)
L = hyperseganchor(hcube, numClusters);             % spectral-aware clustering (1 output)
[L, n] = hyperslic(hcube, K);                       % spectral superpixels (2 outputs)

% Block processing — callback receives OBJECT, must use gather()
result = apply(hcube, @(block) mean(gather(block), 3));

Workflow

For functions fully documented in the Essential Syntax and Common Mistakes sections above, generate code directly — those sections provide complete API signatures and constraints.

Read a reference file ONLY when:

  • Using a function NOT covered in Essential Syntax (e.g., sharc, empiricalLine, sharpencnmf, spectralImageLabeler)

  • Unsure about argument order or constraints for a complex workflow

  • The task involves the Spectral Image Labeler app or ground truth objects

Reference Files (consult only when needed):

CRITICAL: Common Mistakes to Avoid

These are the most frequent errors. Violating any of these will cause runtime failures:

  1. NEVER use hypercube() — deprecated. Use imhypercube() or geohypercube().

  2. cropData(hcube, 30:110, 30:110) — row/col INDEX VECTORS, not [x y w h]

  3. selectBands/removeBands require Name=Value: selectBands(hcube, BandNumber=[1 10 20]), removeBands(hcube, Wavelength=[1350 1450]). removeBands errors if range outside cube's actual wavelengths.

  4. customSpectralIndex(spcube, [800 670], @(nir,red) (nir-red)./(nir+red)) — 3 args required

  5. apply(hcube, @(block) mean(gather(block), 3)) — callback receives OBJECT, use gather()

  6. inverseProjection(pcaCube, coeff) — data first, coefficients second

  7. spectralMatch(libData, hcube) — struct from readEcostressSig FIRST. For numeric: use sam(hcube, target) directly.

  8. L = hyperseganchor(hcube, 8) (1 output); [L, n] = hyperslic(hcube, 100) (2 outputs)

  9. immulticube does NOT support ENVI. Sentinel-2: pass manifest.safe (NOT .SAFE folder). Landsat: *_MTL.txt. ASTER: .hdf.

  10. spectralIndices(hcube, "NDVI") → struct with .IndexName/.IndexImage. Use ndvi(hcube) for numeric.

  11. hyperslic with 3 bands: hyperslic(data, 100, IsInputDimReduced=true). Only params: NumIterations (max 30), IsInputDimReduced. NO Compactness.

  12. detectTarget(hcube, target, "ACE") — method is POSITIONAL, not Name=Value

  13. denoiseNGMeet: needs spatial dims > 16. Crop large images to ≤1024x1024 first.

  14. flatField(hcube, [xmin ymin width height]) — rect vector, NOT index vectors like cropData

  15. colorize(mcube) → true RGB (NO Method param!). colorize(mcube, [b1 b2 b3]) for false-color. colorize(hcube, Method="rgb") only works on hypercube.

  16. resampleBands(mcube, 30) = resizes all bands to target res. selectBands(mcube, "DataResolution", 30) = keeps only bands already at that res.

  17. NO NumRows/NumColumns/NumBands properties. Use hcube.Metadata.Height/Width/Bands. Multicube: mcube.BandSize(1,1)/mcube.BandSize(1,2).

  18. NEVER manually compute indices. Use ndvi(spcube), spectralIndices(spcube, "NDVI"), or customSpectralIndex(spcube, [wl1 wl2], @(b1,b2) formula).

  19. sam/sid refSpectra must be C-element VECTOR, not matrix.

  20. assignData(hcube, rows, cols, bands, data) — 5 args with index ranges

  21. enviwrite(hcube, "output") — hypercube ONLY, not multicube

  22. groundTruthSpectralImage labelDefs: 6 columns required including AttributeList. Property: LabelDefinitions (plural).

Key Rules

  • Pipeline: DN → radiance → reflectance → atmospheric correction. Smile correction BEFORE denoising.

  • L2 products already have surface reflectance — DN pipeline is for L1 only.

  • Research datasets (Indian Pines, PaviaU) lack calibration metadata.

  • hypercube ONLY: denoiseNGMeet, hyperpca, hypermnf, inverseProjection, sharpencnmf, countEndmembersHFC, nfindr, ppi, estimateAbundanceLS, anomalyRX, sam, sid, spectralMatch, hyperslic, sharc, empiricalLine, reduceSmile

  • hypercube + multicube: dn2radiance, radiance2Reflectance, fastInScene, detectTarget, ndvi, spectralIndices, customSpectralIndex, hyperseganchor

  • + numeric array: flatField, iarr, logResiduals, subtractDarkPixel

  • Deep learning: trainnet + dlnetwork (not trainNetwork). Use hyperpca before CNN.

  • Valid spectralIndices names: ndvi, osavi, sr, evi, gvi, ndni, pri, cai, mcari, mtvi, msi, cmr, nbr, ndbi, ndmi, mndwi (NOT "ndwi")

  • Labeler (R2026a+): groundTruthSpectralImage properties are read-only after creation


Copyright 2026 The MathWorks, Inc.

Files

references/spectral-analysis.md

Spectral Analysis Reference

Dimensionality reduction, unmixing, spectral matching, target/anomaly detection, indices, and segmentation using the Hyperspectral Imaging Library for Image Processing Toolbox.

Requirement: Desktop MATLAB only (not MATLAB Online or MATLAB Mobile). Requires the Hyperspectral Imaging Library add-on for Image Processing Toolbox.

Dimensionality Reduction

% Principal Component Analysis (PCA) — HYPERCUBE ONLY (fails on multicube)
[outputDataCube, coeff, var] = hyperpca(inputData, numComponents)
[outputDataCube, coeff, var] = hyperpca(inputData, numComponents, Method="svd")   % default
[outputDataCube, coeff, var] = hyperpca(inputData, numComponents, Method="eig")
[outputDataCube, coeff, var] = hyperpca(inputData, numComponents, MeanCentered=true) % default
% inputData: hypercube object or M-by-N-by-C array — NOT multicube
% outputDataCube: M-by-N-by-numComponents
% coeff: C-by-numComponents transformation matrix
% var: variance retained per component (%), length = numComponents
%   Total variance retained = sum(var), NOT sum(var(1:n))/sum(var)*100
% For multicube data, convert first:
%   hcube = imhypercube(im2double(gather(mcube)), mcube.Wavelength)
%   Use im2double to avoid NaN variance from integer (uint16) data
%   Ensure cropped region contains valid (non-zero) pixels — nodata regions cause NaN

% Maximum Noise Fraction (MNF) transform — HYPERCUBE ONLY (fails on multicube)
[outputDataCube, coeff] = hypermnf(inputData, numComponents)
[outputDataCube, coeff] = hypermnf(inputData, numComponents, MeanCentered=true)
% Ordered by decreasing image quality (signal-to-noise)
% inputData: hypercube object or M-by-N-by-C array — NOT multicube

% Inverse projection (reconstruct from PCA/MNF)
% WARNING: argument order is (dataCube, coeff) — NOT (coeff, dataCube)
reconstructedData = inverseProjection(pcDataCube, coeff)
% pcDataCube: M-by-N-by-P transformed cube (FIRST argument)
% coeff: C-by-P coefficient matrix from hyperpca or hypermnf (SECOND argument)
% Returns: M-by-N-by-C reconstructed data

Spectral Unmixing

ALL unmixing functions are HYPERCUBE ONLY — they fail on multicube objects. For multicube data, convert first: hcube = imhypercube(gather(mcube), mcube.Wavelength)

% Count endmembers using HFC/NWHFC (HYPERCUBE ONLY)
numEndmembers = countEndmembersHFC(inputData)
numEndmembers = countEndmembersHFC(inputData, PFA=1e-3)          % probability of false alarm (default: 1e-3)
numEndmembers = countEndmembersHFC(inputData, NoiseWhiten=true)  % NWHFC (default: true)

% Extract endmembers - N-FINDR (HYPERCUBE ONLY)
endmembers = nfindr(inputData, numEndmembers)
endmembers = nfindr(inputData, numEndmembers, NumIterations=15)         % default: 3*numEndmembers
endmembers = nfindr(inputData, numEndmembers, ReductionMethod="MNF")    % "MNF" (default) or "PCA"
% Returns: C-by-numEndmembers matrix

% Extract endmembers - Pixel Purity Index (PPI) (HYPERCUBE ONLY)
endmembers = ppi(inputData, numEndmembers)
endmembers = ppi(inputData, numEndmembers, NumVectors=10000)            % skewers (default: 10000)
endmembers = ppi(inputData, numEndmembers, ReductionMethod="MNF")       % "MNF","PCA","None"

% Extract endmembers - Fast Iterative PPI (FIPPI) (HYPERCUBE ONLY)
endmembers = fippi(inputData, numEndmembers)
endmembers = fippi(inputData, numEndmembers, ReductionMethod="MNF")     % "MNF" (default) or "PCA"

% Estimate abundance maps
abundanceMap = estimateAbundanceLS(inputData, endmembers)
abundanceMap = estimateAbundanceLS(inputData, endmembers, Method="ucls")  % unconstrained (default)
abundanceMap = estimateAbundanceLS(inputData, endmembers, Method="ncls")  % nonnegative constrained
abundanceMap = estimateAbundanceLS(inputData, endmembers, Method="fcls")  % fully constrained
% endmembers: C-by-P matrix
% abundanceMap: M-by-N-by-P double (proportion of each endmember per pixel; output always double regardless of input type)

Spectral Matching and Similarity

ALL similarity functions are HYPERCUBE ONLY — they fail on multicube objects. For multicube data, convert first: hcube = imhypercube(gather(mcube), mcube.Wavelength)

IMPORTANT: refSpectra must be a C-element VECTOR (not a matrix). To compare against multiple references, call the function once per reference spectrum in a loop, or use spectralMatch(libData, hcube) for library-based matching.

% Spectral Angle Mapper (SAM) - angle in radians [0, pi] (HYPERCUBE ONLY)
score = sam(inputData, refSpectra)       % inputData: hypercube or M-by-N-by-C array; refSpectra: C-element vector; returns M-by-N
score = sam(testSpectra, refSpectra)     % two C-element vectors, returns scalar

% Spectral Information Divergence (SID) (HYPERCUBE ONLY)
score = sid(inputData, refSpectra)
score = sid(testSpectra, refSpectra)

% SID-SAM hybrid (HYPERCUBE ONLY)
score = sidsam(inputData, refSpectra)
score = sidsam(testSpectra, refSpectra)

% Jeffries-Matusita SAM (JMSAM) (HYPERCUBE ONLY)
score = jmsam(inputData, refSpectra)
score = jmsam(testSpectra, refSpectra)

% Normalized Spectral Similarity Score (NS3) (HYPERCUBE ONLY)
score = ns3(inputData, refSpectra)
score = ns3(testSpectra, refSpectra)
% All: lower score = stronger match

% Spectral matching with library
% WARNING: libData MUST be a struct (from readEcostressSig), NOT a numeric array.
% For numeric target comparison, use sam()/sid()/sidsam()/jmsam()/ns3() directly.
score = spectralMatch(libData, hcube)
score = spectralMatch(libData, reflectance, wavelength)
score = spectralMatch(libData, hcube, Method="sam")          % "sam"(default),"sid","sidsam","jmsam","ns3"
score = spectralMatch(libData, hcube, MinBandWidth=300)      % min overlap bandwidth in nm (default: 300)
% libData: struct from readEcostressSig with Reflectance and Wavelength fields (NOT a numeric vector)
% score: M-by-N-by-K when K library entries passed (one score map per signature)

% Read ECOSTRESS spectral library
libData = readEcostressSig(filenames)             % specific files
libData = readEcostressSig(dirname)               % all files in directory
libData = readEcostressSig(dirname, keyword)      % filter by keyword
% Returns: 1-by-K struct array with Reflectance, Wavelength, and 24 metadata fields

% Resample signature to match target wavelengths (Since R2024a)
resampledRef = resampleSignature(reflectance, reqWavelength)
resampledRef = resampleSignature(reflectance, reqWavelength, origWavelength)
[resampledRef, commonWL, index] = resampleSignature(reflectance, reqWavelength)
% reflectance: struct (from readEcostressSig with Reflectance+Wavelength fields) or numeric vector
% reqWavelength: target wavelength vector (nm or um, must match units of reflectance)
% origWavelength: required when reflectance is numeric vector (length must match)
% commonWL: wavelengths present in both spectra; index: [start end] indices within reqWavelength
% NOTE: output may have FEWER bands than reqWavelength if library range doesn't cover all target wavelengths

% Remove continuum (normalize spectral signature) — WORKS WITH BOTH hypercube AND multicube
continuumRemovedRef = removeContinuum(reflectance)
continuumRemovedRef = removeContinuum(reflectance, wavelength)
continuumRemovedRef = removeContinuum(reflectance, Method="division")    % "division"(default) or "subtraction"
% reflectance: struct, hypercube, multicube, numeric vector, or 3-D array
% wavelength: required when reflectance is numeric vector or 3-D array (must match spectral dimension length)
% For multicube: all bands must have uniform resolution
% Tip: "division" works best with SAM matching; "subtraction" works best with SID/SIDSAM

Target and Anomaly Detection

% Anomaly detection using Reed-Xiaoli (RX) detector — HYPERCUBE ONLY (fails on multicube)
rxScore = anomalyRX(inputData)
% inputData: hypercube object or M-by-N-by-C array — NOT multicube
% rxScore: M-by-N matrix (higher = more anomalous, uses Mahalanobis distance)

% Target detection (multiple algorithms)
score = detectTarget(spcube, target, method)
score = detectTarget(spcube, target, method, numEndmember=5)
% spcube: hypercube, multicube, or 3-D array (must be 3-D, not 2-D)
% target: C-element single or double vector (must match number of bands in spcube exactly)
% method: "CEM" | "ACE" | "SignedACE" | "MF" | "GLRT" | "AMSD" | "OSP"
% numEndmember: for AMSD and OSP only (warns if used with other methods)
% score: M-by-N double matrix (higher = higher probability of target; always double output)

Spectral Indices

% Compute standard indices
indices = spectralIndices(spcube)                            % all applicable indices
indices = spectralIndices(spcube, indexNames)                % specific indices
indices = spectralIndices(spcube, "all")                     % all supported
indices = spectralIndices(spcube, indexNames, BlockSize=[rows cols])
% Broadband (hyperspectral + multispectral): "NDVI","EVI","NDBI","NBR","MNDWI","MSI","GVI","OSAVI","SR","CMR"
% Narrowband (hyperspectral only): "MCARI","MTVI","PRI","NDNI","NDMI","CAI"
% Returns: struct (single index) or 1-by-K struct array (multiple indices)
%   Each struct has fields: .IndexName (string) and .IndexImage (M-by-N numeric)
%   Access the image data via: indices.IndexImage or indices(k).IndexImage
% Default (no indexNames): returns only EVI, MCARI, SR — use "all" for full set
% Tip: For direct numeric NDVI output (not struct), use ndvi(spcube) instead

% NDVI specifically
output = ndvi(spcube)
output = ndvi(spcube, BlockSize=[rows cols])
% output: M-by-N matrix, range [-1, 1]. Formula: (NIR_800nm - R_670nm) / (NIR_800nm + R_670nm)

% Custom spectral index
indexImage = customSpectralIndex(spcube, wavelengths, func)
indexImage = customSpectralIndex(spcube, wavelengths, func, BlockSize=[rows cols])
% wavelengths: numeric vector of wavelengths to extract (nm)
% func: function handle, e.g., @(b1,b2) (b1-b2)./(b1+b2)
% Example:
indexImage = customSpectralIndex(hcube, [800 670], @(nir,red) (nir-red)./(nir+red));

Segmentation

% Fast spectral clustering with anchor graphs (Since R2024a) — WORKS WITH BOTH hypercube AND multicube
L = hyperseganchor(spcube, K)
L = hyperseganchor(spcube, K, NumAnchor=5)         % anchor points (generates 2*NumAnchor anchors)
L = hyperseganchor(spcube, K, NumNeighbor=5)       % neighbors per pixel
L = hyperseganchor(spcube, K, NumAttempts=3)       % clustering repetitions
L = hyperseganchor(spcube, K, MaxIterations=100)
L = hyperseganchor(spcube, K, Threshold=1e-4)      % convergence threshold
% spcube: hypercube, multicube, or M-by-N-by-C array
% K: number of clusters. Constraint: K <= 2*NumAnchor, M*N >= 2*NumAnchor, NumNeighbor <= 2*NumAnchor-1
% L: M-by-N label matrix (uint8 if K<=255, uint16 if K<=65535, uint32 if K<=2^32-1, double otherwise)
% Also accepts M-by-N 2-D array (single band) as input

% Superpixel oversegmentation (Since R2023b) — HYPERCUBE ONLY (fails on multicube)
[L, numLabels] = hyperslic(hcube, K)
[L, numLabels] = hyperslic(hcube, K, NumIterations=10)           % max 30
[L, numLabels] = hyperslic(hcube, K, IsInputDimReduced=false)    % set true if already reduced to 3 bands
% hcube: hypercube object or M-by-N-by-C array (min 3 bands) — NOT multicube
% K: desired number of superpixels
% L: M-by-N label matrix; numLabels: actual superpixel count
% Tip: set IsInputDimReduced=true when input is already PCA-reduced to 3 bands

% ISODATA unsupervised classification (Since R2024b; multicube support Since R2025a) — WORKS WITH BOTH
[L, C] = imsegisodata(inputData)
[L, C] = imsegisodata(inputData, InitialNumClusters=5)
[L, C] = imsegisodata(inputData, MaxIterations=10)             % default: 10
[L, C] = imsegisodata(inputData, MaxStandardDeviation=2)
[L, C] = imsegisodata(inputData, MinNumPixelsPerCluster=10)
[L, C] = imsegisodata(inputData, MinSamples=1)                 % min pixels per cluster before discard
[L, C] = imsegisodata(inputData, MinClusterSeparation=1)       % min distance to avoid merging
[L, C] = imsegisodata(inputData, MaxPairsToMerge=2)            % max cluster pairs merged per iteration
[L, C] = imsegisodata(inputData, NormalizeInput=true)          % normalize features (default: true)
% inputData: hypercube, multicube, 2-D grayscale, RGB, or M-by-N-by-C array
% L: M-by-N label matrix; C: K-by-C cluster centers
% Automatically determines optimal cluster count via split/merge iterations
% Tip: pass informative bands (via selectBands with endmember signatures) for better results

Hyperspectral Viewer App

% Launch viewer
hyperspectralViewer                         % open empty
hyperspectralViewer(spcube)                 % load hypercube or multicube
hyperspectralViewer(spcube, resolution)     % multicube with specific resolution (Since R2025a)
hyperspectralViewer(cube)                   % load 3-D array (limited features)
hyperspectralViewer close                   % close all instances

Key Rules

Critical Constraints
  • nfindr: numEndmembers must be > 1 and <= C (number of spectral bands)

  • hyperseganchor: K (clusters) <= 2NumAnchor; M*N (pixels) >= 2NumAnchor; NumNeighbor <= 2*NumAnchor-1

  • hyperslic: Minimum 3 spectral bands required; if exactly 3 bands, must set IsInputDimReduced=true; K must not exceed total pixel count (M*N); max 30 iterations

  • spectralIndices with no arguments: returns only EVI, MCARI, SR (not all indices) — pass "all" for full set

  • detectTarget: target vector must have exactly C elements (same as datacube bands), must be single or double; input must be 3-D; output is always double

  • removeContinuum: Use "division" with SAM-based matching; use "subtraction" with SID/SIDSAM

Endmember & Unmixing
  • nfindr (fast, reliable), ppi (robust, 10000 skewers default), fippi (fastest iterative)

  • fippi may return more endmembers than requested (iterative algorithm finds at least numEndmembers)

  • All extraction methods support ReductionMethod: "MNF" (default) or "PCA"

  • Abundance: "fcls" (sum-to-one + non-negative), "ncls" (non-negative only), "ucls" (unconstrained, default)

Target/Anomaly Detection
  • detectTarget methods: "CEM", "ACE", "SignedACE", "MF", "GLRT", "AMSD", "OSP"

  • "AMSD" and "OSP" require numEndmember parameter (default: 5)

  • anomalyRX: higher score = more anomalous (Mahalanobis distance from background)

  • detectTarget scores: higher = more likely target; similarity scores: lower = better match

  • SAM: insensitive to illumination (shape); SID: good for mixed pixels; JMSAM: discriminates spectrally close targets

Parallelism Restrictions
  • These functions do NOT support parfor: sam, sid, jmsam, ns3, spectralMatch


Copyright 2026 The MathWorks, Inc.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
MathWorks
Publisher
MathWorks (Official)
Source
matlab/matlab-agentic-toolkit · skills-catalog/image-processing-and-computer-vision/matlab-analyze-spectral-images · commit 2a7f215
Licence
BSD 2-Clause License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by MathWorks or MathWorks.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-analyze-spectral-images.zip