| import gradio as gr |
| import cv2 |
| import numpy as np |
| import pandas as pd |
| from collections import Counter |
| from ultralytics import YOLO |
| import plotly.express as px |
| import plotly.graph_objects as go |
|
|
| |
| model = YOLO("best.pt") |
|
|
| def create_size_distribution_plot(df): |
| """Create a box plot of cell sizes for each class.""" |
| fig = px.box(df, x="class_name", y="area", title="Cell Size Distribution by Type") |
| fig.update_layout( |
| xaxis_title="Cell Type", |
| yaxis_title="Area (pixels²)", |
| template="plotly_white" |
| ) |
| return fig |
|
|
| def create_density_heatmap(df, image_shape): |
| """Create a heatmap showing cell density.""" |
| heatmap = np.zeros(image_shape[:2]) |
| for _, row in df.iterrows(): |
| center_x = int((row['x_min'] + row['x_max']) / 2) |
| center_y = int((row['y_min'] + row['y_max']) / 2) |
| heatmap[max(0, center_y-20):min(image_shape[0], center_y+20), |
| max(0, center_x-20):min(image_shape[1], center_x+20)] += 1 |
| |
| fig = go.Figure(data=go.Heatmap(z=heatmap)) |
| fig.update_layout(title="Cell Density Heatmap") |
| return fig |
|
|
| def process_image(image, conf_threshold=0.25): |
| """Detect cells in the image, extract attributes, and return results.""" |
| if image is None: |
| return None, "No image uploaded", None, None, None |
| |
| |
| image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) |
| |
| |
| results = model.predict(source=image_rgb, imgsz=640, conf=conf_threshold) |
| |
| |
| annotated_img = results[0].plot() |
| |
| |
| detections = results[0].boxes.data if results[0].boxes is not None else [] |
| |
| if len(detections) > 0: |
| |
| class_names = [model.names[int(cls)] for cls in detections[:, 5]] |
| count = Counter(class_names) |
| detection_str = '\n'.join([f"{name}: {count[name]} cells detected" for name in count]) |
| |
| |
| df = pd.DataFrame(detections.numpy(), columns=["x_min", "y_min", "x_max", "y_max", "confidence", "class"]) |
| df["class_name"] = df["class"].apply(lambda x: model.names[int(x)]) |
| df["width"] = df["x_max"] - df["x_min"] |
| df["height"] = df["y_max"] - df["y_min"] |
| df["area"] = df["width"] * df["height"] |
| |
| |
| summary = df.groupby("class_name").agg({ |
| 'area': ['count', 'mean', 'std', 'min', 'max'], |
| 'confidence': 'mean' |
| }).round(2) |
| summary.columns = ['Count', 'Mean Area', 'Std Dev', 'Min Area', 'Max Area', 'Avg Confidence'] |
| summary = summary.reset_index() |
| |
| |
| size_dist_plot = create_size_distribution_plot(df) |
| density_plot = create_density_heatmap(df, image.shape) |
| |
| return ( |
| annotated_img, |
| detection_str, |
| summary, |
| size_dist_plot, |
| density_plot |
| ) |
| else: |
| return ( |
| annotated_img, |
| "No cells detected", |
| pd.DataFrame(), |
| None, |
| None |
| ) |
|
|
| |
| with gr.Blocks(theme=gr.themes.Soft()) as app: |
| gr.Markdown(""" |
| # Bioengineering Image Analysis Tool |
| Upload microscopy images to detect and analyze cells using YOLOv10. |
| """) |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| input_image = gr.Image(type="numpy", label="Upload Image") |
| conf_slider = gr.Slider( |
| minimum=0.1, |
| maximum=1.0, |
| value=0.25, |
| step=0.05, |
| label="Confidence Threshold", |
| info="Adjust detection sensitivity" |
| ) |
| analyze_btn = gr.Button("Analyze Image", variant="primary") |
| |
| with gr.Column(scale=1): |
| output_image = gr.Image(type="numpy", label="Detected Cells") |
| detection_text = gr.Textbox(label="Detection Summary", lines=3) |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| stats_df = gr.Dataframe( |
| label="Cell Statistics", |
| headers=['Cell Type', 'Count', 'Mean Area', 'Std Dev', 'Min Area', 'Max Area', 'Avg Confidence'] |
| ) |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| size_plot = gr.Plot(label="Cell Size Distribution") |
| with gr.Column(scale=1): |
| density_plot = gr.Plot(label="Cell Density Heatmap") |
| |
| |
| analyze_btn.click( |
| process_image, |
| inputs=[input_image, conf_slider], |
| outputs=[output_image, detection_text, stats_df, size_plot, density_plot] |
| ) |
| |
| gr.Markdown(""" |
| ### Instructions: |
| 1. Upload a microscopy image containing cells |
| 2. Adjust the confidence threshold if needed (higher values = stricter detection) |
| 3. Click 'Analyze Image' to process |
| 4. View results in the various panels: |
| - Annotated image shows detected cells |
| - Summary provides cell counts |
| - Statistics table shows detailed measurements |
| - Plots visualize size distribution and spatial density |
| """) |
|
|
| |
| app.launch() |