ibrahim313 commited on
Commit
4d94df5
·
verified ·
1 Parent(s): 67b1d32

Update app.py

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