{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# How To: Refine Noisy Detection Boundaries\n", "\n", "After detection, colony masks often have ragged edges, small holes, or\n", "spurious fragments. Use refiners to clean up the mask before measuring." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from phenotypic.data import load_yeast_plate\n", "from phenotypic.enhance import GaussianBlur, CLAHE\n", "from phenotypic.detect import OtsuDetector\n", "from phenotypic.refine import (\n", " MaskOpener, MaskFill, SmallObjectRemover, BorderObjectRemover,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plate = load_yeast_plate()\n", "plate = GaussianBlur(sigma=2.0).apply(plate)\n", "plate = CLAHE(clip_limit=0.01).apply(plate)\n", "plate = OtsuDetector().apply(plate)\n", "print(f\"Before refinement: {plate.num_objects} objects\")\n", "plate.dash(overlay=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Remove Border Objects\n", "\n", "Colonies touching the image edge are usually partial. Remove them." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plate = BorderObjectRemover(border_size=1).apply(plate)\n", "print(f\"After border removal: {plate.num_objects} objects\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Remove Small Objects\n", "\n", "Noise fragments smaller than real colonies. Set `min_size` to the\n", "smallest colony area you expect (in pixels)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plate = SmallObjectRemover(min_size=50).apply(plate)\n", "print(f\"After small object removal: {plate.num_objects} objects\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Morphological Opening\n", "\n", "Smooths jagged mask edges and breaks thin bridges between touching\n", "colonies." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plate = MaskOpener(width=5).apply(plate)\n", "print(f\"After opening: {plate.num_objects} objects\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fill Holes\n", "\n", "Some detectors leave holes inside colony masks. `MaskFill` fills them." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plate = MaskFill().apply(plate)\n", "plate.dash(overlay=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## In a Pipeline\n", "\n", "Chain these refiners after detection in your pipeline:\n", "\n", "```python\n", "pipeline = pht.ImagePipeline(ops=[\n", " GaussianBlur(sigma=2.0),\n", " CLAHE(clip_limit=0.01),\n", " OtsuDetector(),\n", " BorderObjectRemover(),\n", " SmallObjectRemover(min_size=50),\n", " MaskOpener(width=5),\n", " MaskFill(),\n", "])\n", "```" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.11.0" } }, "nbformat": 4, "nbformat_minor": 4 }