176 lines
4.6 KiB
Markdown
176 lines
4.6 KiB
Markdown
# Feature Specification v1
|
|
|
|
## Scope
|
|
|
|
Per-artwork feature extraction is deterministic and corpus-independent. Running the extractor for the same canonical inputs and extractor version must produce the same output regardless of how many other artworks exist.
|
|
|
|
## Palette input
|
|
|
|
Milestone 3 uses canonical SMK bulk `colors` and preserves source representation and order. The
|
|
bulk snapshots have no documented weights, so v1 uses explicitly labelled uniform analytical
|
|
weights (`1/n`) after deduplicating exact repeated hex values. Repetition is not interpreted as
|
|
weight.
|
|
|
|
For `colors_palette_weighted_s`, the observed format may contain repeated space-separated hex tokens. Parse defensively:
|
|
|
|
1. tokenize valid colours,
|
|
2. count each colour,
|
|
3. divide by total valid token count,
|
|
4. retain an explicit `weight_source`,
|
|
5. quality-flag malformed/partial input.
|
|
|
|
Uniform v1 weights are `palette_weighting = "uniform"`, never original SMK weights. Future
|
|
enrichment weights must retain separate provenance.
|
|
|
|
Canonical weights must satisfy approximately:
|
|
|
|
```text
|
|
weight >= 0
|
|
sum(weight) = 1
|
|
```
|
|
|
|
## Colour conversion
|
|
|
|
Use:
|
|
|
|
```text
|
|
sRGB -> linear RGB -> OKLab -> OKLCH
|
|
```
|
|
|
|
Use a single documented conversion implementation throughout v1 and test it against known reference colours.
|
|
|
|
## Perceptual colour centroid
|
|
|
|
Calculate the weighted mean in OKLab:
|
|
|
|
```text
|
|
L = Σ(wᵢLᵢ)
|
|
a = Σ(wᵢaᵢ)
|
|
b = Σ(wᵢbᵢ)
|
|
```
|
|
|
|
Store:
|
|
|
|
- `centroid_l`
|
|
- `centroid_a`
|
|
- `centroid_b`
|
|
- `centroid_chroma`
|
|
- `centroid_hue_deg`
|
|
|
|
Convert the centroid to OKLCH for chroma/hue. Hue is undefined for sufficiently achromatic centroids; use null rather than inventing a direction.
|
|
|
|
## Palette statistics
|
|
|
|
There is no `dominant_color_weight` in v1 because uniform weights do not measure image dominance.
|
|
The first source colour and preserved source order are available without claiming dominance.
|
|
|
|
### `palette_entropy_01`
|
|
Normalized Shannon entropy:
|
|
|
|
```text
|
|
H = -Σ(pᵢ ln pᵢ)
|
|
H01 = H / ln(n)
|
|
```
|
|
|
|
For `n <= 1`, define `palette_entropy_01 = 0.0`.
|
|
|
|
### `effective_palette_size`
|
|
|
|
```text
|
|
exp(H)
|
|
```
|
|
|
|
using unnormalized natural-log entropy.
|
|
|
|
### `palette_spread_oklab`
|
|
Weighted mean Euclidean OKLab distance from palette colours to the weighted centroid.
|
|
|
|
### `lightness_stddev`
|
|
Weighted standard deviation of OKLab L.
|
|
|
|
### `chroma_stddev`
|
|
Weighted standard deviation of OKLCH chroma.
|
|
|
|
### `hue_concentration_01`
|
|
Magnitude of a chroma-aware circular resultant where each hue contribution is weighted by:
|
|
|
|
```text
|
|
palette_weight * chroma
|
|
```
|
|
|
|
Return null when total chromatic mass is effectively zero.
|
|
|
|
## SMK-provided visual features
|
|
|
|
Preserve independently from our own calculations when present:
|
|
|
|
- `smk_brightness`
|
|
- `smk_contrast`
|
|
- `smk_saturation`
|
|
- `smk_colortemp`
|
|
- `smk_entropy`
|
|
|
|
SMK image entropy and our palette entropy are different concepts.
|
|
|
|
If multiple enrichment components/versions provide competing values, retain provenance and use an explicit precedence rule. Never silently mix components.
|
|
|
|
## Geometry
|
|
|
|
Canonical feature geometry:
|
|
|
|
- `net_width_cm`
|
|
- `net_height_cm`
|
|
- `net_area_cm2`
|
|
- `net_aspect_ratio`
|
|
- `image_aspect_ratio`
|
|
- `log_net_width_cm`
|
|
- `log_net_height_cm`
|
|
- `log_net_area_cm2`
|
|
|
|
Rules:
|
|
|
|
- prefer meaningful **Netto** dimensions over Brutto when both are available,
|
|
- normalize supported units to centimetres,
|
|
- do not infer physical dimensions from pixel dimensions,
|
|
- calculate area/aspect only where width + height are meaningful,
|
|
- calculate logarithms only for positive valid values.
|
|
|
|
## Aspect sanity check
|
|
|
|
For suitable 2D works where both physical and image aspect ratios exist, compare them using a symmetric log-ratio measure, e.g.:
|
|
|
|
```text
|
|
abs(log(physical_aspect / image_aspect))
|
|
```
|
|
|
|
Flag large mismatches; do not automatically “correct” either source.
|
|
|
|
## Quality/support fields
|
|
|
|
Include:
|
|
|
|
- `feature_schema_version`
|
|
- `extractor_version`
|
|
- source snapshot references
|
|
- enrichment component/version provenance when available
|
|
- `quality_flags`
|
|
|
|
Initial quality-flag vocabulary may include:
|
|
|
|
- `PALETTE_MISSING`
|
|
- `PALETTE_WEIGHTS_MISSING`
|
|
- `PALETTE_MALFORMED`
|
|
- `VERY_LOW_CHROMA`
|
|
- `DIMENSIONS_MISSING`
|
|
- `PHYSICAL_IMAGE_ASPECT_MISMATCH`
|
|
- `NON_2D_OBJECT`
|
|
- `SOURCE_LANGUAGE_MISMATCH`
|
|
|
|
Flags describe observations; they should not automatically exclude records unless a named downstream profile says so.
|
|
|
|
## Corpus-relative derivatives
|
|
|
|
Normalization is specified separately in `NORMALIZATION_V1.md`. Raw OKLab coordinates remain the
|
|
perceptual source of truth; normalized a/b variants do not preserve OKLab Euclidean distance.
|
|
Circular hue x/y are alternative interpretation fields and are not combined with a/b in the
|
|
primary color family.
|