| | 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 |
| | from datetime import datetime |
| | import logging |
| |
|
| | def apply_color_transformation(image, transform_type): |
| | """Apply different color transformations to the image""" |
| | if len(image.shape) == 3: |
| | image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) |
| | |
| | if transform_type == "Original": |
| | return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) |
| | elif transform_type == "Grayscale": |
| | return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
| | elif transform_type == "Binary": |
| | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
| | _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) |
| | return binary |
| | elif transform_type == "CLAHE": |
| | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
| | clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) |
| | return clahe.apply(gray) |
| | return image |
| |
|
| | def process_image(image, transform_type): |
| | """Process uploaded image and extract cell features""" |
| | if image is None: |
| | return None, None, None, None |
| | |
| | try: |
| | |
| | original_image = image.copy() |
| | |
| | |
| | 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) |
| | |
| | |
| | _, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) |
| | |
| | |
| | kernel = np.ones((3,3), np.uint8) |
| | opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2) |
| | |
| | |
| | sure_bg = cv2.dilate(opening, kernel, iterations=3) |
| | |
| | |
| | dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) |
| | _, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0) |
| | sure_fg = sure_fg.astype(np.uint8) |
| | |
| | |
| | unknown = cv2.subtract(sure_bg, sure_fg) |
| | |
| | |
| | _, markers = cv2.connectedComponents(sure_fg) |
| | markers = markers + 1 |
| | markers[unknown == 255] = 0 |
| | |
| | |
| | markers = cv2.watershed(image, markers) |
| | |
| | |
| | features = [] |
| | for region in measure.regionprops(markers): |
| | if region.area >= 50: |
| | features.append({ |
| | 'label': region.label, |
| | 'area': region.area, |
| | 'perimeter': region.perimeter, |
| | 'circularity': (4 * np.pi * region.area) / (region.perimeter ** 2) if region.perimeter > 0 else 0, |
| | 'mean_intensity': region.mean_intensity, |
| | 'centroid_x': region.centroid[1], |
| | 'centroid_y': region.centroid[0] |
| | }) |
| | |
| | |
| | timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
| | vis_img = image.copy() |
| | |
| | |
| | contours = measure.find_contours(markers, 0.5) |
| | for contour in contours: |
| | coords = np.array(contour).astype(int) |
| | coords = coords[:, [1, 0]] |
| | coords = coords.reshape((-1, 1, 2)) |
| | cv2.polylines(vis_img, [coords], True, (0, 255, 0), 2) |
| | |
| | |
| | for feature in features: |
| | x = int(feature['centroid_x']) |
| | y = int(feature['centroid_y']) |
| | |
| | cv2.putText(vis_img, str(feature['label']), |
| | (x, y), cv2.FONT_HERSHEY_SIMPLEX, |
| | 0.5, (255,255,255), 2) |
| | |
| | cv2.putText(vis_img, str(feature['label']), |
| | (x, y), cv2.FONT_HERSHEY_SIMPLEX, |
| | 0.5, (0,0,255), 1) |
| | |
| | |
| | cv2.putText(vis_img, f"Analyzed: {timestamp}", |
| | (10, 30), cv2.FONT_HERSHEY_SIMPLEX, |
| | 0.7, (255,255,255), 2) |
| | |
| | |
| | plt.style.use('seaborn') |
| | fig, axes = plt.subplots(2, 2, figsize=(15, 12)) |
| | fig.suptitle('Cell Analysis Results', fontsize=16, y=0.95) |
| | |
| | df = pd.DataFrame(features) |
| | if not df.empty: |
| | |
| | df['area'].hist(ax=axes[0,0], bins=20, color='skyblue', edgecolor='black') |
| | axes[0,0].set_title('Cell Size Distribution') |
| | axes[0,0].set_xlabel('Area') |
| | axes[0,0].set_ylabel('Count') |
| | |
| | df['circularity'].hist(ax=axes[0,1], bins=20, color='lightgreen', edgecolor='black') |
| | axes[0,1].set_title('Circularity Distribution') |
| | axes[0,1].set_xlabel('Circularity') |
| | axes[0,1].set_ylabel('Count') |
| | |
| | |
| | axes[1,0].scatter(df['circularity'], df['mean_intensity'], |
| | alpha=0.6, c='purple') |
| | axes[1,0].set_title('Circularity vs Intensity') |
| | axes[1,0].set_xlabel('Circularity') |
| | axes[1,0].set_ylabel('Mean Intensity') |
| | |
| | |
| | df.boxplot(column=['area', 'circularity'], ax=axes[1,1]) |
| | axes[1,1].set_title('Feature Distributions') |
| | else: |
| | for ax in axes.flat: |
| | ax.text(0.5, 0.5, 'No cells detected', ha='center', va='center') |
| | |
| | plt.tight_layout() |
| | |
| | |
| | transformed_image = apply_color_transformation(original_image, transform_type) |
| | |
| | return ( |
| | cv2.cvtColor(vis_img, cv2.COLOR_BGR2RGB), |
| | transformed_image, |
| | fig, |
| | df |
| | ) |
| | |
| | except Exception as e: |
| | print(f"Error processing image: {str(e)}") |
| | return None, None, None, None |
| |
|
| | |
| | with gr.Blocks(title="Advanced Cell Analysis Tool", theme=gr.themes.Soft()) as demo: |
| | gr.Markdown(""" |
| | # π¬ Advanced Bioengineering Cell Analysis Tool |
| | |
| | ## Features |
| | - π Automated cell detection and measurement |
| | - π Comprehensive statistical analysis |
| | - π¨ Multiple visualization options |
| | - π₯ Downloadable results |
| | |
| | ## Author |
| | - **Muhammad Ibrahim Qasmi** |
| | - [LinkedIn](https://www.linkedin.com/in/muhammad-ibrahim-qasmi-9876a1297/) |
| | """) |
| | |
| | with gr.Row(): |
| | with gr.Column(scale=1): |
| | input_image = gr.Image( |
| | label="Upload Image", |
| | type="numpy" |
| | ) |
| | transform_type = gr.Dropdown( |
| | choices=["Original", "Grayscale", "Binary", "CLAHE"], |
| | value="Original", |
| | label="Image Transform" |
| | ) |
| | analyze_btn = gr.Button( |
| | "Analyze Image", |
| | variant="primary", |
| | size="lg" |
| | ) |
| | |
| | with gr.Column(scale=2): |
| | with gr.Tabs(): |
| | with gr.Tab("Analysis Results"): |
| | output_image = gr.Image( |
| | label="Detected Cells" |
| | ) |
| | gr.Markdown("*Green contours show detected cells, red numbers are cell IDs*") |
| | |
| | with gr.Tab("Image Transformations"): |
| | transformed_image = gr.Image( |
| | label="Transformed Image" |
| | ) |
| | gr.Markdown("*Select different transformations from the dropdown menu*") |
| | |
| | with gr.Tab("Statistics"): |
| | output_plot = gr.Plot( |
| | label="Statistical Analysis" |
| | ) |
| | gr.Markdown("*Hover over plots for detailed values*") |
| | |
| | with gr.Tab("Data"): |
| | output_table = gr.DataFrame( |
| | label="Cell Features" |
| | ) |
| | |
| | analyze_btn.click( |
| | fn=process_image, |
| | inputs=[input_image, transform_type], |
| | outputs=[output_image, transformed_image, output_plot, output_table] |
| | ) |
| |
|
| | |
| | if __name__ == "__main__": |
| | demo.launch() |