colorscience

package
v0.0.0-...-4d863a0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 2, 2025 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// D50/10 degree observer
	WhitePointD50_10 = WhitePoint{96.72, 100.000, 81.43}
	// D55/10 degree observer
	WhitePointD55_10 = WhitePoint{95.682, 100.000, 92.149}
	// D65/10 degree observer (standard for sRGB)
	WhitePointD65_10 = WhitePoint{94.81, 100.000, 107.32}
	// D75/10 degree observer
	WhitePointD75_10 = WhitePoint{94.972, 100.000, 122.638}
	// D50/2 degree observer
	WhitePointD50_2 = WhitePoint{96.422, 100.000, 82.521}
	// D65/2 degree observer
	WhitePointD65_2 = WhitePoint{95.047, 100.000, 108.883}
	// D75/2 degree observer
	WhitePointD75_2 = WhitePoint{94.972, 100.000, 122.638}
	// Illuminant A
	WhitePointA = WhitePoint{109.850, 100.000, 35.585}
	// Illuminant B
	WhitePointB = WhitePoint{99.092, 100.000, 85.313}
	// Illuminant C
	WhitePointC = WhitePoint{98.074, 100.000, 118.232}
	// Illuminant E
	WhitePointE = WhitePoint{100.000, 100.000, 100.000}
	// F1
	WhitePointF1 = WhitePoint{92.834, 100.000, 103.665}
	// F2
	WhitePointF2 = WhitePoint{99.187, 100.000, 67.395}
	// F3
	WhitePointF3 = WhitePoint{103.754, 100.000, 49.861}
	// F4
	WhitePointF4 = WhitePoint{109.147, 100.000, 38.813}
	// F5
	WhitePointF5 = WhitePoint{90.872, 100.000, 98.723}
	// F6
	WhitePointF6 = WhitePoint{97.309, 100.000, 60.188}
	// F7
	WhitePointF7 = WhitePoint{95.044, 100.000, 108.755}
	// F8
	WhitePointF8 = WhitePoint{96.413, 100.000, 82.333}
	// F9
	WhitePointF9 = WhitePoint{100.365, 100.000, 67.868}
	// F10
	WhitePointF10 = WhitePoint{96.174, 100.000, 108.882}
	// F11
	WhitePointF11 = WhitePoint{100.966, 100.000, 64.370}
	// F12
	WhitePointF12 = WhitePoint{108.046, 100.000, 39.228}
	// Common white LEDs
	WhitePointLED_CW_6500K  = WhitePoint{95.04, 100.0, 108.88}
	WhitePointLED_NW_4300K  = WhitePoint{97.0, 100.0, 92.0}
	WhitePointLED_WW_3000K  = WhitePoint{98.5, 100.0, 67.0}
	WhitePointLED_VWW_2200K = WhitePoint{103.0, 100.0, 50.0}
)

Standard white point constants.

Functions

func AdaptXYZ

func AdaptXYZ(X, Y, Z float32, Ws, Wd WhitePoint, method AdaptationMethod) (float32, float32, float32, error)

AdaptXYZ adapts XYZ values from source white point Ws to destination white point Wd.

func AvailableIlluminants

func AvailableIlluminants() []string

AvailableIlluminants returns a list of available illuminant names.

func DeltaE76

func DeltaE76(lab1, lab2 LAB) float32

DeltaE76 calculates the CIE76 color difference (ΔE) between two LAB color values. Formula: ΔE = sqrt((L1-L2)² + (a1-a2)² + (b1-b2)²) Uses Vector3D.Distance() for efficient Euclidean distance calculation.

func DeltaE94

func DeltaE94(lab1, lab2 LAB, applicationType string) float32

DeltaE94 calculates the CIE94 color difference (ΔE94) between two LAB color values. Reference: https://en.wikipedia.org/wiki/Color_difference#CIE94 ApplicationType: "graphic" or "textiles" (graphic: K_L=1, K1=0.045, K2=0.015; textiles: K_L=2, K1=0.048, K2=0.014)

func DeltaE2000

func DeltaE2000(lab1, lab2 LAB) float32

DeltaE2000 calculates the CIEDE2000 color difference (ΔE00) between two LAB color values. Reference: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000

func FindWavelengthIndex

func FindWavelengthIndex(wavelengths vecTypes.Vector, targetWavelength float32) (int, bool)

FindWavelengthIndex finds the index in a calibrated SPD vector that corresponds to the given wavelength (or nearest wavelength). Returns the index and true if exact match, false if nearest match.

func Integrate

func Integrate(wavelengths vecTypes.Vector, values vecTypes.Vector) float32

Integrate computes the integral of f(λ) over the wavelength range using trapezoidal rule. This is equivalent to kernel · f(λ) where kernel = IntegrationKernel(wavelengths).

func IntegrationKernel

func IntegrationKernel(wavelengths vecTypes.Vector) vec.Vector

IntegrationKernel computes the trapezoidal integration kernel for a given wavelength vector. The kernel can be used to compute ∫f(λ)·dλ ≈ kernel · f(λ) using dot product. Returns a vector where kernel[i] represents the weight for f(wavelengths[i]) in the integration.

func LABToRGB

func LABToRGB(L, a, b float32, illuminant WhitePoint, out255 bool) (float32, float32, float32)

LABToRGB converts CIE LAB to sRGB by chaining LABToXYZ → XYZToRGB.

func LABToXYZ

func LABToXYZ(L, a, b float32, illuminant WhitePoint) (float32, float32, float32)

LABToXYZ converts CIE LAB to CIE XYZ color space.

func Luminance

func Luminance(X, Y, Z float32) float32

Luminance calculates luminance (cd/m²) from CIE XYZ tristimulus values. Luminance is given by the Y component of XYZ. For absolute luminance, Y should be in cd/m² (requires calibration). For relative luminance, Y is normalized (0-100).

Parameters:

  • X, Y, Z: CIE XYZ tristimulus values

Returns: luminance (Y component in cd/m² or normalized 0-100)

func RGBToLAB

func RGBToLAB(r, g, b float32, illuminant WhitePoint) (float32, float32, float32)

RGBToLAB converts sRGB to CIE LAB by chaining RGBToXYZ → XYZToLAB.

func RGBToXYZ

func RGBToXYZ(r, g, b float32) (float32, float32, float32)

RGBToXYZ converts sRGB (0-255 or 0-1) to CIE XYZ (D65).

func XYZToLAB

func XYZToLAB(X, Y, Z float32, illuminant WhitePoint) (float32, float32, float32)

XYZToLAB converts CIE XYZ to CIE LAB color space.

func XYZToRGB

func XYZToRGB(X, Y, Z float32, out255 bool) (float32, float32, float32)

XYZToRGB converts CIE XYZ (D65) to sRGB. out255: if true, return values 0-255; if false, return 0-1.

Types

type AdaptationMethod

type AdaptationMethod string

AdaptationMethod specifies the chromatic adaptation transform method.

const (
	// AdaptationBradford uses the Bradford transform matrix.
	AdaptationBradford AdaptationMethod = "bradford"
	// AdaptationVonKries uses the Von Kries transform matrix.
	AdaptationVonKries AdaptationMethod = "von_kries"
	// AdaptationCAT02 uses the CAT02 transform matrix.
	AdaptationCAT02 AdaptationMethod = "cat02"
)

type CalibrationPoint

type CalibrationPoint struct {
	Index      int     // Index in the SPD (0-based)
	Wavelength float32 // Actual wavelength in nanometers
}

CalibrationPoint represents a calibration point: index -> wavelength.

func DetectCalibrationPoints deprecated

func DetectCalibrationPoints(measuredSPD, referenceSPD SPD, minConfidence float32) []CalibrationPoint

DetectCalibrationPoints is a convenience wrapper for the SPD method. Matches a measured SPD to a reference SPD and returns calibration points.

Deprecated: Use spd.DetectCalibrationPoints(referenceSPD, minConfidence) instead.

type ColorScience

type ColorScience struct {
	// contains filtered or unexported fields
}

ColorScience provides comprehensive spectral color calculations.

func New

func New(opts ...Option) (*ColorScience, error)

New creates a new ColorScience instance with options. Defaults: D65 illuminant, 10-degree observer, WhitePointD65_10.

func (*ColorScience) Calibrate

func (cs *ColorScience) Calibrate(dst *SPD, measurement SPD, optWhitePoint ...WhitePoint) error

Calibrate calibrates a measurement SPD according to dark and light calibration readings. Normalizes SPD readings to the light SPD given non-ideal illuminant and dark current.

The calibration process:

  1. Subtracts dark current from measurement and light: corrected = raw - dark
  2. Normalizes by light reading: calibrated = corrected_measurement / corrected_light

The output is normalized to the light SPD (reflectance or transmittance [0,1] relative to the reference light).

If optWhitePoint is provided and non-zero, it's used for reflective calibration normalization. The white point's Y value is used to scale reflectance to 100% for the reference white.

Parameters:

  • dst: Output SPD (must already be initialized with wavelengths)
  • measurement: Raw measurement SPD
  • optWhitePoint: Optional white point for reflective calibration (if not provided, uses configured white point)

Returns error if dark or light calibration SPDs are not set, or if wavelengths don't match.

func (*ColorScience) ComputeCRI

func (cs *ColorScience) ComputeCRI(spd SPD) (float32, error)

ComputeCRI computes the Color Rendering Index (CRI) of an SPD as a light source. Returns the general CRI (Ra, average of 8 test color samples). CRI ranges from 0 to 100, with higher values indicating better color rendering.

The calculation compares the color rendering of test color samples under the test SPD versus under a reference illuminant with the same CCT.

Parameters:

  • spd: SPD to compute CRI for (as a light source)

Returns: CRI Ra (0-100), error

func (*ColorScience) ComputeColorTemperature

func (cs *ColorScience) ComputeColorTemperature(spd SPD) (cct float32, duv float32, err error)

ComputeColorTemperature computes the Correlated Color Temperature (CCT) and tint (duv) from an SPD. Returns CCT in Kelvin and duv (deviation from Planckian locus). Negative CCT indicates the chromaticity is outside the valid range.

Algorithm: Uses McCamy's formula for CCT and calculates duv as distance from Planckian locus.

func (*ColorScience) ComputeLuminance

func (cs *ColorScience) ComputeLuminance(spdMatrix matTypes.Matrix) (float32, error)

ComputeLuminance computes luminance from a spectral power distribution matrix. Uses the configured CMF and illuminant from ColorScience. Returns absolute or relative luminance depending on the SPD units.

Parameters:

  • cs: ColorScience instance with configured CMF and illuminant
  • spdMatrix: Spectral power distribution matrix (1 row: values only, or 2 rows: wavelengths + values)

Returns: luminance (Y component), error

func (*ColorScience) ComputeXYZ

func (cs *ColorScience) ComputeXYZ(spdMatrix matTypes.Matrix) (XYZ, error)

ComputeXYZ computes CIE XYZ tristimulus values from a spectral power distribution matrix. The input matrix can be:

  • 1 row: values only (wavelengths match CMF/illuminant, no interpolation needed)
  • 2 rows: row 0 = wavelengths, row 1 = values (interpolation to CMF/illuminant wavelengths)

func (*ColorScience) WhitePoint

func (cs *ColorScience) WhitePoint() WhitePoint

WhitePoint returns the configured white point.

type DataLoader

type DataLoader struct {
	// contains filtered or unexported fields
}

DataLoader loads and manages CIE observer and illuminant spectral datasets.

func NewDataLoader

func NewDataLoader() (*DataLoader, error)

NewDataLoader creates a new DataLoader and loads embedded SPD data.

func (*DataLoader) AvailableIlluminants

func (dl *DataLoader) AvailableIlluminants() []string

AvailableIlluminants returns a list of available illuminant names.

func (*DataLoader) GetIlluminant

func (dl *DataLoader) GetIlluminant(illuminant string) (SPD, error)

GetIlluminant returns the SPD for the specified illuminant. Returns full SPD data (no interpolation - illuminant has higher resolution than measured SPD).

func (*DataLoader) GetObserver

func (dl *DataLoader) GetObserver(observer ObserverType) (ObserverCMF, error)

GetObserver returns the Color Matching Functions for the specified observer type. Returns full CMF data (no interpolation - CMF has higher resolution than measured SPD).

type FilterShapeModel

type FilterShapeModel int

FilterShapeModel defines the filter shape model type.

const (
	FilterShapeGaussian       FilterShapeModel = 0 // Standard Gaussian (good general approximation)
	FilterShapeSuperGaussian4 FilterShapeModel = 1 // Super-Gaussian n=4 (steeper sides, better for interference filters)
	FilterShapeSuperGaussian6 FilterShapeModel = 2 // Super-Gaussian n=6 (very steep sides)
	FilterShapeBoxcar         FilterShapeModel = 3 // Boxcar (flat top, sharp sides, ideal filter)
)

type InMemoryDatabase

type InMemoryDatabase struct {
	// contains filtered or unexported fields
}

InMemoryDatabase is an in-memory implementation of SpectrumDatabase.

func (*InMemoryDatabase) Add

func (db *InMemoryDatabase) Add(name string, spd SPD, metadata SpectrumMetadata) error

Add adds a spectrum to the database.

func (*InMemoryDatabase) Get

func (db *InMemoryDatabase) Get(name string) (SpectrumEntry, error)

Get retrieves a spectrum by name.

func (*InMemoryDatabase) List

func (db *InMemoryDatabase) List() []string

List returns all spectrum names in the database.

func (*InMemoryDatabase) Remove

func (db *InMemoryDatabase) Remove(name string) error

Remove removes a spectrum from the database.

func (*InMemoryDatabase) SearchByPeaks

func (db *InMemoryDatabase) SearchByPeaks(peaks []Peak, maxResults int) ([]MatchResult, error)

SearchByPeaks searches for spectra with similar peak patterns.

func (*InMemoryDatabase) SearchBySimilarity

func (db *InMemoryDatabase) SearchBySimilarity(query SPD, maxResults int) ([]MatchResult, error)

SearchBySimilarity searches for spectra similar to the given SPD using correlation.

type LAB

type LAB vec.Vector3D

LAB represents CIE LAB color values.

func NewLAB

func NewLAB(L, a, b float32) LAB

NewLAB creates a new LAB from L, a, b values.

func (LAB) A

func (lab LAB) A() float32

A returns the a component (green-red axis).

func (LAB) B

func (lab LAB) B() float32

B returns the b component (blue-yellow axis).

func (LAB) L

func (lab LAB) L() float32

L returns the L component (lightness).

func (LAB) LAB

func (lab LAB) LAB() (float32, float32, float32)

LAB returns the L, a, b components.

func (LAB) ToRGB

func (lab LAB) ToRGB(illuminant WhitePoint, out255 bool) RGB

ToRGB converts LAB to RGB using the provided white point. out255: if true, return values 0-255; if false, return 0-1.

func (LAB) ToXYZ

func (lab LAB) ToXYZ(illuminant WhitePoint) XYZ

ToXYZ converts LAB to XYZ using the provided white point.

type MatchResult

type MatchResult struct {
	Entry      SpectrumEntry // The matched spectrum entry
	Score      float32       // Similarity score (0-1, higher is better)
	Confidence float32       // Confidence in the match (0-1)
}

MatchResult represents a match result from database search.

type ObserverCMF

type ObserverCMF struct {
	matTypes.Matrix
}

ObserverCMF contains Color Matching Functions as a 4-row matrix. Row 0: wavelengths Row 1: XBar Row 2: YBar Row 3: ZBar ObserverCMF embeds matTypes.Matrix interface, allowing methods to be attached while implementing the interface.

func LoadCMF

func LoadCMF(observer ObserverType) (ObserverCMF, error)

LoadCMF loads Color Matching Functions for the specified observer. Returns full CMF data (CMF has higher resolution than measured SPD).

func (ObserverCMF) Len

func (cmf ObserverCMF) Len() int

Len returns the number of wavelength/CMF pairs in a CMF.

func (ObserverCMF) Wavelengths

func (cmf ObserverCMF) Wavelengths() SPD

Wavelengths returns the wavelengths as an SPD (row 0 + row 0).

func (ObserverCMF) WavelengthsValues

func (cmf ObserverCMF) WavelengthsValues() vec.Vector

WavelengthsValues returns the wavelength vector (row 0) from a CMF.

func (ObserverCMF) XBar

func (cmf ObserverCMF) XBar() SPD

XBar returns the XBar as an SPD (wavelengths row + XBar row 1).

func (ObserverCMF) XBarValues

func (cmf ObserverCMF) XBarValues() vec.Vector

XBarValues returns the XBar vector (row 1) from a CMF.

func (ObserverCMF) YBar

func (cmf ObserverCMF) YBar() SPD

YBar returns the YBar as an SPD (wavelengths row + YBar row 2).

func (ObserverCMF) YBarValues

func (cmf ObserverCMF) YBarValues() vec.Vector

YBarValues returns the YBar vector (row 2) from a CMF.

func (ObserverCMF) ZBar

func (cmf ObserverCMF) ZBar() SPD

ZBar returns the ZBar as an SPD (wavelengths row + ZBar row 3).

func (ObserverCMF) ZBarValues

func (cmf ObserverCMF) ZBarValues() vec.Vector

ZBarValues returns the ZBar vector (row 3) from a CMF.

type ObserverType

type ObserverType string

ObserverType represents a standard observer type.

const (
	Observer2Deg  ObserverType = "2"  // CIE 1931 2 Degree Standard Observer
	Observer10Deg ObserverType = "10" // CIE 1964 10 Degree Standard Observer
)

type Option

type Option func(*ColorScience) error

Option configures a ColorScience instance.

func WithDark

func WithDark(dark matTypes.Matrix) Option

WithDark sets the dark calibration SPD (sensor dark reading). This is used to subtract dark current from measurements.

func WithIlluminant

func WithIlluminant(name string) Option

WithIlluminant sets the illuminant by name (e.g., "D65", "D50", "A"). Default: "D65" Automatically sets appropriate white point based on illuminant name and observer.

func WithIlluminantSPD

func WithIlluminantSPD(illuminant matTypes.Matrix) Option

WithIlluminantSPD sets a custom illuminant SPD.

func WithLight

func WithLight(light matTypes.Matrix) Option

WithLight sets the light calibration SPD (reference white/light reading). This is used to normalize measurements to the reference illuminant.

func WithObserver

func WithObserver(observer ObserverType) Option

WithObserver sets the observer type (default: Observer10Deg).

func WithWhitePoint

func WithWhitePoint(wp WhitePoint) Option

WithWhitePoint sets the white point (default: WhitePointD65_10). Overrides any white point that would be auto-set by WithIlluminant.

type Peak

type Peak struct {
	Index      int     // Index in the SPD
	Wavelength float32 // Wavelength at the peak
	Value      float32 // Peak value (intensity)
	Prominence float32 // Prominence of the peak (height above surrounding baseline)
}

Peak represents a detected peak in an SPD.

type RGB

type RGB vec.Vector3D

RGB represents sRGB color values.

func NewRGB

func NewRGB(r, g, b float32) RGB

NewRGB creates a new RGB from r, g, b values.

func (RGB) B

func (rgb RGB) B() float32

B returns the B component.

func (RGB) G

func (rgb RGB) G() float32

G returns the G component.

func (RGB) R

func (rgb RGB) R() float32

R returns the R component.

func (RGB) RGB

func (rgb RGB) RGB() (float32, float32, float32)

RGB returns the r, g, b components.

func (RGB) ToLAB

func (rgb RGB) ToLAB(illuminant WhitePoint) LAB

ToLAB converts RGB to LAB using the provided white point.

func (RGB) ToXYZ

func (rgb RGB) ToXYZ() XYZ

ToXYZ converts RGB to XYZ.

type SPD

type SPD struct {
	matTypes.Matrix
}

SPD represents a Spectral Power Distribution as a 2-row matrix. Row 0: wavelengths Row 1: values SPD embeds matTypes.Matrix interface, allowing methods to be attached while implementing the interface.

func CalibrateSensorSensitivity

func CalibrateSensorSensitivity(referenceSPD, sensorResponseSPD SPD) (SPD, error)

CalibrateSensorSensitivity calibrates sensor spectral sensitivity using known reference measurements. Given a reference SPD with known spectral power and sensor responses to that SPD, calculates the sensor's spectral sensitivity (responsivity) function.

The calibration process:

  1. Measures sensor response to known reference SPD (calibration lamp, standard illuminant)
  2. Calculates sensitivity = response / reference_SPD at each wavelength
  3. Returns calibrated sensitivity SPD (wavelengths, sensitivity values)

Parameters:

  • referenceSPD: Known reference SPD (e.g., standard illuminant or calibration lamp)
  • sensorResponseSPD: Measured sensor response to the reference SPD (must have same wavelengths)

Returns: calibrated sensitivity SPD (wavelengths, sensitivity values), error

Example:

  • Reference: D65 illuminant with known spectral power
  • Sensor response: measured values when exposed to D65
  • Result: sensor sensitivity function (responsivity at each wavelength)

func CalibrateSensorSensitivityWithDark

func CalibrateSensorSensitivityWithDark(referenceSPD, sensorResponseSPD, darkSPD SPD) (SPD, error)

CalibrateSensorSensitivityWithDark calibrates sensor spectral sensitivity accounting for dark current. Similar to CalibrateSensorSensitivity but subtracts dark current from sensor response first.

The calibration process:

  1. Subtracts dark current: corrected_response = response - dark
  2. Calculates sensitivity = corrected_response / reference_SPD at each wavelength
  3. Returns calibrated sensitivity SPD

Parameters:

  • referenceSPD: Known reference SPD (e.g., standard illuminant or calibration lamp)
  • sensorResponseSPD: Measured sensor response to the reference SPD
  • darkSPD: Dark current measurement (sensor response with no light)

Returns: calibrated sensitivity SPD, error

func FilterSPDFromChannel

func FilterSPDFromChannel(channel SensorChannel, wavelengths vecTypes.Vector) SPD

FilterSPDFromChannel creates an SPD representing a spectral filter response from center wavelength and FWHM. Supports multiple filter shapes optimized for interference filters like those in AS734x sensors.

Filter shapes:

  • Gaussian (default): Good general approximation, y = exp(-0.5 * ((λ - center) / sigma)^2)
  • Super-Gaussian (n=4): Steeper sides, better matches interference filters
  • Super-Gaussian (n=6): Very steep sides, closer to ideal filters
  • Boxcar: Flat top with sharp sides (idealized)

For interference filters (AS734x), Super-Gaussian (n=4) is typically most accurate.

Parameters:

  • channel: SensorChannel with center wavelength, FWHM, and optional shape/asymmetry
  • wavelengths: Target wavelength vector to evaluate the filter at

Returns: SPD representing the filter spectral response

func GaussianSPDFromChannel

func GaussianSPDFromChannel(channel SensorChannel, wavelengths vecTypes.Vector) SPD

GaussianSPDFromChannel is a convenience wrapper for FilterSPDFromChannel using Gaussian shape. Deprecated: Use FilterSPDFromChannel with FilterShapeGaussian instead for better control.

func LoadIlluminantSPD

func LoadIlluminantSPD(illuminantName string) (SPD, error)

LoadIlluminantSPD loads the SPD for the specified illuminant. Returns full SPD data (illuminant has higher resolution than measured SPD).

func NewSPD

func NewSPD(wavelengths, values vecTypes.Vector) SPD

NewSPD creates a new SPD from wavelength and value vectors.

func ReconstructSPDFromChannels

func ReconstructSPDFromChannels(
	channels []SensorChannel,
	targetWavelengths vecTypes.Vector,
	useDampedLS bool,
	lambda float32,
) (SPD, error)

ReconstructSPDFromChannels reconstructs an SPD from sensor channels specified by center wavelength and FWHM. This is a convenience wrapper that creates a new SPD with the target wavelengths and zeroed values, then calls ReconstructFromChannels().

Filter shape recommendations:

  • FilterShapeSuperGaussian4 (recommended for AS734x): Best accuracy for interference filters
  • FilterShapeSuperGaussian6: For very steep-sided filters
  • FilterShapeGaussian: Simple approximation (default, less accurate for interference filters)

Parameters:

  • channels: Array of SensorChannel with center wavelength, FWHM, readings, and optional shape/uncertainty
  • targetWavelengths: Wavelength vector for the reconstructed SPD
  • useDampedLS: If true, use damped least squares (Tikhonov regularization) - recommended for stability
  • lambda: Regularization parameter for damped least squares (typically 0.01-0.1, only used if useDampedLS=true)

Returns: Reconstructed SPD, error

Example for AS7341 (recommended - using Super-Gaussian n=4):

wavelengths := vec.NewFrom(350.0, 360.0, 370.0, ..., 1000.0)
channels := []colorscience.SensorChannel{
    {Name: "F1", CenterWL: 415, FWHM: 20, Reading: 1000, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    {Name: "F2", CenterWL: 445, FWHM: 20, Reading: 1500, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    // ... more channels
}
spd, err := colorscience.ReconstructSPDFromChannels(channels, wavelengths, true, 0.01)

func ReconstructSPDWithConstraints

func ReconstructSPDWithConstraints(
	sensorResponses []SensorResponse,
	targetWavelengths vecTypes.Vector,
	useDampedLS bool,
	lambda float32,
	smoothnessWeight float32,
) (SPD, error)

ReconstructSPDWithConstraints reconstructs SPD with additional constraints. This is a more advanced version that allows specifying constraints like: - Non-negativity (already enforced in SPD.Reconstruct) - Smoothness (can be added via regularization) - Known values at specific wavelengths

For now, this is a convenience wrapper that creates an SPD with the target wavelengths and zeroed values, then calls SPD.Reconstruct(). Future enhancements could add: - Smoothness regularization (second derivative penalty) - Known value constraints - Bounds on values

func (SPD) Calibrate

func (spd SPD) Calibrate(pairs ...float32) (SPD, error)

Calibrate calibrates the SPD using known wavelength calibration points. Takes variadic float32 values that must be even in length, interpreted as (index, wavelength) pairs. The SPD must already be initialized with wavelengths and values rows.

Calibration process:

  1. Uses the calibration points to calculate wavelengths for all indices using linear interpolation
  2. Updates the wavelength row of the SPD with the calibrated wavelengths
  3. The values row remains unchanged (values stay at their indices, wavelengths are corrected)

Example: Calibrate(0, 400.0, 100, 700.0) calibrates so that index 0 = 400nm, index 100 = 700nm, and wavelengths for intermediate indices are linearly interpolated.

func (SPD) DetectCalibrationPoints

func (spd SPD) DetectCalibrationPoints(referenceSPD SPD, minConfidence float32) []CalibrationPoint

DetectCalibrationPoints matches this SPD to a reference SPD and returns calibration points. Uses correlation-based matching to find corresponding features between the two spectra. Returns (index, wavelength) pairs that can be used with SPD.Calibrate().

The algorithm:

  1. Interpolates both SPDs to a common wavelength grid
  2. Uses sliding window correlation to find best matches
  3. Detects peaks in both spectra and matches them
  4. Returns calibration points with confidence scores >= minConfidence

Parameters:

  • referenceSPD: The reference SPD with known wavelengths (e.g., D65 illuminant, any known spectrum)
  • minConfidence: Minimum confidence score (0-1) for a match to be included

Returns: slice of calibration points sorted by index in this SPD

func (SPD) Interpolate

func (spd SPD) Interpolate(targetWavelengths vecTypes.Vector) SPD

Interpolate resamples the SPD to new wavelengths using linear interpolation. The SPD is interpolated to match the target wavelengths (CMF/illuminant have higher resolution).

func (SPD) Len

func (spd SPD) Len() int

Len returns the number of wavelength/value pairs in an SPD.

func (SPD) Peaks

func (spd SPD) Peaks(threshold, minProminence float32) []Peak

Peaks detects local maxima (peaks) in the SPD. Peaks are detected where values are higher than their neighbors. Only peaks with prominence >= minProminence are returned. Threshold filters out peaks below a minimum value.

Parameters:

  • threshold: Minimum peak value to consider (0 = no threshold)
  • minProminence: Minimum prominence for a peak to be included (0 = no prominence filter)

Returns: slice of detected peaks, sorted by wavelength

func (SPD) Reconstruct

func (spd SPD) Reconstruct(sensorResponses []SensorResponse, useDampedLS bool, lambda float32) error

Reconstruct reconstructs the SPD values from measurements of multiple photodetectors with known spectral responses. The SPD must already be initialized with wavelengths row and zeroed values row. This solves the inverse problem: given sensor responses R and sensor spectral sensitivities S, find the stimulus SPD X such that R = S · X.

The problem is formulated as a linear system: R = S · X where:

  • R is a vector of sensor readings (length = num_sensors)
  • S is a matrix of sensor responses (num_sensors × num_wavelengths)
  • X is the unknown stimulus SPD values (length = num_wavelengths)

This is solved using pseudo-inverse: X = S^+ · R

Parameters:

  • sensorResponses: Array of sensor responses with their measured readings
  • useDampedLS: If true, use damped least squares (Tikhonov regularization)
  • lambda: Regularization parameter for damped least squares (only used if useDampedLS=true)

Returns error if reconstruction fails.

func (SPD) ReconstructFromChannels

func (spd SPD) ReconstructFromChannels(channels []SensorChannel, useDampedLS bool, lambda float32) error

ReconstructFromChannels reconstructs an SPD from sensor channels specified by center wavelength and FWHM. This is a convenience wrapper that: 1. Creates filter SPD responses from channel specifications (Gaussian, Super-Gaussian, or Boxcar) 2. Converts to SensorResponse objects 3. Calls SPD.Reconstruct() or SPD.ReconstructWeighted() based on whether uncertainties are provided

This is useful for sensors like AS734x chips that only provide center wavelength and bandwidth information.

Filter shape recommendations for AS734x:

  • FilterShapeSuperGaussian4 (recommended): Best matches interference filter characteristics
  • FilterShapeSuperGaussian6: For very steep-sided filters
  • FilterShapeGaussian: Simple approximation (faster, less accurate)
  • FilterShapeBoxcar: Idealized filter (sharp sides, flat top)

If channels have Uncertainty > 0, weighted least squares is used automatically.

Parameters:

  • spd: SPD to reconstruct (must have wavelengths initialized, values will be filled)
  • channels: Array of SensorChannel with center wavelength, FWHM, readings, and optional shape/uncertainty
  • useDampedLS: If true, use damped least squares (Tikhonov regularization)
  • lambda: Regularization parameter for damped least squares (only used if useDampedLS=true)

Returns error if reconstruction fails.

Example for AS7341 (recommended - using Super-Gaussian for accuracy):

channels := []colorscience.SensorChannel{
    {Name: "F1", CenterWL: 415, FWHM: 20, Reading: 1000, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    {Name: "F2", CenterWL: 445, FWHM: 20, Reading: 1500, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    {Name: "F3", CenterWL: 480, FWHM: 20, Reading: 1200, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    // ... more channels
}
spd := colorscience.NewSPD(wavelengths, vec.New(len(wavelengths)))
err := spd.ReconstructFromChannels(channels, true, 0.01) // Use damped LS for stability

Example with confidence intervals (weighted reconstruction):

channels := []colorscience.SensorChannel{
    {Name: "F1", CenterWL: 415, FWHM: 20, Reading: 1000, Uncertainty: 0.05, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    {Name: "F2", CenterWL: 445, FWHM: 20, Reading: 1500, Uncertainty: 0.03, FilterShape: int(colorscience.FilterShapeSuperGaussian4)},
    // Uncertainty = confidence interval as fraction (0.05 = 5% uncertainty)
}

func (SPD) ReconstructWeighted

func (spd SPD) ReconstructWeighted(sensorResponses []SensorResponse, weights vecTypes.Vector, useDampedLS bool, lambda float32) error

ReconstructWeighted reconstructs the SPD using weighted least squares, accounting for measurement uncertainty. Measurements with higher uncertainty (lower confidence) are given less weight in the reconstruction.

Weighted least squares: minimize ||W · (S · X - R)||² where W is a diagonal weight matrix with weights w_i = 1 / uncertainty_i²

The solution is: X = (S^T · W² · S)^(-1) · S^T · W² · R

Parameters:

  • sensorResponses: Array of sensor responses with readings
  • weights: Weight vector (one per sensor). Higher weight = more trust in measurement. Weights are normalized if needed.
  • useDampedLS: If true, use weighted damped least squares (Tikhonov regularization)
  • lambda: Regularization parameter for damped least squares (only used if useDampedLS=true)

Returns error if reconstruction fails.

Note: If weights is nil or all zeros, falls back to unweighted reconstruction.

func (SPD) Valleys

func (spd SPD) Valleys(threshold, minProminence float32) []Valley

Valleys detects local minima (valleys) in the SPD. Valleys are detected where values are lower than their neighbors. Only valleys with prominence >= minProminence are returned. Threshold filters out valleys above a maximum value.

Parameters:

  • threshold: Maximum valley value to consider (0 = no threshold, use very large value for no filter)
  • minProminence: Minimum prominence for a valley to be included (0 = no prominence filter)

Returns: slice of detected valleys, sorted by wavelength

func (SPD) Values

func (spd SPD) Values() vec.Vector

Values returns the values vector (row 1) from an SPD.

func (SPD) Wavelengths

func (spd SPD) Wavelengths() vec.Vector

Wavelengths returns the wavelength vector (row 0) from an SPD.

type SensorChannel

type SensorChannel struct {
	Name        string  // Channel name/identifier
	CenterWL    float32 // Center wavelength in nanometers
	FWHM        float32 // Full width at half maximum (FWHM) in nanometers
	Reading     float32 // Measured response value (optional, can be set later)
	Uncertainty float32 // Measurement uncertainty/confidence (0 = no weight, >0 = 1/uncertainty² weight). If >0, used as weight in weighted least squares.
	FilterShape int     // Filter shape model: 0=Gaussian (default), 1=Super-Gaussian (n=4, steeper), 2=Super-Gaussian (n=6, very steep), 3=Boxcar (flat top, sharp sides)
	Asymmetry   float32 // Asymmetry factor (-1 to 1): 0=symmetric, >0=redshifted, <0=blueshifted. Default 0.
}

SensorChannel represents a sensor channel with center wavelength and full width at half maximum (FWHM). This is useful for sensors like AS734x chips that only provide center wavelength and bandwidth.

type SensorResponse

type SensorResponse struct {
	Name     string          // Sensor name/identifier
	Response matTypes.Matrix // Spectral response of the sensor (wavelengths -> response) - must be 2-row SPD matrix
	Reading  float32         // Measured response value to the stimulus
}

SensorResponse represents a photodetector with its known spectral response.

func SensorChannelsToResponses

func SensorChannelsToResponses(channels []SensorChannel, targetWavelengths vecTypes.Vector) []SensorResponse

SensorChannelsToResponses converts SensorChannel specifications with readings to SensorResponse objects. Each channel's filter response SPD (Gaussian, Super-Gaussian, or Boxcar) is evaluated at the target wavelengths.

Parameters:

  • channels: Array of SensorChannel with center wavelength, FWHM, readings, and optional shape/uncertainty
  • targetWavelengths: Wavelength vector to evaluate the filter responses at

Returns: Array of SensorResponse ready for use with SPD.Reconstruct() or SPD.ReconstructWeighted()

type SpectrumDatabase

type SpectrumDatabase interface {
	// Add adds a spectrum to the database.
	Add(name string, spd SPD, metadata SpectrumMetadata) error

	// SearchBySimilarity searches for spectra similar to the given SPD.
	// Returns ranked matches sorted by similarity score (highest first).
	SearchBySimilarity(query SPD, maxResults int) ([]MatchResult, error)

	// SearchByPeaks searches for spectra with similar peak patterns.
	// Returns ranked matches sorted by similarity score (highest first).
	SearchByPeaks(peaks []Peak, maxResults int) ([]MatchResult, error)

	// Get retrieves a spectrum by name.
	Get(name string) (SpectrumEntry, error)

	// List returns all spectrum names in the database.
	List() []string

	// Remove removes a spectrum from the database.
	Remove(name string) error
}

SpectrumDatabase provides an interface for storing and searching spectra.

func NewSpectrumDatabase

func NewSpectrumDatabase() SpectrumDatabase

NewSpectrumDatabase creates a new in-memory spectrum database.

type SpectrumEntry

type SpectrumEntry struct {
	SPD      SPD              // The spectrum SPD
	Metadata SpectrumMetadata // Metadata about the spectrum
}

SpectrumEntry represents a spectrum entry in the database.

type SpectrumMetadata

type SpectrumMetadata struct {
	Name        string            // Spectrum name/identifier
	Description string            // Description of the spectrum
	Type        string            // Spectrum type (reflectance, absorption, raman, emission, etc.)
	Properties  map[string]string // Additional properties (material, source, etc.)
}

SpectrumMetadata contains metadata for a spectrum in the database.

type Valley

type Valley struct {
	Index      int     // Index in the SPD
	Wavelength float32 // Wavelength at the valley
	Value      float32 // Valley value (intensity)
	Prominence float32 // Prominence of the valley (depth below surrounding baseline)
}

Valley represents a detected valley in an SPD.

type WhitePoint

type WhitePoint vec.Vector3D

WhitePoint represents a CIE XYZ white point.

func (WhitePoint) XYZ

func (wp WhitePoint) XYZ() (float32, float32, float32)

XYZ returns the XYZ components of the white point.

type XYZ

type XYZ vec.Vector3D

XYZ represents CIE XYZ tristimulus values.

func NewXYZ

func NewXYZ(X, Y, Z float32) XYZ

NewXYZ creates a new XYZ from X, Y, Z values.

func (XYZ) Adapt

func (xyz XYZ) Adapt(Ws, Wd WhitePoint, method AdaptationMethod) (XYZ, error)

Adapt adapts XYZ values from source white point to destination white point. Returns adapted XYZ using the specified adaptation method.

func (XYZ) Luminance

func (xyz XYZ) Luminance() float32

Luminance returns the luminance (Y component) of the XYZ value.

func (XYZ) ToLAB

func (xyz XYZ) ToLAB(illuminant WhitePoint) LAB

ToLAB converts XYZ to LAB using the provided white point.

func (XYZ) ToRGB

func (xyz XYZ) ToRGB(out255 bool) RGB

ToRGB converts XYZ to RGB. out255: if true, return values 0-255; if false, return 0-1.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL