fovea 0.5.0

A high-precision, type-safe computer vision library guaranteeing absolute image correctness at compile time
Documentation
# Pixel types


Pixel types are the vocabulary of a fovea pipeline. Choose the type that says what the bytes mean, not just how many bytes they occupy.

## Quick choice table


| You have | Start with | Why |
|---|---|---|
| 8-bit display/file RGB | `Srgb8` | This is gamma-encoded sRGB, not linear light. |
| Linear RGB samples | `Rgb8`, `Rgb16`, `RgbF32` | These can participate in linear-light operations. |
| 8-bit grayscale display/file data | `SrgbMono8` | Gamma-encoded grayscale. Decode before interpolation. |
| Scientific grayscale intensity | `Mono8`, `Mono16`, `MonoF32` | Linear mono pixels. |
| 10/12/14-bit camera samples | `Mono<10>`, `Mono<12>`, `Mono<14>` | The bit depth is part of the type. |
| BGR camera or SDK buffer | `Bgr8`, `Bgr16`, `BgrF32` | Channel order is explicit. |
| Segmentation mask | `bool` / `BinaryImage` | Native binary-image representation. |
| Connected-component labels | `Label32` | Label pixels are not grayscale pixels. |
| Raw single-sensor colour (CFA mosaic) | `bayer::BayerRggb12` and the other 19 | The mosaic pattern is part of the type. |

## `Srgb8` vs `Rgb8`


This is the most important distinction in the crate.

- `Srgb8` means gamma-encoded sRGB samples, usually from a file or display path.
- `Rgb8` means linear-light RGB samples stored in 8-bit channels.

They are not interchangeable, even if both have three `u8` channels. A resize that copies pixels can accept `Srgb8`; a resize that blends pixels requires linear-space pixels.

```rust
use fovea::image::{Image, ImageView};
use fovea::pixel::{RgbF32, Srgb8};
use fovea::transform::{SrgbGamma, convert_image};

let srgb = Image::fill(2, 2, Srgb8::new(128, 64, 32));
let linear: Image<RgbF32> = convert_image(&srgb, SrgbGamma);

assert_eq!(linear.size(), srgb.size());
```

## Mono camera bit depths


`Mono<N>` stores a monochrome value with an explicit bit depth. The constructor clamps to the range for `N`.

```rust
use fovea::pixel::Mono;

let px = Mono::<12>::new(5000);
assert_eq!(px.value(), 4095);
```

Use `Mono16` instead when your camera SDK already expands samples to a full 16-bit lane and the exact sensor bit depth is documented elsewhere in your pipeline.

## Raw Bayer camera samples


A single-sensor colour camera reports a format like `BayerRG12`. That is *not* `Mono<12>`: each sample carries one colour channel, and which one depends on its position in the repeating 2×2 tile. Typing it as mono is what lets a pipeline blur, resize, or odd-origin-crop the mosaic and quietly ruin the colour.

```rust
use fovea::pixel::bayer::{BayerPattern, BayerPixel, BayerRggb12, CfaColor};

let sample = BayerRggb12::new(2048);
assert_eq!(sample.value(), 2048);
assert_eq!(BayerRggb12::PATTERN, BayerPattern::Rggb);
assert_eq!(BayerRggb12::PATTERN.color_at(1, 1), CfaColor::Blue);
```

The four patterns × five depths are twenty distinct types, so RGGB and BGGR frames cannot be mixed. `LinearSpace` and `OriginInvariantPixel` are deliberately absent, which turns bilinear resize, `blend`, and ordinary `roi` into compile errors; `BayerSubView::aligned_bayer_roi` is the phase-preserving crop, and `BayerToMono` is the named way out of the family. See `fovea::pixel::bayer`.

## Floating-point pixels


Raw `f32` and `f64` are channels, not pixels. Use `MonoF32`, `RgbF32`, `RgbaF32`, and their `f64` counterparts when an image stores pixel data.

```rust
use fovea::image::{Image, ImageView};
use fovea::pixel::MonoF32;

let img = Image::fill(2, 2, MonoF32::new(0.5));
assert_eq!(img.pixel_at(0, 0).value(), 0.5);
```

This is not ceremony. The wrapper states the role of the scalar: it is now a pixel intensity, not an arbitrary number.

## Conversion strategies


When a conversion can lose information or change meaning, name the strategy.

| Strategy | Meaning |
|---|---|
| `SrgbGamma` | Decode or encode the sRGB transfer function. |
| `Luminance` | Convert color to grayscale using BT.601 luminance. |
| `Broadcast` | Copy mono into every color channel. |
| `ColorSwap` | Swap RGB and BGR channel order. |
| `FullRange` | Map the full source numeric range to the full destination range. |
| `Narrow` | Preserve numeric values and clamp when narrowing. |

```rust
use fovea::image::{Image, ImageView};
use fovea::pixel::{Mono8, Rgb8};
use fovea::transform::{Broadcast, convert_image};

let mono = Image::fill(1, 1, Mono8::new(200));
let rgb: Image<Rgb8> = convert_image(&mono, Broadcast);
assert_eq!(rgb.pixel_at(0, 0), Rgb8::new(200, 200, 200));
```

For the full implementation matrix, see the repository's pixel conversion matrix.