|
import cv2 |
|
import numpy as np |
|
import pandas as pd |
|
import gradio as gr |
|
from skimage import morphology, segmentation |
|
import matplotlib.pyplot as plt |
|
from datetime import datetime |
|
|
|
def enhanced_preprocessing(image): |
|
"""Advanced image preprocessing pipeline""" |
|
|
|
lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) |
|
|
|
|
|
l_channel = lab[:,:,0] |
|
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) |
|
lab[:,:,0] = clahe.apply(l_channel) |
|
|
|
|
|
enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) |
|
|
|
|
|
filtered = cv2.bilateralFilter(enhanced, 9, 75, 75) |
|
|
|
return filtered |
|
|
|
def detect_cells(image): |
|
"""Advanced cell detection using multiple techniques""" |
|
|
|
processed = enhanced_preprocessing(image) |
|
|
|
|
|
gray = cv2.cvtColor(processed, cv2.COLOR_RGB2GRAY) |
|
|
|
|
|
binary = cv2.adaptiveThreshold(gray, 255, |
|
cv2.ADAPTIVE_THRESH_GAUSSIAN_C, |
|
cv2.THRESH_BINARY_INV, 21, 4) |
|
|
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) |
|
cleaned = morphology.area_opening(binary, area_threshold=128) |
|
cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, kernel, iterations=2) |
|
|
|
|
|
distance = cv2.distanceTransform(cleaned, cv2.DIST_L2, 3) |
|
_, sure_fg = cv2.threshold(distance, 0.5*distance.max(), 255, 0) |
|
sure_fg = np.uint8(sure_fg) |
|
|
|
|
|
_, markers = cv2.connectedComponents(sure_fg) |
|
markers += 1 |
|
markers[cleaned == 0] = 0 |
|
|
|
|
|
segmented = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) |
|
markers = segmentation.watershed(segmented, markers) |
|
|
|
|
|
contours = [] |
|
for label in np.unique(markers): |
|
if label < 1: |
|
continue |
|
mask = np.zeros(gray.shape, dtype="uint8") |
|
mask[markers == label] = 255 |
|
cnts, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
contours.extend(cnts) |
|
|
|
return contours, cleaned |
|
|
|
def feature_analysis(contours, image): |
|
"""Comprehensive feature extraction and validation""" |
|
features = [] |
|
for i, contour in enumerate(contours, 1): |
|
area = cv2.contourArea(contour) |
|
perimeter = cv2.arcLength(contour, True) |
|
|
|
|
|
circularity = (4 * np.pi * area) / (perimeter**2 + 1e-6) |
|
|
|
|
|
if 50 < area < 10000 and 0.4 < circularity < 1.2: |
|
M = cv2.moments(contour) |
|
if M["m00"] != 0: |
|
cx = int(M["m10"] / M["m00"]) |
|
cy = int(M["m01"] / M["m00"]) |
|
|
|
|
|
hull = cv2.convexHull(contour) |
|
hull_area = cv2.contourArea(hull) |
|
convexity = area / hull_area if hull_area > 0 else 0 |
|
|
|
features.append({ |
|
'Cell ID': i, |
|
'Area (px²)': area, |
|
'Perimeter (px)': perimeter, |
|
'Circularity': round(circularity, 3), |
|
'Convexity': round(convexity, 3), |
|
'Centroid X': cx, |
|
'Centroid Y': cy |
|
}) |
|
|
|
return features |
|
|
|
def visualize_results(image, contours, features): |
|
"""Enhanced visualization with better annotations""" |
|
vis_img = image.copy() |
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
|
|
|
|
|
for idx, feature in enumerate(features): |
|
contour = contours[idx] |
|
cv2.drawContours(vis_img, [contour], -1, (0, 255, 0), 2) |
|
|
|
|
|
x, y = feature['Centroid X'], feature['Centroid Y'] |
|
cv2.putText(vis_img, str(feature['Cell ID']), |
|
(x+5, y-5), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.6, (255, 255, 255), 3) |
|
cv2.putText(vis_img, str(feature['Cell ID']), |
|
(x+5, y-5), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.6, (0, 0, 255), 2) |
|
|
|
|
|
cv2.putText(vis_img, f"Cells Detected: {len(features)} | {timestamp}", |
|
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.7, (0, 0, 0), 3) |
|
cv2.putText(vis_img, f"Cells Detected: {len(features)} | {timestamp}", |
|
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.7, (255, 255, 255), 2) |
|
|
|
return vis_img |
|
|
|
def process_image(image, transform_type): |
|
"""Upgraded image processing pipeline""" |
|
if image is None: |
|
return None, None, None, None |
|
|
|
try: |
|
original = image.copy() |
|
contours, mask = detect_cells(image) |
|
features = feature_analysis(contours, image) |
|
vis_img = visualize_results(image, contours, features) |
|
|
|
|
|
plt.style.use('seaborn-v0_8') |
|
fig, ax = plt.subplots(2, 2, figsize=(15, 12)) |
|
fig.suptitle('Advanced Cell Analysis', fontsize=16) |
|
|
|
df = pd.DataFrame(features) |
|
if not df.empty: |
|
ax[0,0].hist(df['Area (px²)'], bins=30, color='#1f77b4', ec='black') |
|
ax[0,0].set_title('Area Distribution') |
|
|
|
ax[0,1].scatter(df['Circularity'], df['Convexity'], |
|
c=df['Area (px²)'], cmap='viridis', alpha=0.7) |
|
ax[0,1].set_title('Shape Correlation') |
|
|
|
ax[1,0].boxplot([df['Area (px²)'], df['Circularity']], |
|
labels=['Area', 'Circularity']) |
|
ax[1,0].set_title('Feature Distribution') |
|
|
|
ax[1,1].hexbin(df['Centroid X'], df['Centroid Y'], |
|
gridsize=20, cmap='plasma', bins='log') |
|
ax[1,1].set_title('Spatial Distribution') |
|
|
|
plt.tight_layout() |
|
|
|
return ( |
|
vis_img, |
|
apply_color_transformation(original, transform_type), |
|
fig, |
|
df |
|
) |
|
|
|
except Exception as e: |
|
print(f"Error: {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() |