HeshamAI commited on
Commit
b4356a9
·
verified ·
1 Parent(s): 1a153fd

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -281
app.py DELETED
@@ -1,281 +0,0 @@
1
- import gradio as gr
2
- import cv2
3
- import numpy as np
4
- import pandas as pd
5
- import pydicom
6
- import tempfile
7
- import os
8
-
9
- class DicomAnalyzer:
10
- def __init__(self):
11
- self.results = []
12
- self.circle_diameter = 9
13
- self.current_image1 = None
14
- self.image_display1 = None
15
- self.dicom_data1 = None
16
- self.marks1 = []
17
-
18
- def load_dicom(self, file):
19
- try:
20
- if file is None:
21
- return None, None, None
22
-
23
- dicom_data = pydicom.dcmread(file.name)
24
- image = dicom_data.pixel_array.astype(np.float32)
25
-
26
- # Apply rescale slope and intercept
27
- rescale_slope = getattr(dicom_data, 'RescaleSlope', 1)
28
- rescale_intercept = getattr(dicom_data, 'RescaleIntercept', 0)
29
- image = (image * rescale_slope) + rescale_intercept
30
-
31
- # Store original image for analysis
32
- original_image = image.copy()
33
-
34
- # Normalize for display
35
- image_display = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
36
-
37
- # Convert to BGR for visualization
38
- if len(image_display.shape) == 2:
39
- image_display = cv2.cvtColor(image_display, cv2.COLOR_GRAY2BGR)
40
-
41
- return original_image, image_display, dicom_data
42
- except Exception as e:
43
- print(f"Error loading DICOM file: {str(e)}")
44
- return None, None, None
45
-
46
- def analyze_point(self, image, dicom_data, x, y):
47
- try:
48
- # Create a circular mask
49
- mask = np.zeros_like(image, dtype=np.uint8)
50
- y_indices, x_indices = np.ogrid[:image.shape[0], :image.shape[1]]
51
- distance_from_center = np.sqrt((x_indices - x)**2 + (y_indices - y)**2)
52
- mask[distance_from_center <= self.circle_diameter / 2] = 1
53
-
54
- # Extract pixel values within the circle
55
- pixels = image[mask == 1]
56
-
57
- # Calculate metrics
58
- area_pixels = np.sum(mask)
59
- pixel_spacing = float(dicom_data.PixelSpacing[0])
60
- area_mm2 = area_pixels * (pixel_spacing**2)
61
- mean = np.mean(pixels)
62
- stddev = np.std(pixels)
63
- min_val = np.min(pixels)
64
- max_val = np.max(pixels)
65
-
66
- return {
67
- 'Area (mm²)': f"{area_mm2:.3f}",
68
- 'Mean': f"{mean:.3f}",
69
- 'StdDev': f"{stddev:.3f}",
70
- 'Min': f"{min_val:.3f}",
71
- 'Max': f"{max_val:.3f}"
72
- }
73
- except Exception as e:
74
- print(f"Error analyzing point: {str(e)}")
75
- return None
76
-
77
- def draw_circle(self, image, x, y):
78
- try:
79
- image_copy = image.copy()
80
-
81
- # Draw all previous marks
82
- for mark_x, mark_y in self.marks1:
83
- cv2.circle(image_copy,
84
- (int(mark_x), int(mark_y)),
85
- int(self.circle_diameter / 2),
86
- (255, 255, 0), 1, # Yellow outer ring (thin)
87
- lineType=cv2.LINE_AA)
88
- cv2.circle(image_copy,
89
- (int(mark_x), int(mark_y)),
90
- int(self.circle_diameter / 2) - 1,
91
- (255, 255, 255), 1, # White inner ring (thin)
92
- lineType=cv2.LINE_AA)
93
-
94
- # Draw the new mark
95
- cv2.circle(image_copy,
96
- (int(x), int(y)),
97
- int(self.circle_diameter / 2),
98
- (255, 255, 0), 1, # Yellow outer ring (thin)
99
- lineType=cv2.LINE_AA)
100
- cv2.circle(image_copy,
101
- (int(x), int(y)),
102
- int(self.circle_diameter / 2) - 1,
103
- (255, 255, 255), 1, # White inner ring (thin)
104
- lineType=cv2.LINE_AA)
105
-
106
- # Store the new mark
107
- self.marks1.append((x, y))
108
-
109
- return image_copy
110
- except Exception as e:
111
- print(f"Error drawing circle: {str(e)}")
112
- return image
113
-
114
- def process_image(self, file):
115
- image, image_display, dicom_data = self.load_dicom(file)
116
- self.current_image1 = image
117
- self.image_display1 = image_display
118
- self.dicom_data1 = dicom_data
119
- return image_display
120
-
121
- def handle_click(self, evt: gr.SelectData):
122
- if self.current_image1 is None:
123
- return self.image_display1, "Please load an image first"
124
-
125
- try:
126
- x, y = evt.index
127
- marked_image = self.draw_circle(self.image_display1, x, y)
128
- self.image_display1 = marked_image
129
-
130
- results = self.analyze_point(self.current_image1, self.dicom_data1, x, y)
131
- if results:
132
- results['Point'] = f"({x}, {y})"
133
- self.results.append(results)
134
-
135
- return self.image_display1, self.format_results()
136
- except Exception as e:
137
- print(f"Error in handle_click: {str(e)}")
138
- return self.image_display1, f"Error: {str(e)}"
139
-
140
- def format_results(self):
141
- if not self.results:
142
- return "No results yet"
143
- df = pd.DataFrame(self.results)
144
- return df.to_string()
145
-
146
- def clear_results(self):
147
- self.results = []
148
- self.marks1 = []
149
- if self.current_image1 is not None:
150
- self.image_display1 = cv2.cvtColor(
151
- cv2.normalize(self.current_image1, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8),
152
- cv2.COLOR_GRAY2BGR
153
- )
154
- return "Results cleared", self.image_display1
155
-
156
- def add_blank_row(self):
157
- self.results.append({
158
- 'Point': '',
159
- 'Area (mm²)': '',
160
- 'Mean': '',
161
- 'StdDev': '',
162
- 'Min': '',
163
- 'Max': ''
164
- })
165
- return self.format_results()
166
-
167
- def add_zero_row(self):
168
- self.results.append({
169
- 'Point': '0',
170
- 'Area (mm²)': '0',
171
- 'Mean': '0',
172
- 'StdDev': '0',
173
- 'Min': '0',
174
- 'Max': '0'
175
- })
176
- return self.format_results()
177
-
178
- def undo_last_action(self):
179
- if self.results:
180
- self.results.pop()
181
- if self.marks1:
182
- self.marks1.pop()
183
- return self.format_results()
184
-
185
- def update_circle_diameter(self, value):
186
- self.circle_diameter = value
187
- return f"Circle diameter set to {value}"
188
-
189
- def save_results(self):
190
- try:
191
- if not self.results:
192
- return None, "No results to save"
193
-
194
- df = pd.DataFrame(self.results)
195
-
196
- # Create temporary file
197
- temp_dir = tempfile.gettempdir()
198
- temp_file = os.path.join(temp_dir, "analysis_results.xlsx")
199
-
200
- # Save to Excel
201
- df.to_excel(temp_file, index=False, engine='openpyxl')
202
-
203
- return temp_file, "Results saved successfully. Click to download."
204
- except Exception as e:
205
- print(f"Error saving results: {str(e)}")
206
- return None, f"Error saving results: {str(e)}"
207
-
208
- def create_interface():
209
- analyzer = DicomAnalyzer()
210
-
211
- with gr.Blocks() as interface:
212
- gr.Markdown("# CT DICOM Image Analyzer")
213
-
214
- with gr.Row():
215
- with gr.Column():
216
- file1 = gr.File(label="Upload DICOM file")
217
- image1 = gr.Image(label="DICOM Image", interactive=True, type="numpy")
218
- file1.change(fn=analyzer.process_image, inputs=file1, outputs=image1)
219
-
220
- with gr.Row():
221
- circle_diameter = gr.Slider(
222
- minimum=1,
223
- maximum=20,
224
- value=9,
225
- step=1,
226
- label="Circle Diameter"
227
- )
228
-
229
- with gr.Row():
230
- clear_btn = gr.Button("Clear Results")
231
- blank_row_btn = gr.Button("Add Blank Row")
232
- zero_row_btn = gr.Button("Add '0' Row")
233
- undo_btn = gr.Button("Undo Last Action")
234
- save_btn = gr.Button("Save Results")
235
-
236
- results = gr.Textbox(label="Results", interactive=False)
237
- file_output = gr.File(label="Download Results")
238
- status = gr.Textbox(label="Status")
239
-
240
- # Connect events
241
- circle_diameter.change(
242
- fn=analyzer.update_circle_diameter,
243
- inputs=circle_diameter,
244
- outputs=status
245
- )
246
-
247
- image1.select(
248
- fn=analyzer.handle_click,
249
- outputs=[image1, results]
250
- )
251
-
252
- clear_btn.click(
253
- fn=analyzer.clear_results,
254
- outputs=[status, image1]
255
- )
256
-
257
- blank_row_btn.click(
258
- fn=analyzer.add_blank_row,
259
- outputs=results
260
- )
261
-
262
- zero_row_btn.click(
263
- fn=analyzer.add_zero_row,
264
- outputs=results
265
- )
266
-
267
- undo_btn.click(
268
- fn=analyzer.undo_last_action,
269
- outputs=results
270
- )
271
-
272
- save_btn.click(
273
- fn=analyzer.save_results,
274
- outputs=[file_output, status]
275
- )
276
-
277
- return interface
278
-
279
- if __name__ == "__main__":
280
- interface = create_interface()
281
- interface.launch()