DuplicateResolver#

class rapidtools.processing.DuplicateResolver(model: BaseInferenceModel | None = None, *, judge: Callable[[Sequence[Path], Sequence[Path]], tuple[bool | None, float | None]] | None = None, max_distance_m: float = 8.0, min_confidence: float = 0.9, max_images_per_asset: int = 2, prompt: str | None = None, generation: GenerationConfig | None = None, max_workers: int | None = None, keep_duplicates: bool = False, attribute_prefix: str = 'duplicate', save_directory: str | Path | None = None, cancel_event: Event | None = None)[source]#

Bases: object

Merge pairs of nearby objects that a model says are one vehicle.

Every pair of assets within max_distance_m of each other that both have downloaded crops is shown to the model as two rows of crops, row A and row B, with PAIR_PROMPT. Pairs answered same with at least min_confidence are joined (chains too, through union-find). In each group the asset seen in the most frames is kept; it gains the others’ sightings and crops and the attribute <prefix>_merged with their ids, and the others are removed (or kept, flagged <prefix>_of, with keep_duplicates=True).

Parameters:
  • model – Any wrapper from rapidtools.models.load() that accepts images. Exactly one of model and judge must be given.

  • judge – A callable judge(paths_a, paths_b) -> (same, confidence) standing in for the model, for tests or a custom comparator.

  • max_distance_m – Farthest apart two objects may be and still be compared. Defaults to 8.

  • min_confidence – Confidence at or above which a same verdict is acted on. Defaults to 0.9; on the labelled block every true duplicate scored 0.95 or more and the one false match that was not flagged at 0.5 came from crops without outlines.

  • max_images_per_asset – Crops of each object shown, closest first. Defaults to 2.

  • prompt – Replaces PAIR_PROMPT.

  • generation – Generation settings; defaults to JSON mode at temperature 0.

  • max_workers – Parallel model calls. Defaults to one at a time.

  • keep_duplicates – Keep the merged-away assets, flagged, instead of removing them.

  • attribute_prefix – Prefix of the attributes written. Defaults to 'duplicate'.

  • save_directory – Where the pair composites are written; a temporary directory by default.

  • cancel_event – Set to stop early.

Example

>>> resolver = DuplicateResolver(judge=lambda a, b: (True, 1.0))
>>> resolver.stage
<Stage.VERIFY: 45>

Methods

candidate_pairs

Pairs of assets within max_distance_m that both have crops.

compose

Lay two objects' crops out as row A over row B and save the image.

property model_name: str#

Identifier of the model or 'judge'.

candidate_pairs(collection: PhysicalAssetCollection) → list[tuple[PhysicalAsset, PhysicalAsset, float]][source]#

Pairs of assets within max_distance_m that both have crops.

Returns:

list[tuple[PhysicalAsset, PhysicalAsset, float]] – Each pair once, with its separation in metres.

Example

>>> resolver.candidate_pairs(vehicles)
[(<PhysicalAsset veh_12>, <PhysicalAsset veh_57>, 3.1)]
compose(crops_a: Sequence[ImageAsset], crops_b: Sequence[ImageAsset], out: Path) → Path[source]#

Lay two objects’ crops out as row A over row B and save the image.

Each crop is zoomed to its outline, which is drawn thick, so that a neighbour the cropper’s margin let into the frame is not what the model judges.

Parameters:
  • crops_a – Crops of the first object, as attached by the cropper.

  • crops_b – Crops of the second.

  • out – Where to write the composite.

Returns:

Path – out.