Point detection

Point detection returns one x, y location per object instead of a bounding box. LibreYOLO exposes it as the point task, and a prediction carries one row of x, y, class and confidence per object.

Definition

The point task locates each object with a single x, y coordinate and a class, with no width, height or mask. Because a prediction is a flat list of objects, the row count is the object count, which is what makes this the counting task.

A prediction fills result.points, a Points payload wrapping an (N, 4) array of x, y, class, confidence rows in original-image pixels. .xy returns the coordinates, .xyn the same coordinates divided by the image size, .cls the class indices and .conf the scores; len() returns the number of points. result.boxes stays empty, so iou and max_det have nothing to act on.

Models

Three families serve point, and they are not interchangeable.

FOMO is the fixed-vocabulary option: a grid classifier that labels each cell of a low-resolution grid as background or an object center. It is the only point family LibreYOLO can train, and the only one that exports.

LocateAnything takes text instead of a class index, so the vocabulary is whatever phrase you write. It needs the vlm extra, is constructed as LibreLocateAnything rather than through the LibreYOLO() factory, and its weights are restricted to non-commercial use. The exact terms, and the two further licenses the checkpoint composes, are on its page.

SenseNova-Vision reaches point through the same prompted-generation checkpoint it uses for six other tasks, loaded with LibreVLM("sensenova-vision", task="point"). It needs the sensenova extra, and every prediction is a generation pass over a 7B model, so expect noticeably higher per-image latency than a purpose-built detector. Its weights are non-commercial; the license is on its page.

Predict

LibreFOMO weights are the one exception to automatic download on this site. LibreYOLO("LibreFOMOs-point.pt") looks for that file on disk and raises a ValueError naming it rather than fetching it. Download a checkpoint from the LibreYOLO organization on Hugging Face first and load it by local path, or train your own.

Predict points and count them
from libreyolo import LibreYOLO, SAMPLE_IMAGE # LibreFOMO weights are not auto-downloaded. Fetch a checkpoint from# https://huggingface.co/LibreYOLO first and load it by local path.model = LibreYOLO("./LibreFOMOs-point.pt")result = model(SAMPLE_IMAGE, save=True) points = result.pointsprint(len(points))     # object countprint(points.xy)       # (N, 2) centers in original-image pixelsprint(points.cls, points.conf)
Normalized coordinates and per-class counts
from collections import Counter from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("./LibreFOMOs-point.pt")result = model(SAMPLE_IMAGE) points = result.points.numpy()print(points.xyn)                          # same centers in [0, 1]print(Counter(points.cls.astype(int).tolist()))

The filename has to carry the -point task suffix for the loader to recognize it. predict(..., nms_radius=1) controls how many grid cells apart two FOMO detections must be to both survive. See prediction for sources, streaming and result handling.

Dataset format

point has no label format of its own. The point families read the standard YOLO detection layout and derive one center from each box row, so cx cy is the point and w h only decide whether the row is valid.

dataset/
  data.yaml
  images/
    train/scene.jpg
    val/scene.jpg
  labels/
    train/scene.txt
    val/scene.txt

Each label file holds one row per object, with normalized coordinates:

<class_id> <cx> <cy> <w> <h>
yaml
path: dataset
train: images/train
val: images/val
nc: 1
names: {0: seedling}

A missing or empty label file means no objects. See dataset formats for the full contract.

Train

FOMO is the only point family with a training implementation. train() on LocateAnything and on SenseNova-Vision raises NotImplementedError; fine-tune those upstream and load the result.

Train FOMO on a YOLO dataset
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")model.train(data="my-dataset.yaml", epochs=40, batch=32, lr0=3e-4)
Predict with the trained checkpoint
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("./LibreFOMOs-point.pt")results = model.train(data="my-dataset.yaml", epochs=40) # train() reloads the best checkpoint into the same object, so the# model predicts with the trained weights when the call returns.print(results["best_checkpoint"])print(model(SAMPLE_IMAGE).points.xy)

imgsz is not a free choice for FOMO: it defaults to the loaded checkpoint's native resolution, and passing a different value raises ValueError naming the size it expects. See training for datasets, loggers and multi-GPU, and the FOMO page for this family's defaults.

Validate

val() matches predicted points to ground-truth points one-to-one with the Hungarian algorithm, over a sweep of distance thresholds. A threshold is a Euclidean distance in normalized image coordinates, and the default sweep is ten values from 0.01 to 0.10.

Validate and read the metric keys
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/precision"], metrics["metrics/recall"])print(metrics["metrics/f1"])print(metrics["metrics/mAP@[0.01:0.10]"])   # fitnessprint(metrics["metrics/MLE"])               # mean localization errorprint(metrics["metrics/MAE"], metrics["metrics/RMSE"])   # count error
Change the distance thresholds
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt") # The sweep bounds are part of the key text, so a custom sweep# renames the mAP keys it produces.metrics = model.val(data="my-dataset.yaml", dist_thresholds=[0.02, 0.05]) print(metrics["metrics/mAP@0.02"])print(metrics["metrics/mAP@[0.02:0.05]"])

metrics/precision, metrics/recall and metrics/f1 are macro-averaged over classes at the strictest threshold in the sweep, 0.01 by default. metrics/mAP@0.01 is average precision at that same threshold, and metrics/mAP@[0.01:0.10] is the mean over the whole sweep. That sweep value is also fitness, the number best-checkpoint selection reads. Both mAP keys are built from the thresholds in use, so passing dist_thresholds= renames them.

metrics/MLE is the mean distance between matched pairs at the strictest threshold, in the same normalized units. metrics/MAE and metrics/RMSE are counting metrics rather than localization ones: they measure the per-image difference between the number of predicted and ground-truth points.

FOMO adds a second, grid-level group on top of these. It sweeps confidence and nms_radius and publishes the best-F1 combination as metrics/grid_F1, metrics/grid_precision, metrics/grid_recall, metrics/grid_mean_distance, metrics/grid_TP, metrics/grid_FP and metrics/grid_FN, with the settings that produced it under decode/threshold and decode/nms_radius.

Export

FOMO exports through the shared export path, and an exported artifact loads back through LibreYOLO() on its file suffix, so a .onnx or .engine file behaves like a checkpoint and returns the same Results.

Export
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")model.export(format="onnx")
Run the exported file
from libreyolo import LibreYOLO, SAMPLE_IMAGE # The factory routes on the file suffix, so an exported artifact loads# like any checkpoint and returns the same Results object.model = LibreYOLO("./LibreFOMOs-point.onnx")result = model(SAMPLE_IMAGE) print(result.points.xy)

Per-format coverage is on the FOMO page and in the full export matrix. LocateAnything and SenseNova-Vision do not export: export() raises on both, because a generative model has no traceable detection graph.

Verified against LibreYOLO v1.5.0.