{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial 9: Diagnosing Image Quality\n", "\n", "Before building a pipeline, it helps to assess the quality of your plate\n", "images. PhenoTypic's diagnostics plotter gives you objective metrics for\n", "noise, contrast, and structure — so you can make informed decisions about\n", "which enhancers and detectors to use.\n", "\n", "**What you will learn:**\n", "\n", "1. Use `PlotDiagnostics().inspect(image)` to assess plate quality\n", "2. Interpret the noise, contrast, and structure metrics\n", "3. Use quality metrics to guide pipeline design" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:15:54.073521Z", "start_time": "2026-04-07T22:15:51.280649Z" } }, "outputs": [], "source": [ "from phenotypic.data import load_yeast_plate\n", "from phenotypic.plotting import PlotDetectModes, PlotDiagnostics\n", "from phenotypic.util import ImageMetricsCalculator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load the Plate" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:15:54.425900Z", "start_time": "2026-04-07T22:15:54.075565Z" } }, "outputs": [], "source": [ "plate = load_yeast_plate()\n", "plate.dash()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run Diagnostics\n", "\n", "`PlotDiagnostics.inspect()` produces the primary interactive diagnostic\n", "figure. `PlotDiagnostics.report()` exposes the complete multi-panel report.\n", "The renderer-neutral plotting class can also be placed in a pipeline's\n", "`plots` list for automatic deliverable generation." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:17:36.604879Z", "start_time": "2026-04-07T22:17:09.528358Z" } }, "outputs": [], "source": [ "diagnostics = PlotDiagnostics()\n", "fig = diagnostics.inspect(plate)\n", "fig" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Inspect the Metrics\n", "\n", "The `metrics` dictionary contains objective measurements organized by\n", "category. Let's look at each one." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:16:25.010769Z", "start_time": "2026-04-07T22:16:24.989604Z" } }, "outputs": [], "source": [ "calculator = ImageMetricsCalculator(plate.detect_mat[:])\n", "metrics = {\n", " \"noise\": calculator.compute_noise_metrics(),\n", " \"contrast\": calculator.compute_contrast_metrics(),\n", " \"structure\": calculator.compute_structure_metrics(),\n", " \"background\": calculator.compute_background_metrics(),\n", "}\n", "print(\"Available metric categories:\")\n", "for category in metrics:\n", " print(f\" {category}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Noise Metrics\n", "\n", "Noise metrics tell you how much random variation exists in the image\n", "background. High noise can confuse detectors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:16:25.063775Z", "start_time": "2026-04-07T22:16:25.025386Z" } }, "outputs": [], "source": [ "if \"noise\" in metrics:\n", " print(\"Noise metrics:\")\n", " for key, val in metrics[\"noise\"].items():\n", " if isinstance(val, (int, float)):\n", " print(f\" {key}: {val:.4f}\")\n", " else:\n", " print(f\" {key}: {val}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **SNR** (Signal-to-Noise Ratio) — higher is better. Values below 10\n", " suggest the image would benefit from denoising (`StableDenoise` or\n", " `BlurGauss`).\n", "- **Correlation length** — longer correlation suggests structured noise\n", " (e.g., uneven illumination) rather than random pixel noise." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Contrast Metrics\n", "\n", "Contrast metrics measure how well colonies separate from the agar\n", "background." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:16:25.077729Z", "start_time": "2026-04-07T22:16:25.066031Z" } }, "outputs": [], "source": [ "if \"contrast\" in metrics:\n", " print(\"Contrast metrics:\")\n", " for key, val in metrics[\"contrast\"].items():\n", " if isinstance(val, (int, float)):\n", " print(f\" {key}: {val:.4f}\")\n", " else:\n", " print(f\" {key}: {val}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **RMS contrast** — overall contrast level. Low values mean faint\n", " colonies that may need `CLAHE` to boost local contrast.\n", "- **Michelson contrast** — ratio of (max − min) / (max + min). Values\n", " close to 1.0 indicate strong colony/agar separation.\n", "- **Dynamic range** — fraction of the bit depth in use. Low dynamic\n", " range suggests the image is under-exposed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Structure Metrics\n", "\n", "Structure metrics assess the spatial organization of the image." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:16:25.089070Z", "start_time": "2026-04-07T22:16:25.078594Z" } }, "outputs": [], "source": [ "if \"structure\" in metrics:\n", " print(\"Structure metrics:\")\n", " for key, val in metrics[\"structure\"].items():\n", " if isinstance(val, (int, float)):\n", " print(f\" {key}: {val:.4f}\")\n", " else:\n", " print(f\" {key}: {val}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **Gradient mean** — average edge strength. Higher values mean sharper\n", " colony boundaries, which makes detection easier.\n", "- **Coherence** — consistency of edge orientation. High coherence on grid\n", " plates suggests well-organized colonies." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other Plot Methods\n", "\n", "The standalone plotting API also supports full reports and detection-mode\n", "comparisons without adding an accessor to `Image`:\n", "\n", "- **`diagnostics.report(plate)`** — complete interactive diagnostic report\n", "- **`PlotDetectModes().inspect(plate)`** — comparison of registered detection modes\n", "- **`plate.show(overlay=True)`** — static image and object overlay\n", "- **`plate.dash(overlay=True)`** — interactive image and object overlay" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-07T22:16:25.094901Z", "start_time": "2026-04-07T22:16:25.090499Z" } }, "outputs": [], "source": [ "detect_modes = PlotDetectModes()\n", "# mode_comparison = detect_modes.inspect(plate) # Runs every registered mode." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "You now know how to assess plate image quality before committing to a\n", "pipeline:\n", "\n", "- **`PlotDiagnostics().inspect(plate)`** — primary diagnostic figure\n", "- **Noise metrics** guide denoising decisions (SNR, correlation length)\n", "- **Contrast metrics** guide enhancement decisions (RMS contrast, dynamic range)\n", "- **Structure metrics** assess colony edge quality (gradient, coherence)\n", "\n", "Use these metrics to choose between enhancers, detectors, and prefab\n", "pipelines — rather than guessing.\n", "\n", "**Next up:** [Tutorial 10: Detecting Filamentous Fungi](10_detecting_filamentous_fungi.ipynb) —\n", "handle branching fungal morphology with PhenoTypic's specialized detector." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.11.0" } }, "nbformat": 4, "nbformat_minor": 4 }