# `Image.Color`
[🔗](https://github.com/elixir-image/image/blob/v0.67.0/lib/image/color.ex#L2)

Vectorised colour-space conversions for `Nx` tensors of pixel
rows.

Per-pixel conversion via `Color.convert/2` is correct but slow
when there are tens of thousands of pixels in flight (e.g.
palette extraction from an image). The helpers in this module
do the same conversions as a single tensor op so the cost is
`O(matmul + element-wise)` rather than `O(n × Elixir-call)`.

All functions in this module require [`Nx`](https://hex.pm/packages/nx).
They are not compiled if `Nx` is not loaded.

# `srgb_tensor_to_oklab`

```elixir
@spec srgb_tensor_to_oklab(Nx.Tensor.t()) :: Nx.Tensor.t()
```

Converts a tensor of sRGB pixel rows to an Oklab tensor.

Input values are interpreted as 8-bit sRGB (0–255) when the
tensor type is integer; as unit-range linear sRGB (0.0–1.0)
is **not** assumed — even float tensors are treated as
gamma-encoded sRGB on the [0, 1] scale, matching what
`Image.to_nx/2` returns when the source image is in the
sRGB colourspace.

The pipeline is the standard one:

    sRGB → linear-sRGB → XYZ (D65) → LMS → ∛ → LMS' → Oklab

All of it is expressed as Nx tensor ops so a 90 000-row
input is one matmul-heavy pass rather than 90 000 Elixir
function calls.

### Arguments

* `tensor` is an `Nx.Tensor.t/0` of shape `{n, 3}` (alpha
  bands must be stripped before calling — alpha is a property
  of the *source* image, not of the colour conversion).

### Returns

* An `Nx.Tensor.t/0` of shape `{n, 3}`, type `f32`, where
  column `0` is `L`, column `1` is `a`, and column `2` is
  `b`.

### Examples

    iex> rgb = Nx.tensor([[255, 0, 0], [0, 255, 0], [0, 0, 255]], type: :u8)
    iex> oklab = Image.Color.srgb_tensor_to_oklab(rgb)
    iex> Nx.shape(oklab)
    {3, 3}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
