| | import cv2 |
| | import numpy as np |
| | import pandas as pd |
| | import gradio as gr |
| | from skimage import measure, morphology |
| | from skimage.segmentation import watershed |
| | import matplotlib.pyplot as plt |
| |
|
| | def process_image(image): |
| | """Process uploaded image and extract cell features""" |
| | |
| | if len(image.shape) == 3: |
| | image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) |
| | |
| | |
| | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
| | clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) |
| | enhanced = clahe.apply(gray) |
| | blurred = cv2.medianBlur(enhanced, 5) |
| | |
| | |
| | thresh = cv2.adaptiveThreshold( |
| | blurred, 255, |
| | cv2.ADAPTIVE_THRESH_GAUSSIAN_C, |
| | cv2.THRESH_BINARY_INV, 21, 4 |
| | ) |
| | |
| | |
| | cleaned = morphology.opening(thresh, morphology.disk(2)) |
| | |
| | |
| | sure_bg = cv2.dilate(cleaned, morphology.disk(3), iterations=3) |
| | dist = cv2.distanceTransform(cleaned, cv2.DIST_L2, 5) |
| | ret, sure_fg = cv2.threshold(dist, 0.5*dist.max(), 255, 0) |
| | sure_fg = np.uint8(sure_fg) |
| | unknown = cv2.subtract(sure_bg, sure_fg) |
| | |
| | |
| | ret, markers = cv2.connectedComponents(sure_fg) |
| | markers += 1 |
| | markers[unknown == 255] = 0 |
| | markers = watershed(-dist, markers, mask=cleaned) |
| | |
| | |
| | features = [] |
| | props = measure.regionprops(markers, intensity_image=gray) |
| | |
| | for i, prop in enumerate(props): |
| | if prop.area < 50: |
| | continue |
| | |
| | features.append({ |
| | 'cell_id': i+1, |
| | 'area': prop.area, |
| | 'perimeter': prop.perimeter, |
| | 'circularity': (4 * np.pi * prop.area) / (prop.perimeter**2 + 1e-6), |
| | 'mean_intensity': prop.mean_intensity, |
| | 'centroid_x': prop.centroid[1], |
| | 'centroid_y': prop.centroid[0] |
| | }) |
| | |
| | |
| | vis_img = image.copy() |
| | contours = measure.find_contours(markers, 0.5) |
| | |
| | |
| | for contour in contours: |
| | coords = contour.astype(int) |
| | cv2.drawContours(vis_img, [coords], -1, (0,255,0), 1) |
| | |
| | for region in measure.regionprops(markers): |
| | if region.area >= 50: |
| | y, x = region.centroid |
| | cv2.putText(vis_img, str(region.label), |
| | (int(x), int(y)), |
| | cv2.FONT_HERSHEY_SIMPLEX, |
| | 0.4, (255,0,0), 1) |
| | |
| | |
| | fig, axes = plt.subplots(1, 2, figsize=(12, 6)) |
| | |
| | |
| | df = pd.DataFrame(features) |
| | df['area'].hist(ax=axes[0], bins=20) |
| | axes[0].set_title('Cell Size Distribution') |
| | axes[0].set_xlabel('Area') |
| | axes[0].set_ylabel('Count') |
| | |
| | |
| | axes[1].scatter(df['circularity'], df['mean_intensity']) |
| | axes[1].set_title('Circularity vs Intensity') |
| | axes[1].set_xlabel('Circularity') |
| | axes[1].set_ylabel('Mean Intensity') |
| | |
| | plt.tight_layout() |
| | |
| | return ( |
| | cv2.cvtColor(vis_img, cv2.COLOR_BGR2RGB), |
| | fig, |
| | df |
| | ) |
| |
|
| | |
| | with gr.Blocks(title="Cell Analysis Tool") as demo: |
| | gr.Markdown(""" |
| | # 🔬 Bioengineering Cell Analysis Tool |
| | |
| | Upload microscopy images to analyze cell properties: |
| | - Automated cell detection |
| | - Feature extraction (size, shape, intensity) |
| | - Statistical analysis |
| | |
| | **Instructions:** |
| | 1. Upload an image containing cells |
| | 2. Wait for analysis to complete |
| | 3. Review results in three tabs: |
| | - Detected cells visualization |
| | - Statistical plots |
| | - Detailed measurements table |
| | """) |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | input_image = gr.Image( |
| | label="Upload Image", |
| | type="numpy", |
| | tool="upload" |
| | ) |
| | analyze_btn = gr.Button( |
| | "Analyze Image", |
| | variant="primary" |
| | ) |
| | |
| | with gr.Column(): |
| | with gr.Tabs(): |
| | with gr.Tab("Detection Results"): |
| | output_image = gr.Image( |
| | label="Detected Cells" |
| | ) |
| | with gr.Tab("Statistics"): |
| | output_plot = gr.Plot( |
| | label="Statistical Analysis" |
| | ) |
| | with gr.Tab("Measurements"): |
| | output_table = gr.DataFrame( |
| | label="Cell Features" |
| | ) |
| | |
| | analyze_btn.click( |
| | fn=process_image, |
| | inputs=input_image, |
| | outputs=[output_image, output_plot, output_table] |
| | ) |
| |
|
| | |
| | if __name__ == "__main__": |
| | demo.launch() |