HeshamAI commited on
Commit
99da8a7
·
verified ·
1 Parent(s): 9bd02f7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -124
app.py CHANGED
@@ -131,141 +131,72 @@ class DicomAnalyzer:
131
  # Get image dimensions
132
  height, width = raw_image.shape[:2]
133
 
134
- # Get clicked coordinates
135
  clicked_x = evt.index[0]
136
  clicked_y = evt.index[1]
137
 
138
- # ImageJ coordinate system conversion
139
  if self.zoom_factor != 1.0:
140
- # Convert from display coordinates to image coordinates
141
  x = int((clicked_x + self.pan_x) / self.zoom_factor)
142
  y = int((clicked_y + self.pan_y) / self.zoom_factor)
143
  else:
144
- # Direct mapping for no zoom
145
- x = int(clicked_x)
146
- y = int(clicked_y)
147
 
148
- # Offset correction for ImageJ compatibility
149
- x = x + 4 # Adjust these offset values based on testing
150
- y = y + 4 # Adjust these offset values based on testing
151
-
152
- # Ensure coordinates are within bounds
153
- x = max(0, min(x, width-1))
154
- y = max(0, min(y, height-1))
155
-
156
- # Create circular mask
157
- mask = np.zeros_like(raw_image, dtype=np.uint8)
158
- y_indices, x_indices = np.ogrid[:height, :width]
159
- radius = self.circle_diameter / 2
160
- distance_from_center = np.sqrt(
161
- (x_indices - x)**2 + (y_indices - y)**2
162
- )
163
- mask[distance_from_center <= radius] = 1
164
-
165
- # Get ROI pixels directly from raw image
166
- roi_pixels = raw_image[mask == 1]
167
-
168
- # Calculate statistics from raw values
169
- pixel_spacing = float(self.dicom_data.PixelSpacing[0])
170
- area_pixels = np.sum(mask)
171
- area_mm2 = area_pixels * (pixel_spacing ** 2)
172
-
173
- # Calculate statistics
174
- mean = np.mean(roi_pixels)
175
- stddev = np.std(roi_pixels)
176
- min_val = np.min(roi_pixels)
177
- max_val = np.max(roi_pixels)
178
-
179
- # Store results
180
- result = {
181
- 'Area (mm²)': f"{area_mm2:.3f}",
182
- 'Mean': f"{mean:.3f}",
183
- 'StdDev': f"{stddev:.3f}",
184
- 'Min': f"{min_val:.3f}",
185
- 'Max': f"{max_val:.3f}",
186
- 'Point': f"({x}, {y})"
187
- }
188
-
189
- self.results.append(result)
190
- self.marks.append((x, y, self.circle_diameter))
191
-
192
- # Debug information
193
- print(f"Original click: ({clicked_x}, {clicked_y})")
194
- print(f"Adjusted coordinates: ({x}, {y})")
195
- print(f"Zoom factor: {self.zoom_factor}")
196
- print(f"Pan: ({self.pan_x}, {self.pan_y})")
197
- print(f"ROI Statistics: Mean={mean:.3f}, StdDev={stddev:.3f}")
198
- print(f"Min={min_val:.3f}, Max={max_val:.3f}")
199
-
200
- return self.update_display(), self.format_results()
201
- except Exception as e:
202
- print(f"Error analyzing ROI: {str(e)}")
203
- return self.display_image, f"Error analyzing ROI: {str(e)}"
204
-
205
- def update_display(self):
206
- try:
207
- if self.original_display is None:
208
- return None
209
-
210
- height, width = self.original_display.shape[:2]
211
- new_height = int(height * self.zoom_factor)
212
- new_width = int(width * self.zoom_factor)
213
-
214
- # Create zoomed image
215
- zoomed = cv2.resize(self.original_display, (new_width, new_height),
216
- interpolation=cv2.INTER_CUBIC)
217
-
218
- # Convert to BGR for drawing
219
- zoomed_bgr = cv2.cvtColor(zoomed, cv2.COLOR_RGB2BGR)
220
-
221
- # Draw marks
222
- for x, y, diameter in self.marks:
223
- zoomed_x = int(x * self.zoom_factor)
224
- zoomed_y = int(y * self.zoom_factor)
225
- zoomed_diameter = int(diameter * self.zoom_factor)
226
-
227
- # Draw main circle in BGR color space
228
- cv2.circle(zoomed_bgr,
229
- (zoomed_x, zoomed_y),
230
- zoomed_diameter // 2,
231
- (0, 255, 255), # BGR: Yellow
232
- 1,
233
- lineType=cv2.LINE_AA)
234
-
235
- # Draw dots on circle
236
- num_points = 8
237
- for i in range(num_points):
238
- angle = 2 * np.pi * i / num_points
239
- point_x = int(zoomed_x + (zoomed_diameter/2) * np.cos(angle))
240
- point_y = int(zoomed_y + (zoomed_diameter/2) * np.sin(angle))
241
- cv2.circle(zoomed_bgr,
242
- (point_x, point_y),
243
- 1,
244
- (0, 255, 255), # BGR: Yellow
245
- -1,
246
- lineType=cv2.LINE_AA)
247
 
248
- # Convert back to RGB for display
249
- zoomed = cv2.cvtColor(zoomed_bgr, cv2.COLOR_BGR2RGB)
250
 
251
- # Calculate pan limits
252
- self.max_pan_x = max(0, new_width - width)
253
- self.max_pan_y = max(0, new_height - height)
254
-
255
- # Ensure pan values are within bounds
256
- self.pan_x = min(max(0, self.pan_x), self.max_pan_x)
257
- self.pan_y = min(max(0, self.pan_y), self.max_pan_y)
258
-
259
- # Extract visible portion
260
- visible = zoomed[
261
- int(self.pan_y):int(self.pan_y + height),
262
- int(self.pan_x):int(self.pan_x + width)
263
- ]
 
 
 
 
 
 
 
 
 
 
 
264
 
265
- return visible
266
- except Exception as e:
267
- print(f"Error updating display: {str(e)}")
268
- return self.original_display
269
 
270
  def format_results(self):
271
  if not self.results:
 
131
  # Get image dimensions
132
  height, width = raw_image.shape[:2]
133
 
134
+ # Get clicked coordinates and adjust for ImageJ alignment
135
  clicked_x = evt.index[0]
136
  clicked_y = evt.index[1]
137
 
138
+ # Convert coordinates with ImageJ offset correction
139
  if self.zoom_factor != 1.0:
140
+ # For zoomed image
141
  x = int((clicked_x + self.pan_x) / self.zoom_factor)
142
  y = int((clicked_y + self.pan_y) / self.zoom_factor)
143
  else:
144
+ x = clicked_x
145
+ y = clicked_y
 
146
 
147
+ # Apply ImageJ coordinate system correction
148
+ # These offset values might need fine-tuning based on testing
149
+ x_offset = -2 # Adjust this value
150
+ y_offset = -2 # Adjust this value
151
+
152
+ x = x + x_offset
153
+ y = y + y_offset
154
+
155
+ # Ensure coordinates are within bounds
156
+ x = max(0, min(x, width-1))
157
+ y = max(0, min(y, height-1))
158
+
159
+ # Create circular mask with adjusted coordinates
160
+ mask = np.zeros_like(raw_image, dtype=np.uint8)
161
+ y_indices, x_indices = np.ogrid[:height, :width]
162
+ radius = self.circle_diameter / 2
163
+ distance_from_center = np.sqrt(
164
+ (x_indices - x)**2 + (y_indices - y)**2
165
+ )
166
+ mask[distance_from_center <= radius] = 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
+ # Get ROI pixels using ImageJ-aligned coordinates
169
+ roi_pixels = raw_image[mask == 1]
170
 
171
+ # Calculate statistics using ImageJ scaling
172
+ pixel_spacing = float(self.dicom_data.PixelSpacing[0])
173
+ area_pixels = np.sum(mask)
174
+ area_mm2 = area_pixels * (pixel_spacing ** 2)
175
+
176
+ # Apply ImageJ-like scaling to match results
177
+ scaling_factor = 1.0 # Adjust this value to match ImageJ scaling
178
+ mean = np.mean(roi_pixels) * scaling_factor
179
+ stddev = np.std(roi_pixels) * scaling_factor
180
+ min_val = np.min(roi_pixels)
181
+ max_val = np.max(roi_pixels)
182
+
183
+ # Store results
184
+ result = {
185
+ 'Area (mm²)': f"{area_mm2:.3f}",
186
+ 'Mean': f"{mean:.3f}",
187
+ 'StdDev': f"{stddev:.3f}",
188
+ 'Min': f"{min_val:.3f}",
189
+ 'Max': f"{max_val:.3f}",
190
+ 'Point': f"({x}, {y})"
191
+ }
192
+
193
+ self.results.append(result)
194
+ self.marks.append((x, y, self.circle_diameter))
195
 
196
+ return self.update_display(), self.format_results()
197
+ except Exception as e:
198
+ print(f"Error analyzing ROI: {str(e)}")
199
+ return self.display_image, f"Error analyzing ROI: {str(e)}"
200
 
201
  def format_results(self):
202
  if not self.results: