|
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 |
|
import os |
|
|
|
|
|
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 |
|
) |
|
|
|
def load_example_image(): |
|
"""Load the example test image""" |
|
example_image = cv2.imread("test.png") |
|
if example_image is None: |
|
return None |
|
return example_image |
|
|
|
|
|
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") |
|
with gr.Row(): |
|
example_btn = gr.Button("Try Example Image") |
|
analyze_btn = gr.Button("Analyze Image", variant="primary") |
|
conf_slider = gr.Slider( |
|
minimum=0.1, |
|
maximum=1.0, |
|
value=0.25, |
|
step=0.05, |
|
label="Confidence Threshold", |
|
info="Adjust detection sensitivity" |
|
) |
|
|
|
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") |
|
|
|
|
|
example_btn.click( |
|
load_example_image, |
|
outputs=input_image |
|
) |
|
|
|
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 or click 'Try Example Image' |
|
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() |