diff --git a/docs/inference.md b/docs/inference.md index a7e5833..8dc7bd1 100644 --- a/docs/inference.md +++ b/docs/inference.md @@ -339,7 +339,7 @@ class takes the extent of what survived. A box therefore does not move when `det | --- | --- | --- | | `detail` | `coarse`, `balanced` or `fine` - how much of the outline survives | polygon | | `fill_holes` | the widest gap closed, as a share of the piece's area | polygon | -| `fragments` | `one` piece or `all` of them | polygon and box | +| `fragments` | `one` piece - the one under your points - or `all` of them | polygon and box | Every one is optional, and omitting all three gives what this route always gave: `balanced`, a reach of two parts in a thousand, and the piece you pointed at. @@ -349,6 +349,21 @@ of the region's own size rather than a pixel count, so it does the same thing to pixels across and a thing eight hundred across, and `balanced` keeps a typical object in the 10-40 vertex range. +**`one` means the piece you pointed at, not the biggest one on the frame.** A mask routinely +carries more than one separate piece - a speck of antialiasing along an edge, a reflection, a +scrap of the same colour elsewhere - and which of them you meant is a question only the points can +answer. So the choice is made from the prompt: a point inside a piece picks that piece; several +points inside several pieces pick the largest of *those*, because two positives describe one +object rather than propose two; and a point inside none of them picks the piece nearest to it, +since a mask need not cover the exact pixel you clicked. Negative points never select - they say +what the shape is not, and a piece is chosen before its shape is known. + +Picking whichever piece happened to own the topmost-leftmost lit pixel would be a different rule +and a worse one: that is a fact about where the speckle fell, not about what you asked for. + +`all` drops the question and proposes every piece at or above a twentieth of the largest one's +area. The floor is there because one click should not become a cleanup job. + **`parameters` says which of them apply here**, for the kind of shape your `allowed_geometries` will produce. A box has no outline, so `detail` and `fill_holes` have nothing to do to one and are not named. A client renders what this lists and works none of it out for itself. diff --git a/docs/ui.md b/docs/ui.md index 54efe4d..1d5bbe4 100644 --- a/docs/ui.md +++ b/docs/ui.md @@ -493,7 +493,9 @@ of the vertices beside it, and `[` and `]` move it without opening anything - that one costs no request at all, because the answer carried the full outline and the editor re-simplifies it here. **Close gaps** smooths the notches a segmenter bites out of an edge. **Every separate piece** proposes each part of the mask -rather than only the one you clicked. Those last two change what the model's mask +rather than only the one you pointed at - which is what it offers otherwise, and +it is chosen from your clicks rather than by size, so a stray speck elsewhere on +the frame never wins. Those last two change what the model's mask *is*, so they ask again - the frame is already read, so it is quick. On a class that stores a box only the last of the three appears, because the diff --git a/frontend/ui-core/src/generated/api.ts b/frontend/ui-core/src/generated/api.ts index 25cb0c2..9e0e6df 100644 --- a/frontend/ui-core/src/generated/api.ts +++ b/frontend/ui-core/src/generated/api.ts @@ -2989,6 +2989,10 @@ export interface components { /** * Fragments * @description How many of a mask's separate pieces become shapes. + * + * `one` is the piece your points are on, not the biggest piece on the frame: + * which of them you meant is a question only the prompt can answer. `all` + * proposes every piece big enough to be worth proposing. * @enum {string} */ Fragments: "one" | "all"; diff --git a/openapi.json b/openapi.json index 3163cf5..e6afbf1 100644 --- a/openapi.json +++ b/openapi.json @@ -2170,7 +2170,7 @@ "type": "object" }, "Fragments": { - "description": "How many of a mask's separate pieces become shapes.", + "description": "How many of a mask's separate pieces become shapes.\n\n`one` is the piece your points are on, not the biggest piece on the frame:\nwhich of them you meant is a question only the prompt can answer. `all`\nproposes every piece big enough to be worth proposing.", "enum": [ "one", "all" diff --git a/src/visionset/kernel/domain/suggestion.py b/src/visionset/kernel/domain/suggestion.py index 887c476..b630f7e 100644 --- a/src/visionset/kernel/domain/suggestion.py +++ b/src/visionset/kernel/domain/suggestion.py @@ -65,9 +65,14 @@ class Detail(StrEnum): # speckle fell. Naming this ``largest`` would describe a tie-break as though it # were the rule. class Fragments(StrEnum): - """How many of a mask's separate pieces become shapes.""" + """How many of a mask's separate pieces become shapes. - #: The piece under the click, and nothing else. + `one` is the piece your points are on, not the biggest piece on the frame: + which of them you meant is a question only the prompt can answer. `all` + proposes every piece big enough to be worth proposing. + """ + + #: The piece the prompt points at, and nothing else. ONE = "one" #: Every piece big enough to be worth proposing. ALL = "all"