# `SSCMEx.Model`

High-level API for ML model inference using SSCMA-Micro.

This module provides a convenient interface for creating and using
ML models (detectors, classifiers, etc.) with the TPU.

## Supported Model Types

- `:fomo` - Fast Object Mobile Object detection
- `:yolov5` - YOLOv5 object detection
- `:yolov8` - YOLOv8 object detection
- `:yolo11` - YOLO11 object detection
- `:classifier` - Image classification
- `:yolov8_pose` - YOLOv8 pose estimation
- `:yolo11_pose` - YOLO11 pose estimation
- `:yolo11_seg` - YOLO11 instance segmentation
- `:yolo26` - YOLO26 object detection

Note: With the currently pinned SSCMA-Micro commit, YOLO26 is detection-only.

## Example

    # Create engine and load model
    {:ok, engine} = SSCMEx.Engine.new()
    :ok = SSCMEx.Engine.load(engine, "/data/yolo11n.cvimodel")

    # Create detector model
    {:ok, model} = SSCMEx.Model.create(engine)

    # Configure thresholds
    :ok = SSCMEx.Model.set_config(model, :threshold_score, 0.5)

    # Prepare image (zero-copy)
    image = SSCMEx.Image.new(640, 480, :rgb888, frame_data)

    # Run inference
    {:ok, detections} = SSCMEx.Model.run(model, image)

    # Process results
    for det <- detections do
      IO.puts("Class #{det.target}: #{det.score}")
    end

# `classification`

```elixir
@type classification() :: %{score: float(), target: integer()}
```

# `config_option`

```elixir
@type config_option() :: :threshold_score | :threshold_nms
```

# `detection`

```elixir
@type detection() :: %{
  x: float(),
  y: float(),
  w: float(),
  h: float(),
  score: float(),
  target: integer()
}
```

# `inference_result`

```elixir
@type inference_result() ::
  detection()
  | classification()
  | point()
  | keypoint_result()
  | segment_result()
```

# `input_type`

```elixir
@type input_type() :: :image | :audio | :text | :unknown
```

# `keypoint`

```elixir
@type keypoint() :: %{x: float(), y: float(), z: float()}
```

# `keypoint_result`

```elixir
@type keypoint_result() :: %{box: detection(), points: [keypoint()]}
```

# `model_type`

```elixir
@type model_type() ::
  :fomo
  | :yolov5
  | :yolov8
  | :yolo11
  | :classifier
  | :yolov8_pose
  | :yolo11_pose
  | :yolo11_seg
  | :yolo26
  | :unknown
```

# `output_type`

```elixir
@type output_type() ::
  :tensor | :boxes | :classes | :points | :keypoints | :segments | :unknown
```

# `perf`

```elixir
@type perf() :: %{preprocess: integer(), inference: integer(), postprocess: integer()}
```

# `point`

```elixir
@type point() :: %{x: float(), y: float(), score: float(), target: integer()}
```

# `resource`

```elixir
@type resource() :: reference()
```

# `segment_mask`

```elixir
@type segment_mask() :: %{
  width: non_neg_integer(),
  height: non_neg_integer(),
  data: binary()
}
```

# `segment_result`

```elixir
@type segment_result() :: %{box: detection(), mask: segment_mask()}
```

# `t`

```elixir
@type t() :: %SSCMEx.Model{resource: resource()}
```

# `create`

```elixir
@spec create(
  SSCMEx.Engine.t(),
  keyword()
) :: {:ok, t()} | {:error, term()}
```

Create a new model from an engine.

The model is automatically created based on the loaded model type.
You must load a model with `SSCMEx.Engine.load/2` before calling this;
otherwise you get `{:error, ~c"no_model_loaded"}`.

## Parameters

- `engine` - An initialized engine with a loaded model
- `opts` - Options (optional)
  - `:algorithm_id` - Algorithm ID for model creation (default: 0)

## Examples

    {:ok, engine} = SSCMEx.Engine.new()
    :ok = SSCMEx.Engine.load(engine, "/path/to/model.cvimodel")
    {:ok, model} = SSCMEx.Model.create(engine)
    {:ok, model} = SSCMEx.Model.create(engine, algorithm_id: 0)

# `get_config`

```elixir
@spec get_config(t(), config_option()) :: {:ok, float()} | {:error, term()}
```

Get a model configuration option.

## Options

- `:threshold_score` - Minimum confidence score threshold
- `:threshold_nms` - Non-maximum suppression threshold

## Examples

    {:ok, threshold} = SSCMEx.Model.get_config(model, :threshold_score)

# `get_input_type`

```elixir
@spec get_input_type(t()) :: {:ok, input_type()} | {:error, term()}
```

Get the model input type.

## Examples

    {:ok, input_type} = SSCMEx.Model.get_input_type(model)
    # => :image

# `get_name`

```elixir
@spec get_name(t()) :: {:ok, String.t()} | {:error, term()}
```

Get the model name.

## Examples

    {:ok, name} = SSCMEx.Model.get_name(model)
    # => "yolo11n"

# `get_output_type`

```elixir
@spec get_output_type(t()) :: {:ok, output_type()} | {:error, term()}
```

Get the model output type.

## Examples

    {:ok, output_type} = SSCMEx.Model.get_output_type(model)
    # => :boxes

# `get_perf`

```elixir
@spec get_perf(t()) :: {:ok, perf()} | {:error, term()}
```

Get performance metrics from the last inference.

Returns a map with timing information in milliseconds:

    %{preprocess: 10, inference: 50, postprocess: 5}

## Examples

    {:ok, perf} = SSCMEx.Model.get_perf(model)
    IO.puts("Inference took #{perf.inference}ms")

# `get_type`

```elixir
@spec get_type(t()) :: {:ok, model_type()} | {:error, term()}
```

Get the model type.

## Examples

    {:ok, type} = SSCMEx.Model.get_type(model)
    # => :yolo11

# `run`

```elixir
@spec run(t(), SSCMEx.Image.t()) :: {:ok, [inference_result()]} | {:error, term()}
```

Run inference on an image.

This is a zero-copy operation - the image data is not copied.

## Parameters

- `model` - The model to run inference on
- `image` - An `%SSCMEx.Image{}` struct with the image data

## Returns

Returns a list of decoded results based on the model output type:

- `:boxes` -> `[%{x, y, w, h, score, target}, ...]`
- `:classes` -> `[%{score, target}, ...]`
- `:points` -> `[%{x, y, score, target}, ...]`
- `:keypoints` -> `[%{box: %{...}, points: [%{x, y, z}, ...]}, ...]`
- `:segments` -> `[%{box: %{...}, mask: %{width, height, data}}, ...]`

You can inspect the output type with `get_output_type/1`.

## Examples

    image = SSCMEx.Image.new(640, 480, :rgb888, frame_data)
    {:ok, results} = SSCMEx.Model.run(model, image)

# `set_config`

```elixir
@spec set_config(t(), config_option(), float()) :: :ok | {:error, term()}
```

Set a model configuration option.

## Options

- `:threshold_score` - Minimum confidence score threshold (0.0 - 1.0)
- `:threshold_nms` - Non-maximum suppression threshold (0.0 - 1.0)

## Examples

    :ok = SSCMEx.Model.set_config(model, :threshold_score, 0.5)
    :ok = SSCMEx.Model.set_config(model, :threshold_nms, 0.45)

---

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