HeshamAI commited on
Commit
b7e4b29
·
verified ·
1 Parent(s): a82c6bf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -98
app.py CHANGED
@@ -28,23 +28,6 @@ class DicomAnalyzer:
28
  self.CIRCLE_COLOR = (0, 255, 255) # BGR Yellow
29
  print("DicomAnalyzer initialized...")
30
 
31
- def transform_coordinates(self, clicked_x, clicked_y):
32
- """Transform screen coordinates to image coordinates using ImageJ method"""
33
- # Transform from screen to image coordinates
34
- x = clicked_x + self.pan_x
35
- y = clicked_y + self.pan_y
36
-
37
- # Apply zoom factor
38
- if self.zoom_factor != 1.0:
39
- x = x / self.zoom_factor
40
- y = y / self.zoom_factor
41
-
42
- # Round to nearest integer to match ImageJ behavior
43
- x = round(x)
44
- y = round(y)
45
-
46
- return x, y
47
-
48
  def load_dicom(self, file):
49
  try:
50
  if file is None:
@@ -139,89 +122,89 @@ class DicomAnalyzer:
139
  print(f"Error handling keyboard input: {str(e)}")
140
  return self.display_image
141
 
142
- def analyze_roi(self, evt: gr.SelectData):
143
- try:
144
- if self.current_image is None:
145
- return None, "No image loaded"
146
-
147
- # Get clicked coordinates
148
- clicked_x = evt.index[0]
149
- clicked_y = evt.index[1]
150
-
151
- # Transform coordinates to match ImageJ exactly
152
- x = clicked_x + self.pan_x
153
- y = clicked_y + self.pan_y
154
- if self.zoom_factor != 1.0:
155
- x = x / self.zoom_factor
156
- y = y / self.zoom_factor
157
-
158
- # ImageJ uses integer coordinates
159
- x = int(round(x))
160
- y = int(round(y))
161
-
162
- # Get image dimensions
163
- height, width = self.current_image.shape[:2]
164
-
165
- # Create mask exactly as ImageJ does
166
- Y, X = np.ogrid[:height, :width]
167
- center_x = x
168
- center_y = y
169
-
170
- # ImageJ uses a specific radius calculation
171
- radius = self.circle_diameter / 2.0
172
-
173
- # Create the mask using ImageJ's method
174
- dx = X - center_x
175
- dy = Y - center_y
176
- dist_squared = dx * dx + dy * dy
177
- mask = dist_squared <= (radius * radius)
178
-
179
- # Get ROI pixels
180
- roi_pixels = self.current_image[mask]
181
-
182
- if len(roi_pixels) == 0:
183
- return self.display_image, "Error: No pixels selected"
184
-
185
- # Get pixel spacing (mm/pixel)
186
- pixel_spacing = float(self.dicom_data.PixelSpacing[0])
187
-
188
- # Calculate statistics exactly as ImageJ does
189
- n_pixels = np.sum(mask)
190
- area = n_pixels * (pixel_spacing ** 2)
191
-
192
- # Use ImageJ's statistical calculations
193
- mean_value = np.mean(roi_pixels)
194
- std_dev = np.std(roi_pixels, ddof=1) # ImageJ uses n-1
195
- min_val = np.min(roi_pixels)
196
- max_val = np.max(roi_pixels)
197
 
198
- # Print debug information
199
- print(f"\nDetailed Analysis:")
200
- print(f"Coordinates: ({x}, {y})")
201
- print(f"Pixel count: {n_pixels}")
202
- print(f"Area: {area:.3f} mm²")
203
- print(f"Mean: {mean_value:.3f}")
204
- print(f"StdDev: {std_dev:.3f}")
205
- print(f"Min: {min_val}")
206
- print(f"Max: {max_val}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
- # Store results
209
- result = {
210
- 'Area (mm²)': f"{area:.3f}",
211
- 'Mean': f"{mean_value:.3f}",
212
- 'StdDev': f"{std_dev:.3f}",
213
- 'Min': f"{min_val:.3f}",
214
- 'Max': f"{max_val:.3f}",
215
- 'Point': f"({x}, {y})"
216
- }
217
-
218
- self.results.append(result)
219
- self.marks.append((x, y, self.circle_diameter))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
- return self.update_display(), self.format_results()
222
- except Exception as e:
223
- print(f"Error analyzing ROI: {str(e)}")
224
- return self.display_image, f"Error analyzing ROI: {str(e)}"
225
  def update_display(self):
226
  try:
227
  if self.original_display is None:
@@ -242,7 +225,7 @@ def analyze_roi(self, evt: gr.SelectData):
242
  for x, y, diameter in self.marks:
243
  zoomed_x = int(x * self.zoom_factor)
244
  zoomed_y = int(y * self.zoom_factor)
245
- zoomed_radius = int(((diameter - 1) / 2) * self.zoom_factor) # ImageJ radius
246
 
247
  # Draw main circle
248
  cv2.circle(zoomed_bgr,
 
28
  self.CIRCLE_COLOR = (0, 255, 255) # BGR Yellow
29
  print("DicomAnalyzer initialized...")
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  def load_dicom(self, file):
32
  try:
33
  if file is None:
 
122
  print(f"Error handling keyboard input: {str(e)}")
123
  return self.display_image
124
 
125
+ def analyze_roi(self, evt: gr.SelectData):
126
+ try:
127
+ if self.current_image is None:
128
+ return None, "No image loaded"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
+ # Get clicked coordinates
131
+ clicked_x = evt.index[0]
132
+ clicked_y = evt.index[1]
133
+
134
+ # Transform coordinates to match ImageJ exactly
135
+ x = clicked_x + self.pan_x
136
+ y = clicked_y + self.pan_y
137
+ if self.zoom_factor != 1.0:
138
+ x = x / self.zoom_factor
139
+ y = y / self.zoom_factor
140
+
141
+ # ImageJ uses integer coordinates
142
+ x = int(round(x))
143
+ y = int(round(y))
144
+
145
+ # Get image dimensions
146
+ height, width = self.current_image.shape[:2]
147
+
148
+ # Create mask exactly as ImageJ does
149
+ Y, X = np.ogrid[:height, :width]
150
+ center_x = x
151
+ center_y = y
152
+
153
+ # ImageJ uses a specific radius calculation
154
+ radius = self.circle_diameter / 2.0
155
+
156
+ # Create the mask using ImageJ's method
157
+ dx = X - center_x
158
+ dy = Y - center_y
159
+ dist_squared = dx * dx + dy * dy
160
+ mask = dist_squared <= (radius * radius)
161
+
162
+ # Get ROI pixels
163
+ roi_pixels = self.current_image[mask]
164
+
165
+ if len(roi_pixels) == 0:
166
+ return self.display_image, "Error: No pixels selected"
167
 
168
+ # Get pixel spacing (mm/pixel)
169
+ pixel_spacing = float(self.dicom_data.PixelSpacing[0])
170
+
171
+ # Calculate statistics exactly as ImageJ does
172
+ n_pixels = np.sum(mask)
173
+ area = n_pixels * (pixel_spacing ** 2)
174
+
175
+ # Use ImageJ's statistical calculations
176
+ mean_value = np.mean(roi_pixels)
177
+ std_dev = np.std(roi_pixels, ddof=1) # ImageJ uses n-1
178
+ min_val = np.min(roi_pixels)
179
+ max_val = np.max(roi_pixels)
180
+
181
+ # Print debug information
182
+ print(f"\nDetailed Analysis:")
183
+ print(f"Coordinates: ({x}, {y})")
184
+ print(f"Pixel count: {n_pixels}")
185
+ print(f"Area: {area:.3f} mm²")
186
+ print(f"Mean: {mean_value:.3f}")
187
+ print(f"StdDev: {std_dev:.3f}")
188
+ print(f"Min: {min_val}")
189
+ print(f"Max: {max_val}")
190
+
191
+ # Store results
192
+ result = {
193
+ 'Area (mm²)': f"{area:.3f}",
194
+ 'Mean': f"{mean_value:.3f}",
195
+ 'StdDev': f"{std_dev:.3f}",
196
+ 'Min': f"{min_val:.3f}",
197
+ 'Max': f"{max_val:.3f}",
198
+ 'Point': f"({x}, {y})"
199
+ }
200
+
201
+ self.results.append(result)
202
+ self.marks.append((x, y, self.circle_diameter))
203
 
204
+ return self.update_display(), self.format_results()
205
+ except Exception as e:
206
+ print(f"Error analyzing ROI: {str(e)}")
207
+ return self.display_image, f"Error analyzing ROI: {str(e)}"
208
  def update_display(self):
209
  try:
210
  if self.original_display is None:
 
225
  for x, y, diameter in self.marks:
226
  zoomed_x = int(x * self.zoom_factor)
227
  zoomed_y = int(y * self.zoom_factor)
228
+ zoomed_radius = int((diameter/2) * self.zoom_factor)
229
 
230
  # Draw main circle
231
  cv2.circle(zoomed_bgr,