CoolFace
Modelpublic

rotsl/fungal-colony-pipeline

sourceHugging Faceapache-2.0updated 5mo agoView on Hugging Face
0likes4downloads
Model Card

πŸ„ Fungal Colony Image Analysis Pipeline

![Downloads (All Time)](https://huggingface.co/rotsl/fungal-colony-pipeline) ![License](https://opensource.org/licenses/Apache-2.0) ![DOI](https://doi.org/10.57967/hf/8570)

End-to-end analysis pipeline for Magnaporthe (and other fungal) colony morphometry on 90 mm petri-dish images.

[β–Ά Try the live demo](https://huggingface.co/spaces/rotsl/fungal-colony-input) β€” upload images, run inference, see overlays & growth charts in your browser.

Designed for Apple Silicon Mac (M1/M2/M3 Pro/Max, MPS backend, float32). Also works on CPU (Linux/Windows).


Model

Weights: `rotsl/grayleafspot-segmentation/grayleafspot.pt`

PropertyValue
Architecturesmp.Unet(encoder_name="resnet34") via segmentation-models-pytorch
Parameters24.4M
Input256Γ—256 RGB
Output1-channel sigmoid mask (threshold 0.5)
Dish detectionOpenCV HoughCircles on Gaussian-blurred grayscale
MPS compatibleβœ… Pure PyTorch β€” no custom CUDA kernels

Pipeline Overview

input.py                                pipeline.py / app.py (Space)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Gradio GUI      β”‚                    β”‚  Read image_metadata.csv             β”‚
β”‚  - Scan folder   β”‚  image_metadata.   β”‚  Load smp.Unet (thread-local)       β”‚
β”‚  - Tag metadata  │──── csv/json ─────▢│  For each image:                     β”‚
β”‚  - Export CSV    β”‚                    β”‚    1. OpenCV HoughCircles β†’ dish     β”‚
β”‚  - Export ICS    β”‚                    β”‚    2. U-Net β†’ colony mask            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚    3. Crack detection (adaptive)     β”‚
                                        β”‚    4. Hyphae (Frangi + Meijering)    β”‚
                                        β”‚    5. Morphometrics (mm/mmΒ²)         β”‚
                                        β”‚  6 overlay panels per image          β”‚
                                        β”‚  Growth charts (β‰₯2 images)           β”‚
                                        β”‚  Output: analysis_full.csv/json      β”‚
                                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Visualisation Outputs

6 Overlay Panels Per Image

PanelColourShows
Raw + DishGreen circle, red contourDetected dish boundary + colony outline
Colony MaskWhite on blackBinary segmentation mask
Colony OverlayRed 50% blendColony area highlighted on raw image
CracksYellowDetected cracks inside colony (dilated for visibility)
HyphaeCyanHyphae skeleton (Frangi + Meijering hybrid filter)
All CombinedRed + yellow + cyanColony + cracks + hyphae together

Growth Charts (when β‰₯2 images)

  • β€”Colony Area (mmΒ²) vs days β€” with fill + data labels
  • β€”Diameter (mm) over time
  • β€”Relative Growth Rate (RGR) β€” bar chart per interval
  • β€”Crack Coverage (%) over time
  • β€”Hyphae Network Length (mm) over time
  • β€”Morphology β€” eccentricity + edge roughness dual panel

All charts are included as PNGs in the download zip.


Installation (Local)

Prerequisites

  • β€”Python 3.10+
  • β€”macOS with Apple Silicon recommended (MPS acceleration) β€” also works on CPU
  • β€”~100 MB disk for model weights (cached in ~/.cache/huggingface)

Setup

bash
# 1. Clone
git clone https://huggingface.co/rotsl/fungal-colony-pipeline
cd fungal-colony-pipeline

# 2. Virtual environment
python3 -m venv .venv
source .venv/bin/activate

# 3. Install
pip install -r requirements.txt

# 4. (Optional) Pre-download model
python -c "
from huggingface_hub import hf_hub_download
p = hf_hub_download('rotsl/grayleafspot-segmentation', 'grayleafspot.pt')
print(f'Downloaded to: {p}')
"

Usage (Local)

Step 1: Tag Images with Metadata

bash
python input.py
  1. 1.Open http://localhost:7860
  2. 2.Paste image folder path β†’ πŸ“‚ Scan
  3. 3.Fill experiment details (name, start date, user, plates count)
  4. 4.Click thumbnails β†’ edit per-image dates β†’ πŸ’Ύ Save
  5. 5.πŸ“₯ Export β†’ writes image_metadata.csv, .json, reminders.ics to your folder

Step 2: Run Analysis

bash
IMG_DIR=./data python pipeline.py
VariableDefaultDescription
IMG_DIR.Folder with image_metadata.csv + images
MAX_WORKERS2Parallel threads (hard cap 2 for 16 GB)
MODEL_REPOrotsl/grayleafspot-segmentationHF model repo
MODEL_FILEgrayleafspot.ptWeight file

Outputs: analysis_full.csv + analysis_full.json in IMG_DIR


Usage via HF API (Programmatic Access)

You can run the full pipeline remotely via the Gradio Client without installing anything locally. The Space exposes five API endpoints.

Install

bash
pip install gradio_client

Quick Start β€” Upload + Run Pipeline

python
from gradio_client import Client, handle_file

client = Client("rotsl/fungal-colony-input")

# Step 1: Upload images
result = client.predict(
    files=[
        handle_file("plate_d01.jpg"),
        handle_file("plate_d03.jpg"),
        handle_file("plate_d05.jpg"),
    ],
    api_name="/on_upload",
)
# result = (gallery_items, status_markdown)

# Step 2: Run the full analysis pipeline
analysis = client.predict(
    en="MagExp01",                # experiment name
    ed="2025-04-01",              # experiment start date
    un="YourName",                # user name
    pc=1,                         # plates count
    api_name="/on_run",
)
# analysis is a tuple:
#   [0] status message (str)
#   [1] overlay gallery β€” list of dicts with 'image' paths (6 panels per input image)
#   [2] growth chart gallery β€” list of dicts with 'image' paths
#   [3] results dataframe (dict with 'headers' and 'data')
#   [4] path to analysis_full.zip

status_msg    = analysis[0]
overlays      = analysis[1]   # list of {image: filepath, caption: str}
charts        = analysis[2]   # list of {image: filepath, caption: str}
results_table = analysis[3]   # {"headers": [...], "data": [[...], ...]}
zip_path      = analysis[4]   # local path to downloaded analysis_full.zip

print(status_msg)
print(f"Overlays: {len(overlays)} panels")
print(f"Charts:   {len(charts)}")
print(f"Results:  {len(results_table['data'])} rows Γ— {len(results_table['headers'])} cols")
print(f"Download: {zip_path}")

Export Metadata Only (no inference)

python
meta = client.predict(
    en="MagExp01",
    ed="2025-04-01",
    un="YourName",
    pc=1,
    api_name="/on_export",
)
# meta[0] = status message
# meta[1] = metadata dataframe
# meta[2] = path to image_metadata.zip

Available API Endpoints

EndpointDescriptionKey Parameters
/on_uploadUpload images β†’ galleryfiles: list of filepaths
/on_selSelect image in galleryed: experiment date
/on_saveSave per-image date/remindernd: date, nr: reminder, ed: exp date
/on_exportExport metadata CSV/JSON/ICSen, ed, un, pc
/on_runRun full pipeline (segmentation + morphometrics + charts)en, ed, un, pc

cURL Example

bash
# Upload images and run pipeline via REST API
# (Gradio uses a session-based API β€” the Python client is recommended)

curl -X POST https://rotsl-fungal-colony-input.hf.space/gradio_api/call/on_upload \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
      [{"path": "https://your-server.com/plate_d01.jpg"}]
    ]
  }'
Note: For multi-step workflows (upload β†’ run), use the Python gradio_client which handles session state automatically. Direct REST calls require managing the session hash between requests.

Batch Processing Script

python
"""Process a folder of petri dish images via the HF Space API."""
from pathlib import Path
from gradio_client import Client, handle_file

IMAGE_DIR = Path("./my_experiment")
EXPERIMENT = "MagExp01"
START_DATE = "2025-04-01"

client = Client("rotsl/fungal-colony-input")

# Collect all images
images = sorted(
    p for p in IMAGE_DIR.rglob("*")
    if p.suffix.lower() in {".jpg", ".jpeg", ".png", ".tif", ".bmp", ".webp"}
)
print(f"Found {len(images)} images")

# Upload
client.predict(
    files=[handle_file(str(p)) for p in images],
    api_name="/on_upload",
)

# Run pipeline
status, overlays, charts, table, zip_path = client.predict(
    en=EXPERIMENT,
    ed=START_DATE,
    un="BatchUser",
    pc=1,
    api_name="/on_run",
)

print(status)
print(f"Results zip: {zip_path}")

# Access results as a DataFrame
import pandas as pd
df = pd.DataFrame(table["data"], columns=table["headers"])
print(df[["image_path", "area_mm2", "diameter_mm", "crack_coverage_pct"]].to_string())

Output Columns

Metadata

ColumnDescription
image_pathRelative path from IMG_DIR
experiment_nameExperiment identifier
experiment_dateStart date (YYYY-MM-DD)
image_dateAuto-detected capture date
day_coded01, d02, …
user_nameResearcher
plates_countNumber of plates

Calibration

ColumnUnitDescription
dish_cx, dish_cypxDish centre
dish_radius_pxpxDish radius
px_to_mmmm/pxScale factor
calibration_diameter_mmmmShould be β‰ˆ90.0
calibration_error_pct%Target <2%

Colony Morphometry

ColumnUnitDescription
area_mm2mmΒ²Colony area
diameter_mmmmEquivalent circular diameter
perimeter_mmmmColony perimeter
eccentricity–0=circle, 1=line
edge_roughness–Perimeter / equivalent circle perimeter
centre_delta_mmmmColony centre to dish centre

Texture

ColumnDescription
entropyShannon entropy
texture_stdPixel intensity Οƒ

Cracks

ColumnUnitDescription
crack_pxpxTotal crack pixels
crack_area_mm2mmΒ²Total crack area
crack_coverage_pct%Crack / colony area Γ— 100
crack_count–Distinct crack count

Hyphae

ColumnUnitDescription
hyph_frangi_mmmmFrangi vesselness skeleton length
hyph_meijering_mmmmMeijering neuriteness skeleton length
hyph_hybrid_mmmmUnion of both

Time-Series

ColumnUnitDescription
days_since_startdaysFrom first image
rgr_per_dayday⁻¹(ln Aβ‚‚ βˆ’ ln A₁) / Ξ”days
relative_growth_per_daymmΒ²/day(Aβ‚‚ βˆ’ A₁) / Ξ”days

R Studio Integration

r
library(readr)
library(dplyr)
library(ggplot2)

df <- read_csv("analysis_full.csv")

# Growth curve
df %>%
  filter(is.na(error) | error == "") %>%
  ggplot(aes(x = days_since_start, y = area_mm2, color = experiment_name)) +
  geom_line() + geom_point() +
  labs(x = "Days", y = "Colony Area (mmΒ²)", title = "Magnaporthe Growth") +
  theme_minimal()

# Morphology summary
df %>%
  filter(is.na(error) | error == "") %>%
  group_by(experiment_name) %>%
  summarise(
    n = n(),
    mean_area = mean(area_mm2, na.rm = TRUE),
    mean_roughness = mean(edge_roughness, na.rm = TRUE),
    mean_crack_pct = mean(crack_coverage_pct, na.rm = TRUE),
    total_hyphae = sum(hyph_hybrid_mm, na.rm = TRUE)
  )

# RGR
df %>%
  filter(!is.na(rgr_per_day) & rgr_per_day != "") %>%
  mutate(rgr_per_day = as.numeric(rgr_per_day)) %>%
  ggplot(aes(x = days_since_start, y = rgr_per_day)) +
  geom_col(fill = "steelblue") +
  facet_wrap(~ experiment_name) +
  labs(x = "Days", y = "RGR (day⁻¹)") +
  theme_minimal()
r
library(jsonlite)
df <- fromJSON("analysis_full.json")
meta <- read_csv("image_metadata.csv")

Technical Notes

Segmentation Strategy

  1. 1.Dish detection: OpenCV GaussianBlur β†’ HoughCircles (HOUGH_GRADIENT, dp=1.2)
  2. 2.Colony segmentation: Resize full image to 256Γ—256 β†’ smp.Unet(resnet34) β†’ sigmoid β†’ threshold 0.5
  3. 3.Resize mask back to original resolution (nearest-neighbour)
  4. 4.Restrict to dish interior (95% of detected radius)
  5. 5.Cleanup: OpenCV morphological close/open, keep largest connected component

Crack Detection

  • β€”Local adaptive thresholding inside colony mask
  • β€”Filter by elongation (aspect ratio > 2.5 or eccentricity > 0.85)
  • β€”Edge artefacts removed via erosion

Hyphae Detection

  • β€”Frangi filter: multi-scale vesselness (Οƒ = 1–4)
  • β€”Meijering filter: neuriteness (Οƒ = 1–4)
  • β€”Hybrid: union of both skeletonised responses
  • β€”Analysis region extends 20 px beyond colony boundary

Memory Management

  • β€”Max 2 parallel threads β€” prevents OOM on 16 GB
  • β€”torch.mps.empty_cache() after each image
  • β€”Thread-local model loading
  • β€”Float32 throughout

File Structure

your_image_folder/
β”œβ”€β”€ subdir_a/
β”‚   β”œβ”€β”€ mag01_20250401_01.jpg
β”‚   └── mag01_20250402_01.jpg
β”œβ”€β”€ image_metadata.csv          ← input.py
β”œβ”€β”€ image_metadata.json         ← input.py
β”œβ”€β”€ reminders.ics               ← input.py (if reminders)
β”œβ”€β”€ analysis_full.csv           ← pipeline.py
└── analysis_full.json          ← pipeline.py

Troubleshooting

IssueFix
torch.mps not availablemacOS 13+ and PyTorch 2.1+ required
OOM on 16 GBMAX_WORKERS=1
Model download failsCheck internet + HF_TOKEN for gated repo
Dish not detectedFull rim must be visible, avoid heavy shadows
Colony not detectedVerify image has visible colony contrast against agar

Citation

bibtex
@misc{rohan_r_2026,
	author       = { rohan r },
	title        = { fungal-colony-pipeline (Revision e51373b) },
	year         = 2026,
	url          = { https://huggingface.co/rotsl/fungal-colony-pipeline },
	doi          = { 10.57967/hf/8570 },
	publisher    = { Hugging Face }
}

License

Apache License 2.0