File size: 7,656 Bytes
8312ddd d28c822 4d94df5 3cf3c0d 4d94df5 b5ba092 4d94df5 b5ba092 4d94df5 cfb7ff1 4d94df5 67b1d32 4d94df5 8312ddd 4d94df5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
import cv2
import numpy as np
import pandas as pd
import gradio as gr
import matplotlib.pyplot as plt
from datetime import datetime
from sklearn.cluster import DBSCAN
from scipy import ndimage
class BloodCellAnalyzer:
def __init__(self):
self.min_cell_area = 100
self.max_cell_area = 5000
self.min_circularity = 0.7
def preprocess_image(self, image):
"""Enhanced image preprocessing with multiple color spaces and filtering."""
if len(image.shape) == 2:
image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
# Convert to multiple color spaces for robust detection
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# Create masks for different color ranges
hsv_mask = cv2.inRange(hsv, np.array([0, 20, 20]), np.array([180, 255, 255]))
lab_mask = cv2.inRange(lab, np.array([20, 120, 120]), np.array([200, 140, 140]))
# Combine masks
combined_mask = cv2.bitwise_or(hsv_mask, lab_mask)
# Apply advanced morphological operations
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
clean_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_CLOSE, kernel, iterations=2)
clean_mask = cv2.morphologyEx(clean_mask, cv2.MORPH_OPEN, kernel, iterations=1)
# Apply distance transform to separate touching cells
dist_transform = cv2.distanceTransform(clean_mask, cv2.DIST_L2, 5)
_, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0)
return clean_mask.astype(np.uint8), sure_fg.astype(np.uint8)
def extract_cell_features(self, contour):
"""Extract comprehensive features for each detected cell."""
area = cv2.contourArea(contour)
perimeter = cv2.arcLength(contour, True)
circularity = 4 * np.pi * area / (perimeter ** 2) if perimeter > 0 else 0
# Calculate additional shape features
hull = cv2.convexHull(contour)
hull_area = cv2.contourArea(hull)
solidity = float(area) / hull_area if hull_area > 0 else 0
# Calculate moments and orientation
moments = cv2.moments(contour)
cx = int(moments['m10'] / moments['m00']) if moments['m00'] != 0 else 0
cy = int(moments['m01'] / moments['m00']) if moments['m00'] != 0 else 0
# Calculate eccentricity using ellipse fitting
if len(contour) >= 5:
(x, y), (MA, ma), angle = cv2.fitEllipse(contour)
eccentricity = np.sqrt(1 - (ma / MA) ** 2) if MA > 0 else 0
else:
eccentricity = 0
angle = 0
return {
'area': area,
'perimeter': perimeter,
'circularity': circularity,
'solidity': solidity,
'eccentricity': eccentricity,
'orientation': angle,
'centroid_x': cx,
'centroid_y': cy
}
def detect_cells(self, image):
"""Detect and analyze blood cells with advanced filtering."""
mask, sure_fg = self.preprocess_image(image)
# Find contours
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Extract features and filter cells
cells = []
valid_contours = []
for i, contour in enumerate(contours):
features = self.extract_cell_features(contour)
# Apply multiple criteria for cell validation
if (self.min_cell_area < features['area'] < self.max_cell_area and
features['circularity'] > self.min_circularity and
features['solidity'] > 0.8):
features['label'] = i + 1
cells.append(features)
valid_contours.append(contour)
return valid_contours, cells, mask
def analyze_image(self, image):
"""Perform comprehensive image analysis and generate visualizations."""
if image is None:
return None, None, None, None
# Detect cells and extract features
contours, cells, mask = self.detect_cells(image)
vis_img = image.copy()
# Draw detections and labels
for cell in cells:
contour = contours[cell['label'] - 1]
cv2.drawContours(vis_img, [contour], -1, (0, 255, 0), 2)
cv2.putText(vis_img, str(cell['label']),
(cell['centroid_x'], cell['centroid_y']),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
# Create DataFrame and calculate summary statistics
df = pd.DataFrame(cells)
if not df.empty:
summary_stats = {
'total_cells': len(cells),
'avg_cell_size': df['area'].mean(),
'std_cell_size': df['area'].std(),
'avg_circularity': df['circularity'].mean(),
'cell_density': len(cells) / (image.shape[0] * image.shape[1])
}
df = df.assign(**{k: [v] * len(df) for k, v in summary_stats.items()})
# Generate visualizations
fig = self.generate_analysis_plots(df)
return vis_img, mask, fig, df
def generate_analysis_plots(self, df):
"""Generate comprehensive analysis plots."""
if df.empty:
return None
plt.style.use('dark_background')
fig = plt.figure(figsize=(15, 10))
# Create subplot grid
gs = plt.GridSpec(2, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[0, 2])
ax4 = fig.add_subplot(gs[1, :])
# Cell size distribution
ax1.hist(df['area'], bins=20, color='cyan', edgecolor='black')
ax1.set_title('Cell Size Distribution')
ax1.set_xlabel('Area')
ax1.set_ylabel('Count')
# Area vs Circularity
scatter = ax2.scatter(df['area'], df['circularity'],
c=df['solidity'], cmap='viridis', alpha=0.6)
ax2.set_title('Area vs Circularity')
ax2.set_xlabel('Area')
ax2.set_ylabel('Circularity')
plt.colorbar(scatter, ax=ax2, label='Solidity')
# Eccentricity distribution
ax3.hist(df['eccentricity'], bins=15, color='magenta', edgecolor='black')
ax3.set_title('Eccentricity Distribution')
ax3.set_xlabel('Eccentricity')
ax3.set_ylabel('Count')
# Cell position scatter plot
scatter = ax4.scatter(df['centroid_x'], df['centroid_y'],
c=df['area'], cmap='plasma', alpha=0.6, s=100)
ax4.set_title('Cell Positions and Sizes')
ax4.set_xlabel('X Position')
ax4.set_ylabel('Y Position')
plt.colorbar(scatter, ax=ax4, label='Cell Area')
plt.tight_layout()
return fig
# Create Gradio interface
analyzer = BloodCellAnalyzer()
demo = gr.Interface(
fn=analyzer.analyze_image,
inputs=gr.Image(type="numpy"),
outputs=[
gr.Image(label="Detected Cells"),
gr.Image(label="Segmentation Mask"),
gr.Plot(label="Analysis Plots"),
gr.DataFrame(label="Cell Data")
],
title="Blood Cell Analysis Tool",
description="Upload an image to analyze blood cells and extract features."
)
if __name__ == "__main__":
demo.launch() |