Skip to content

v0.2.0 — real-world units, colour correction, and a mask check that is finally two-sided

Choose a tag to compare

@musharna musharna released this 31 Jul 00:52

The first release actually published to PyPI. 0.1.0 was tagged in the changelog but never uploaded, so everything below shipped together.

The correctness fix that matters most

object_type was hardcoded to "dark" and unreachable, so channels s and b returned the background as the plant: mask_fraction 0.961, and measure() reported area=1007829, width=1024, height=1024 — the whole frame — with no error at all. list_methods() made it worse by recommending 's'. The parameter is now exposed, and the guidance names the polarity each channel needs.

Mask validity is now two-sided. assert_not_degenerate only ever rejected masks that were too small, which left inverting a threshold — the dominant failure of any threshold operation — outside the set of outcomes this system could express as a failure. An implausible_coverage warning fires above 50% frame coverage; measured on the fixture, plant masks land at 0.031–0.046 and inverted ones at 0.959–0.967, so the boundary sits in a wide empty gap.

Added

  • Real-world units. measure(session_id, px_per_mm=…) converts spatial traits to mm and mm2 — without it every size is in pixels, and pixel sizes are not comparable between images shot at different distance or zoom. The conversion uses an explicit table rather than PlantCV's unit strings, which label both area and width as "pixels"; a unit-derived rule would leave every area wrong by exactly a factor of px_per_mm.
  • calibrate_scale_from_marker — measures a marker of known real size and returns px_per_mm. It deliberately does not wrap pcv.report_size_marker_area: against a synthetic disc of known 80 px diameter that function returns major_axis=79.1 with a whole-frame ROI but 348.0 with a tight ROI around the marker, a silent 4.35× scale error under the most intuitive usage. Here the region is cropped before thresholding, removing the mechanism instead of compensating for it.
  • Colour-card correction. segment(..., color_correct=true) detects a ColorChecker and corrects to a standard reference; measure() re-applies it so traits are measured on the pixels the mask was drawn on. If no card is found it raises rather than silently measuring the uncorrected image. Mean absolute error to the undistorted original falls from 8.77 to 3.43.
  • measure_images — one recipe across up to 200 images. Batch cannot honour "no number without the picture" literally, so the overlay is replaced by explicit refusal: every image runs the same guards via shared code, and any image tripping a blocking guard returns no traits, only a reason. That is weaker than a human reading a mask, and is documented as such rather than implied.
  • Colour analysis (analyses=["size", "color"]), with the three frequency histograms — 692 numbers — withheld unless include_histograms=true, because that is a context-window cost rather than a feature.
  • Server instructions and tool metadata. Every tool publishes a title and ToolAnnotations; measure, list_methods, calibrate_scale_from_marker and measure_images publish an outputSchema. segment and suggest_segmentation return image blocks and so have none by nature — a test asserts exactly that split.

Also fixed

  • fill_size=200 was hardcoded and silently erased any specimen smaller than itself; a measured 144 px object became an empty mask. Thresholding and filling are now separate steps, and this reports fill_erased_mask instead of presenting as a bad channel choice.
  • measure() no longer destroys the host's PlantCV state — pcv.outputs.clear() wiped a process-global table shared with any application also using PlantCV directly.
  • The stale-image guard compares content, not just shape: swapping the file for a different image of identical dimensions previously passed, measuring a stale mask against new pixels.
  • segment() warns on an empty mask, which previously surfaced only if measure() happened to be called afterwards.

Full changelog: https://github.com/musharna/plantcv-mcp/blob/master/CHANGELOG.md