DetectionEngine.crops

DetectionEngine.crops(
    model_name=None,
    split='test',
    *,
    score_threshold=None,
    context=0.0,
    size=None,
    fit='letterbox',
    fill=0.5,
)

Every detection cut out of the image it was found in.

The pipeline this is for is a detector followed by a classifier it does not contain: find the objects with three classes, crop them, hand the crops to something that knows eighty. It is the second thing people ask for after boxes, and doing it by hand means re-reading every image and getting the rounding right.

Filtered at operating_point, not at score_threshold. The specification’s score_threshold is deliberately near zero so that average precision integrates the whole ranking - on BCCD that is hundreds of boxes an image, almost all of them the tail that AP exists to measure over. Cropping them would hand a classifier mostly noise. operating_point is where someone stands when they act on a prediction, which is what cropping is.

One record per image rather than one flat list, because a crop without its source is not traceable: key says which image, and boxes are the coordinates it came from, in that image’s own pixels.

Parameters

Name Type Description Default
model_name str | None which trained detector. None
split str which split’s images to read. 'test'
score_threshold float | None override the confidence to crop at. None
context float expand each box by this fraction of its size per side, 0 by default. 0.0
size tuple[int, int] | None bring every crop to (height, width), or None to keep each as cut. None
fit str "letterbox" to preserve aspect, "stretch" to resize both axes. 'letterbox'
fill float padding value for "letterbox". 0.5

Returns

Name Type Description
list[dict[str, Any]] One dict per image with key, crops, boxes, scores, labels, names.

Parameters

Name Type Description Default
split str Which data to cut from. 'test'
model_name str | None Which detector. Defaults to the first. None
context float Extra margin, as a fraction of the box rather than in pixels, so one value suits a platelet and a white cell. 0.0
size tuple[int, int] | None Resize every crop to this. Letterboxed rather than stretched, because a stretch changes the aspect of every non-square object and has to be asked for. None

Returns

Name Type Description
list[dict[str, Any]] One record per image, each with the crops and the boxes they came from, plus
list[dict[str, Any]] dropped - boxes the inverse letterbox mapped to no extent at all, which a
list[dict[str, Any]] model may legitimately produce by saying an object is off the frame.

Read at operating_point, not at score_threshold: that one sits near zero so average precision can integrate the whole ranking, and cropping it would hand a classifier the tail.