| import cv2 |
| import numpy as np |
| import pandas as pd |
| import gradio as gr |
| from skimage import measure, morphology |
| import matplotlib.pyplot as plt |
| from datetime import datetime |
|
|
| def detect_blood_cells(image): |
| """Specialized function for blood cell detection""" |
| |
| if len(image.shape) == 2: |
| image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) |
| |
| |
| hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) |
| |
| |
| |
| lower_red1 = np.array([0, 70, 50]) |
| upper_red1 = np.array([10, 255, 255]) |
| lower_red2 = np.array([170, 70, 50]) |
| upper_red2 = np.array([180, 255, 255]) |
| |
| mask1 = cv2.inRange(hsv, lower_red1, upper_red1) |
| mask2 = cv2.inRange(hsv, lower_red2, upper_red2) |
| mask = mask1 + mask2 |
| |
| |
| kernel = np.ones((3,3), np.uint8) |
| mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=2) |
| mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2) |
| |
| |
| contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
| |
| return contours, mask |
|
|
| def apply_color_transformation(image, transform_type): |
| """Apply different color transformations to the image""" |
| if len(image.shape) == 2: |
| image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) |
| |
| if transform_type == "Original": |
| return image |
| elif transform_type == "Grayscale": |
| return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) |
| elif transform_type == "Binary": |
| gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) |
| _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) |
| return binary |
| elif transform_type == "CLAHE": |
| gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) |
| 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 blood cell features""" |
| if image is None: |
| return None, None, None, None |
| |
| try: |
| |
| original_image = image.copy() |
| |
| |
| contours, mask = detect_blood_cells(image) |
| |
| |
| features = [] |
| for i, contour in enumerate(contours, 1): |
| area = cv2.contourArea(contour) |
| |
| if 100 < area < 5000: |
| perimeter = cv2.arcLength(contour, True) |
| circularity = 4 * np.pi * area / (perimeter * perimeter) if perimeter > 0 else 0 |
| |
| |
| if circularity > 0.7: |
| M = cv2.moments(contour) |
| if M["m00"] != 0: |
| cx = int(M["m10"] / M["m00"]) |
| cy = int(M["m01"] / M["m00"]) |
| |
| features.append({ |
| 'label': i, |
| 'area': area, |
| 'perimeter': perimeter, |
| 'circularity': circularity, |
| 'centroid_x': cx, |
| 'centroid_y': cy |
| }) |
| |
| |
| vis_img = image.copy() |
| timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
| |
| |
| for feature in features: |
| contour = contours[feature['label']-1] |
| cv2.drawContours(vis_img, [contour], -1, (0, 255, 0), 2) |
| |
| |
| x = feature['centroid_x'] |
| y = 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} | Cells: {len(features)}", |
| (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('Blood 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 (pixels)') |
| 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['area'], df['circularity'], alpha=0.6, c='purple') |
| axes[1,0].set_title('Area vs Circularity') |
| axes[1,0].set_xlabel('Area') |
| axes[1,0].set_ylabel('Circularity') |
| |
| |
| 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 ( |
| vis_img, |
| 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() |