Skip to main content

A file-based pipeline for efficient batch processing and modeling of hyperspectral images.

Project description

SpecPipe

A high-performance, file-based pipeline for batch processing and modeling of hyperspectral images.

SpecPipe streamlines the batch testing and optimization of hyperspectral analysis workflows. It provides a structured framework to apply various image processing techniques (calibration, baseline correction, denoising, feature engineering, etc.) in combination with various machine learning models. The pipeline employs a comprehensive full-factorial design to evaluate all method combinations and generates standard reports on performance metrics, residual analysis, influence anlaysis and visualizations.

Core features:

  • Batch processing: Automate numerous data processing and modeling workflows in a single batch operation.
  • File-based: A resumable, file-based processing pipeline enabling result validation and break tolerance.
  • High-performance: Optimized for hyperspectral images with minimal memory consumption and options of GPU acceleration and pipeline-level multiprocessing.
  • Simple extensible integration: Intuitive data management and straightforward integration for custom processing functions and Scikit-learn-style models.

Table of Contents

Installation

Follow these steps to install the project:

  1. Prerequisites: Ensure you have Python 3.9 or higher installed.

  2. Install from PyPI (Recommended):

    pip install specpipe
    
  3. Install from source (for development):

    git clone https://github.com/siwei66/SpecPipe.git
    cd SpecPipe
    pip install -e specpipe
    

Usage

1. Prepare mock spectral experiment data

  • Create a directory for mock experiment data (The example uses a temporary directory):

    import tempfile
    data_dir = tempfile.mkdtemp(prefix="specpipe_example_")
    
  • Create mock data:

    from specpipe import create_test_raster, create_test_roi_xml
    create_test_raster(f"{data_dir}/example.tif")
    create_test_roi_xml(f"{data_dir}/example_roi.xml")
    

2. Configure your experiment data

2.1 Create a spectral experiment instance

  • Here we use the same directory as report directory:

    report_dir = data_dir
    
  • Create a SpecExp instance:

    from specpipe import SpecExp
    exp = SpecExp(report_dir)
    

The instance stores and organizes the data loading configurations of an experiment, which faciliates lazy-loading.

  • Check report directory:
    exp.report_directory
    

2.2. Experiment group management

  • Add experiment groups:

    exp.add_groups(['group_1', 'group_2'])
    
  • Check groups:

    exp.ls_groups()
    
  • Remove a group:

    exp.rm_group('group_2')
    

2.3. Raster image management

  • Add raster images:

    exp.add_images_by_name(
        image_name = 'example',
        image_directory = data_dir,
        group = 'group_1'
        )
    
  • Check added images:

    exp.ls_images()
    

2.4. Region of interest (ROI) management

  • Load image ROIs using suffix to image names:

    exp.add_rois_by_suffix("_roi.xml", data_dir, "group_1")
    
  • Remove ROIs by name:

    exp.rm_rois(roi_name='ROI_10')
    
  • Load ROIs to a image using ROI files by paths:

    exp.add_rois_by_file([f"{data_dir}/example_roi.xml"], image_name="example.tif", group="group_1")
    
  • Check added ROIs:

    exp.ls_rois()
    

The example xml ROI file contains 10 ROIs.

  • Check sample ROIs:
    exp.ls_rois_sample()
    

2.5. Sample labels and target values

2.5.1 Set sample labels
  • Get current sample label dataframe:

    labels = exp.ls_labels()
    
  • Set new sample labels in the dataframe: Here we use sample_1, sample_2 ... sample_10

    labels.iloc[:,1] = [f'sample_{str(i+1)}' for i in range(len(labels))]
    
  • Update sample labels using the updated dataframe:

    exp.sample_labels = labels
    
  • Check sample labels:

    exp.ls_labels()
    
2.5.2 Set target values
  • List target value dataframe:

    targets = exp.ls_sample_targets()
    
  • Create mock target values for regression and update target dataframe: Here we use 1 to 10

    targets['Target_value'] = [i for i in range(len(targets))]
    
  • Load target values from updated target dataframe:

    exp.sample_targets_from_df(targets)
    
  • Check target values:

    exp.ls_targets()
    

3. Design testing pipeline

  • SpecPipe follows a structured data processing workflow with these sequential data levels:

    Raster image data -> ROI spectra -> ROI statistics -> Traits to model
    
  • The technical data levels in SpecPipe includes:

    Images: 
        0 - "image", input image path and output processed image path.
    
    Image pixel spectra: 
        1 - "pixel_spec", 1D spectrum of image pixel (simple)
    
        2 - "pixel_specs_array", 2D spectra array of image pixels (fast)
    
        3 - "pixel_specs_tensor", 2D spectra tensor of image pixels (fast)
    
        4 - "pixel_hyperspecs_tensor", 2D hyperspectra tensor of image pixels (fastest)
    
        (See "rasterop.pixel_apply" - apply processing functions to spectra of image pixels)
    
    Image ROIs:
        5 - "image_roi", raster with sample ROIs, for spectrum extraction
    
        6 - "roispecs", 2D array of ROI spectra
    
        7 - "spec1d", arbitrary 1D data of samples, e.g. 1D spectra, spectra statistics
    
    Models:
        8 - "model", model evaluation with standard report output as files
    
  • The corresponding data processing workflow is:

    Raster image data:    0 ~ 4
        ↓
    Extract ROI spectra:  5 - "image_roi"
        ↓
    ROI spectra:          6 - "roispecs"
        ↓
    ROI statistics:       7 - "spec1d"
        ↓
    Model evaluation:     8 - "model"
    

The processing functions are wrapped in the pipeline according to the specified "data levels". Parallel processes can be added with identical "data level" and "application sequence", and they are arranged using full-factorial approach in the pipeline.

3.1 Create processing pipeline

  • Create processing pipeline from SpecExp instance configured above:
    from specpipe import SpecPipe
    
    pipe = SpecPipe(exp)
    

3.2 Image processing

  • Create some image processing functions, such as:

  • Standard normal variate:

    import numpy as np
    def snv(v):
        vmean = np.mean(v, axis=1, keepdims=True)
        vstd = np.std(v, axis=1, keepdims=True)
        snv = (v - vmean) / vstd
        return snv
    
  • Raw data for performance comparison:

    def raw(v):
        return v
    
  • Add these processing functions to the pipeline:

    pipe.add_process(
        input_data_level = 'pixel_specs_array', 
        output_data_level = 'pixel_specs_array', 
        application_sequence = 0, 
        method = snv
        )
    
  • Or we can specify the data level using the corresponding number:

    pipe.add_process(2, 2, 0, raw)
    

3.3 ROI statistics

  • Import some ROI spectral statistic metrics:

    from specpipe import roi_mean
    from specpipe import roi_median
    
  • Add these process to the pipeline:

    pipe.add_process(
        input_data_level = 'image_roi', 
        output_data_level = 'spec1d', 
        application_sequence = 0, 
        method = roi_mean
        )
    
  • Or specify data level using number:

    pipe.add_process(5, 7, 0, roi_median)
    

3.4 Sample data wrangling

  • Create a function to remove nan and inf values:

    def replace_nan(v: np.ndarray) -> np.ndarray:
        return np.nan_to_num(v, nan=0.0, posinf=0.0, neginf=0.0)
    
  • Add the process to the pipeline:

    pipe.add_process('spec1d', 'spec1d', 0, replace_nan)
    
  • Check all added processes:

    pipe.ls_process()
    
  • To remove added processes from the pipeline:

    pipe.rm_process(method='raw')
    

Processes can be removed by various criteria, the example removes the function 'raw' by its name.

3.5 Add models to the pipeline

  • Create some models:

    from sklearn.linear_model import LinearRegression
    from sklearn.ensemble import RandomForestRegressor
    from sklearn.neighbors import KNeighborsRegressor
    from sklearn.svm import SVR
    
    linear_regressor = LinearRegression()
    rf_regressor = RandomForestRegressor(n_estimators=10)
    knn_regressor = KNeighborsRegressor(n_neighbors=3)
    svr = SVR()
    
  • Add model using "add_process":

    pipe.add_process('spec1d', 'model', 1, linear_regressor, validation_method = '10-fold')
    pipe.add_process(7, 8, 1, rf_regressor, validation_method = '10-fold')
    
  • Add model using add_model:

    pipe.add_model(knn_regressor, validation_method = '10-fold')
    pipe.add_model(svr, validation_method = '10-fold')
    
  • Check added models:

    pipe.ls_model()
    
  • Check all processes including models:

    pipe.ls_process()
    

4 Run pipeline

  • Check processing chains of the pipeline:

    pipe.ls_chains()
    
  • Manually test all added processes:

    pipe.test_run()
    

The added processes are also automatically tested before formal run.

  • Run pipeline:

    pipe.run()
    
  • Set resume True to enable resuming:

    pipe.run(resume=True)
    

If the implementation is interrupted or forcibly terminated, running the pipeline again will automatically resume from the last completed step.

5 Running results

  • The pipeline produces following results for every processing chain, including:

    • Final and intermediate processing results
    • Configurations
    • Validation and application models
    • Model evaluation reports
    • Visualization
    
  • The resulting file structure is as follows:

  • For input data:

    data_directory/
    ├── SpecExp_configuration/
    │    ├── Loading_history/
    │    │   ├── Loaded_images.csv
    │    │   └── Loaded_ROIs.csv
    │    └── SpecExp_data_configuration.dill
    ├── Your_rasters.tif
    └── Your_ROIs.xml
    
  • For regression tasks, the pipeline generates:

    report_directory/
    ├── Modeling/
    │    └── Model_Evaluation_Reports/
    │        ├── Data_chain_Preprocessing_#0_Model_(model label 0)/
    │        │   ├── Model_for_application/
    │        │   ├── Model_in_validation/
    │        │   ├── Validation_results.csv
    │        │   ├── Regression_performance.csv
    │        │   ├── Residual_analysis.csv
    │        │   ├── Influence_analysis.csv
    │        │   ├── Scatter_plot.png
    │        │   └── Residual_plot.png
    │        ├── Data_chain_Preprocessing_#0_Model_(model label 1)/
    │        ├── Data_chain_Preprocessing_#1_Model_(model label 0)/
    │        ├── Data_chain_Preprocessing_#1_Model_(model label 1)/
    │        ├──  Preprocessing_#0.txt
    │        └──  Preprocessing_#1.txt
    ├── Pre_execution_test_data/
    ├── Preprocessing/
    │    ├── Step_results/
    │    ├── PreprocessingChainResult_chain_0.csv
    │    └── PreprocessingChainResult_chain_1.csv
    └── test_run/
    
  • For classification tasks, the pipeline generates:

    report_directory/
    ├── Modeling/
    │    └── Model_Evaluation_Reports/
    │        ├── Data_chain_Preprocessing_#0_Model_(model label 0)/
    │        │   ├── Model_for_application/
    │        │   ├── Model_in_validation/
    │        │   ├── Validation_results.csv
    │        │   ├── Classification_performance.csv
    │        │   ├── Residual_analysis.csv
    │        │   ├── Influence_analysis.csv
    │        │   └── ROC_curve.png
    │        ├── Data_chain_Preprocessing_#0_Model_(model label 1)/
    │        ├── Data_chain_Preprocessing_#1_Model_(model label 0)/
    │        ├── Data_chain_Preprocessing_#1_Model_(model label 1)/
    │        ├──  Preprocessing_#0.txt
    │        └──  Preprocessing_#1.txt
    ├── Pre_execution_test_data/
    ├── Preprocessing/
    │    ├── Step_results/
    │    ├── PreprocessingChainResult_chain_0.csv
    │    └── PreprocessingChainResult_chain_1.csv
    └── test_run/
    

Contributing

This is an initial release of SpecPipe. Your experience applying this toolset in your specialized field is extremely valuable. Any feedback and contributions are highly welcomed!

  • Report bugs: Found an issue? Please open a GitHub issue with details
  • Share your domain expertise: Tell us how SpecPipe works (or doesn't work) in your specific application area in discussions
  • Suggest features: Have ideas for improvements? Use the GitHub discussions or issues tab
  • Submit pull requests: Feel free to fork and submit PRs for bug fixes or small features
  • Test and provide feedback: Try it out and let us know about your experience in discussions

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

specpipe-0.1.1.tar.gz (167.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

specpipe-0.1.1-py3-none-any.whl (113.7 kB view details)

Uploaded Python 3

File details

Details for the file specpipe-0.1.1.tar.gz.

File metadata

  • Download URL: specpipe-0.1.1.tar.gz
  • Upload date:
  • Size: 167.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for specpipe-0.1.1.tar.gz
Algorithm Hash digest
SHA256 848480a2ba9356bd089e82992afd5a51e0b35e4505dad7665c447a338f9b78ee
MD5 b974caa3c6845401c3be8b38eda52edb
BLAKE2b-256 f17a60c9ebc049fb2e40a65899c812d33443b4e0612149cd76b036dd5d081b24

See more details on using hashes here.

Provenance

The following attestation bundles were made for specpipe-0.1.1.tar.gz:

Publisher: specpipe_release.yml on siwei66/specpipe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file specpipe-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: specpipe-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 113.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for specpipe-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9eedd59b4a9b7f4006dc3b977a2d5cbaf861bd1d9c43159a5e24aee08a1fb4a0
MD5 f49eaa2b55407bc0f5b80340f7b6529e
BLAKE2b-256 99aa9a4bfa174d0dda367ce190b9a713e70b66c180fd0493cbfc014c6075d840

See more details on using hashes here.

Provenance

The following attestation bundles were made for specpipe-0.1.1-py3-none-any.whl:

Publisher: specpipe_release.yml on siwei66/specpipe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page