HeshamAI commited on
Commit
a7226bf
·
verified ·
1 Parent(s): 9847dc2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -81
app.py CHANGED
@@ -1,97 +1,102 @@
1
- import gradio as gr
2
- import pydicom
3
- import numpy as np
4
  import cv2
 
5
  import pandas as pd
 
 
 
6
 
7
- def load_dicom(file):
8
- """Load a DICOM file and extract pixel data with rescale slope and intercept applied."""
9
- dicom_data = pydicom.dcmread(file)
 
 
 
 
 
 
10
  image = dicom_data.pixel_array.astype(np.float32)
11
- rescale_slope = getattr(dicom_data, "RescaleSlope", 1)
12
- rescale_intercept = getattr(dicom_data, "RescaleIntercept", 0)
13
  image = (image * rescale_slope) + rescale_intercept
14
- pixel_spacing = getattr(dicom_data, "PixelSpacing", [1, 1])
15
- return image, pixel_spacing
 
 
 
 
 
 
 
 
16
 
17
- def analyze_dicom(file, circle_diameter):
18
- """
19
- Analyze the DICOM file:
20
- - Load image and pixel spacing
21
- - Display the image
22
- - Analyze a circular region of interest
23
- """
24
- try:
25
- # Load DICOM file
26
- image, pixel_spacing = load_dicom(file)
27
- pixel_size_mm = float(pixel_spacing[0]) # Assuming square pixels
28
-
29
- # Normalize image for display
30
- image_display = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
31
-
32
- # Convert to RGB for overlay purposes
33
- image_rgb = cv2.cvtColor(image_display, cv2.COLOR_GRAY2RGB)
34
 
35
- # Analyze center of the image as a circular ROI
36
- h, w = image.shape
37
- center_x, center_y = w // 2, h // 2
 
 
 
 
38
 
39
- # Create a circular mask
40
- mask = np.zeros_like(image, dtype=np.uint8)
41
- y_indices, x_indices = np.ogrid[:image.shape[0], :image.shape[1]]
42
- distance_from_center = np.sqrt((x_indices - center_x) ** 2 + (y_indices - center_y) ** 2)
43
- mask[distance_from_center <= circle_diameter / 2] = 1
44
 
45
- # Extract pixel values within the circle
46
- pixels = image[mask == 1]
 
 
 
 
 
47
 
48
- # Calculate metrics
49
- area_pixels = np.sum(mask)
50
- area_mm2 = area_pixels * (pixel_size_mm**2)
51
- mean = np.mean(pixels)
52
- stddev = np.std(pixels)
53
- min_val = np.min(pixels)
54
- max_val = np.max(pixels)
55
 
56
- # Save the result
57
- results = {
58
- "Area (mm²)": f"{area_mm2:.3f}",
59
- "Mean Intensity": f"{mean:.3f}",
60
- "Standard Deviation": f"{stddev:.3f}",
61
- "Minimum Intensity": f"{min_val:.3f}",
62
- "Maximum Intensity": f"{max_val:.3f}",
63
- }
64
 
65
- # Draw the circle on the image
66
- cv2.circle(image_rgb, (center_x, center_y), int(circle_diameter / 2), (0, 255, 0), 2)
67
-
68
- # Convert the image back to BGR for display
69
- annotated_image = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
70
 
71
- return annotated_image, pd.DataFrame([results]).to_csv(index=False)
72
- except Exception as e:
73
- return None, f"Error: {str(e)}"
 
 
 
 
 
 
 
 
 
74
 
75
- # Define the Gradio interface
76
- inputs = [
77
- gr.File(label="Upload DICOM File (.IMA or .dcm)", type="filepath"),
78
- gr.Number(label="Circle Diameter (in pixels)", value=50, precision=1),
79
- ]
80
 
81
- outputs = [
82
- gr.Image(label="Annotated DICOM Image"),
83
- gr.File(label="Analysis Results (CSV)"),
84
- ]
 
 
 
 
 
 
85
 
86
- # Launch the app
87
- gr.Interface(
88
- fn=analyze_dicom,
89
- inputs=inputs,
90
- outputs=outputs,
91
- title="DICOM Analyzer Tool",
92
- description=(
93
- "Upload a DICOM file and analyze a circular region of interest (ROI). "
94
- "The tool calculates metrics such as mean intensity, standard deviation, and area in mm²."
95
- ),
96
- theme="compact",
97
- ).launch()
 
 
 
 
1
  import cv2
2
+ import numpy as np
3
  import pandas as pd
4
+ import pydicom
5
+ import gradio as gr
6
+ import os
7
 
8
+ # Global variables to mimic the local functionality
9
+ results = []
10
+ image_display = None
11
+ circle_diameter = 9
12
+ zoom_factor = 1.0
13
+
14
+ # Function to load DICOM files
15
+ def load_dicom(file_path):
16
+ dicom_data = pydicom.dcmread(file_path)
17
  image = dicom_data.pixel_array.astype(np.float32)
18
+ rescale_slope = getattr(dicom_data, 'RescaleSlope', 1)
19
+ rescale_intercept = getattr(dicom_data, 'RescaleIntercept', 0)
20
  image = (image * rescale_slope) + rescale_intercept
21
+ pixel_spacing = dicom_data.PixelSpacing
22
+ return image, dicom_data, pixel_spacing
23
+
24
+ # Function to analyze ROI
25
+ def analyze_roi(image, pixel_spacing, x, y, circle_diameter):
26
+ mask = np.zeros_like(image, dtype=np.uint8)
27
+ y_indices, x_indices = np.ogrid[:image.shape[0], :image.shape[1]]
28
+ distance_from_center = np.sqrt((x_indices - x)**2 + (y_indices - y)**2)
29
+ mask[distance_from_center <= circle_diameter / 2] = 1
30
+ pixels = image[mask == 1]
31
 
32
+ # Calculate metrics
33
+ area_mm2 = np.sum(mask) * (float(pixel_spacing[0])**2)
34
+ mean = np.mean(pixels)
35
+ stddev = np.std(pixels)
36
+ min_val = np.min(pixels)
37
+ max_val = np.max(pixels)
 
 
 
 
 
 
 
 
 
 
 
38
 
39
+ return {
40
+ "Area (mm²)": f"{area_mm2:.3f}",
41
+ "Mean": f"{mean:.3f}",
42
+ "StdDev": f"{stddev:.3f}",
43
+ "Min": f"{min_val:.3f}",
44
+ "Max": f"{max_val:.3f}"
45
+ }
46
 
47
+ # Gradio callback function to simulate the local analyzer
48
+ def process_image(file, x, y, zoom, diameter):
49
+ global results, image_display, circle_diameter, zoom_factor
 
 
50
 
51
+ # Load the DICOM image
52
+ image, dicom_data, pixel_spacing = load_dicom(file.name)
53
+ image_display = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
54
+
55
+ # Adjust zoom and diameter
56
+ zoom_factor = float(zoom)
57
+ circle_diameter = int(diameter)
58
 
59
+ # Analyze the clicked point
60
+ x_original = int(float(x) / zoom_factor)
61
+ y_original = int(float(y) / zoom_factor)
62
+ analysis_result = analyze_roi(image, pixel_spacing, x_original, y_original, circle_diameter)
 
 
 
63
 
64
+ # Append to results
65
+ results.append(analysis_result)
66
+ return analysis_result
 
 
 
 
 
67
 
68
+ # Gradio app definition
69
+ def reset_results():
70
+ global results
71
+ results = []
72
+ return "Results cleared!"
73
 
74
+ with gr.Blocks() as app:
75
+ gr.Markdown("## DICOM Analyzer - Matches Local Features")
76
+
77
+ with gr.Row():
78
+ file_input = gr.File(label="Upload DICOM File", type="filepath")
79
+ x_input = gr.Number(label="X Coordinate (px)", value=50)
80
+ y_input = gr.Number(label="Y Coordinate (px)", value=50)
81
+ zoom_input = gr.Number(label="Zoom Factor", value=1.0)
82
+ diameter_input = gr.Number(label="Circle Diameter (px)", value=9)
83
+
84
+ output_text = gr.Textbox(label="Analysis Results")
85
+ clear_button = gr.Button("Clear Results")
86
 
87
+ with gr.Row():
88
+ analyze_button = gr.Button("Analyze")
89
+ reset_button = gr.Button("Reset")
 
 
90
 
91
+ analyze_button.click(
92
+ process_image,
93
+ inputs=[file_input, x_input, y_input, zoom_input, diameter_input],
94
+ outputs=output_text
95
+ )
96
+
97
+ reset_button.click(
98
+ reset_results,
99
+ outputs=output_text
100
+ )
101
 
102
+ app.launch()