|
import cv2 |
|
import numpy as np |
|
import pandas as pd |
|
import gradio as gr |
|
import matplotlib.pyplot as plt |
|
from datetime import datetime |
|
|
|
def detect_blood_cells(image): |
|
"""Optimized 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, 100, 100]) |
|
upper_red1 = np.array([10, 255, 255]) |
|
lower_red2 = np.array([160, 100, 100]) |
|
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 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) |
|
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1) |
|
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2) |
|
|
|
|
|
dist_transform = cv2.distanceTransform(mask, cv2.DIST_L2, 5) |
|
_, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0) |
|
sure_fg = np.uint8(sure_fg) |
|
|
|
|
|
_, markers = cv2.connectedComponents(sure_fg) |
|
|
|
|
|
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
|
|
|
|
filtered_contours = [] |
|
for contour in contours: |
|
area = cv2.contourArea(contour) |
|
perimeter = cv2.arcLength(contour, True) |
|
if perimeter == 0: |
|
continue |
|
|
|
circularity = 4 * np.pi * area / (perimeter * perimeter) |
|
|
|
|
|
if 500 < area < 2500 and circularity > 0.8: |
|
filtered_contours.append(contour) |
|
|
|
return filtered_contours, markers |
|
|
|
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, markers = detect_blood_cells(image) |
|
|
|
|
|
features = [] |
|
for i, contour in enumerate(contours, 1): |
|
area = cv2.contourArea(contour) |
|
perimeter = cv2.arcLength(contour, True) |
|
circularity = 4 * np.pi * area / (perimeter * perimeter) |
|
|
|
|
|
M = cv2.moments(contour) |
|
if M["m00"] != 0: |
|
cx = int(M["m10"] / M["m00"]) |
|
cy = int(M["m01"] / M["m00"]) |
|
|
|
|
|
mask = np.zeros(image.shape[:2], dtype=np.uint8) |
|
cv2.drawContours(mask, [contour], -1, 255, -1) |
|
mean_intensity = cv2.mean(cv2.cvtColor(image, cv2.COLOR_RGB2GRAY), mask=mask)[0] |
|
|
|
features.append({ |
|
'label': i, |
|
'area': area, |
|
'perimeter': perimeter, |
|
'circularity': circularity, |
|
'mean_intensity': mean_intensity, |
|
'centroid_x': cx, |
|
'centroid_y': cy |
|
}) |
|
|
|
|
|
vis_img = image.copy() |
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
|
|
|
|
|
for feature in features: |
|
i = feature['label'] - 1 |
|
cv2.drawContours(vis_img, contours, i, (0, 255, 0), 2) |
|
|
|
|
|
x = feature['centroid_x'] |
|
y = feature['centroid_y'] |
|
|
|
cv2.putText(vis_img, str(feature['label']), |
|
(x-10, y), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.4, (255, 255, 255), 2) |
|
|
|
cv2.putText(vis_img, str(feature['label']), |
|
(x-10, y), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.4, (0, 0, 255), 1) |
|
|
|
|
|
info_text = f"Analyzed: {timestamp} | Cells Detected: {len(features)}" |
|
cv2.putText(vis_img, info_text, |
|
(10, 25), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.6, (255, 255, 255), 2) |
|
|
|
|
|
plt.style.use('default') |
|
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: |
|
|
|
axes[0,0].hist(df['area'], 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') |
|
axes[0,0].grid(True, alpha=0.3) |
|
|
|
axes[0,1].hist(df['circularity'], 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[0,1].grid(True, alpha=0.3) |
|
|
|
|
|
scatter = axes[1,0].scatter(df['area'], df['mean_intensity'], |
|
c=df['circularity'], cmap='viridis', |
|
alpha=0.6) |
|
axes[1,0].set_title('Area vs Intensity') |
|
axes[1,0].set_xlabel('Area') |
|
axes[1,0].set_ylabel('Mean Intensity') |
|
axes[1,0].grid(True, alpha=0.3) |
|
plt.colorbar(scatter, ax=axes[1,0], label='Circularity') |
|
|
|
|
|
df.boxplot(column=['area', 'circularity'], ax=axes[1,1]) |
|
axes[1,1].set_title('Feature Distributions') |
|
axes[1,1].grid(True, alpha=0.3) |
|
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)}") |
|
import traceback |
|
traceback.print_exc() |
|
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() |