Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -20,31 +20,29 @@ def extract_frames(gif_path):
|
|
20 |
except Exception as e:
|
21 |
return None, f"Error loading GIF: {str(e)}"
|
22 |
|
23 |
-
def preprocess_frame(frame):
|
24 |
"""Preprocess a frame: isolate mid-to-light pixels and enhance circular patterns."""
|
25 |
# Apply Gaussian blur to reduce noise
|
26 |
blurred = cv2.GaussianBlur(frame, (9, 9), 0)
|
27 |
|
28 |
-
# Isolate mid-to-light pixels
|
29 |
-
lower_bound = 150
|
30 |
-
upper_bound = 255
|
31 |
mask = cv2.inRange(blurred, lower_bound, upper_bound)
|
32 |
|
33 |
# Apply morphological operation to enhance circular patterns
|
34 |
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
35 |
-
enhanced = cv2.dilate(mask, kernel, iterations=
|
36 |
|
37 |
return enhanced
|
38 |
|
39 |
-
def detect_circles(frame_diff, image_center, min_radius=20, max_radius=200):
|
40 |
"""Detect circles in a frame difference image, centered at the Sun."""
|
41 |
circles = cv2.HoughCircles(
|
42 |
frame_diff,
|
43 |
cv2.HOUGH_GRADIENT,
|
44 |
dp=1.5, # Resolution for better detection
|
45 |
minDist=100, # Prevent overlapping circles
|
46 |
-
param1=
|
47 |
-
param2=
|
48 |
minRadius=min_radius,
|
49 |
maxRadius=max_radius
|
50 |
)
|
@@ -53,7 +51,6 @@ def detect_circles(frame_diff, image_center, min_radius=20, max_radius=200):
|
|
53 |
circles = np.round(circles[0, :]).astype("int")
|
54 |
# Filter circles: only keep those centered near the image center
|
55 |
filtered_circles = []
|
56 |
-
center_tolerance = 30 # Allow 30-pixel deviation from the center
|
57 |
for (x, y, r) in circles:
|
58 |
if (abs(x - image_center[0]) < center_tolerance and
|
59 |
abs(y - image_center[1]) < center_tolerance):
|
@@ -61,7 +58,7 @@ def detect_circles(frame_diff, image_center, min_radius=20, max_radius=200):
|
|
61 |
return filtered_circles if filtered_circles else None
|
62 |
return None
|
63 |
|
64 |
-
def analyze_gif(gif_file):
|
65 |
"""Analyze a GIF for growing concentric circles of mid-to-light pixels."""
|
66 |
try:
|
67 |
# Handle Gradio file input
|
@@ -86,8 +83,8 @@ def analyze_gif(gif_file):
|
|
86 |
|
87 |
# Process frames and detect circles
|
88 |
for i in range(len(frames) - 1):
|
89 |
-
frame1 = preprocess_frame(frames[i])
|
90 |
-
frame2 = preprocess_frame(frames[i + 1])
|
91 |
|
92 |
# Compute absolute difference between consecutive frames
|
93 |
frame_diff = cv2.absdiff(frame2, frame1)
|
@@ -95,7 +92,7 @@ def analyze_gif(gif_file):
|
|
95 |
frame_diff = cv2.convertScaleAbs(frame_diff, alpha=3.0, beta=0)
|
96 |
|
97 |
# Detect circles centered at the Sun
|
98 |
-
circles = detect_circles(frame_diff, image_center, min_radius, max_radius)
|
99 |
|
100 |
if circles:
|
101 |
# Take the largest circle (most prominent CME feature)
|
@@ -120,7 +117,7 @@ def analyze_gif(gif_file):
|
|
120 |
|
121 |
# Generate output frames and report
|
122 |
results = []
|
123 |
-
report = "Analysis Report (as of 07:
|
124 |
if growing_circle_data:
|
125 |
report += f"Detected {len(growing_circle_data)} frames with growing concentric circles of mid-to-light pixels:\n"
|
126 |
for c in growing_circle_data:
|
@@ -140,16 +137,24 @@ def analyze_gif(gif_file):
|
|
140 |
except Exception as e:
|
141 |
return f"Error during analysis: {str(e)}", []
|
142 |
|
143 |
-
# Gradio interface
|
144 |
iface = gr.Interface(
|
145 |
fn=analyze_gif,
|
146 |
-
inputs=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
outputs=[
|
148 |
gr.Textbox(label="Analysis Report"),
|
149 |
gr.Gallery(label="Frames with Growing Circles")
|
150 |
],
|
151 |
title="Solar CME Detection",
|
152 |
-
description="Upload a GIF of solar images to detect growing concentric circles of mid-to-light pixels indicative of Earth-directed coronal mass ejections (CMEs)."
|
153 |
)
|
154 |
|
155 |
if __name__ == "__main__":
|
|
|
20 |
except Exception as e:
|
21 |
return None, f"Error loading GIF: {str(e)}"
|
22 |
|
23 |
+
def preprocess_frame(frame, lower_bound, upper_bound, morph_iterations):
|
24 |
"""Preprocess a frame: isolate mid-to-light pixels and enhance circular patterns."""
|
25 |
# Apply Gaussian blur to reduce noise
|
26 |
blurred = cv2.GaussianBlur(frame, (9, 9), 0)
|
27 |
|
28 |
+
# Isolate mid-to-light pixels using user-defined intensity range
|
|
|
|
|
29 |
mask = cv2.inRange(blurred, lower_bound, upper_bound)
|
30 |
|
31 |
# Apply morphological operation to enhance circular patterns
|
32 |
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
33 |
+
enhanced = cv2.dilate(mask, kernel, iterations=morph_iterations)
|
34 |
|
35 |
return enhanced
|
36 |
|
37 |
+
def detect_circles(frame_diff, image_center, center_tolerance, param1, param2, min_radius=20, max_radius=200):
|
38 |
"""Detect circles in a frame difference image, centered at the Sun."""
|
39 |
circles = cv2.HoughCircles(
|
40 |
frame_diff,
|
41 |
cv2.HOUGH_GRADIENT,
|
42 |
dp=1.5, # Resolution for better detection
|
43 |
minDist=100, # Prevent overlapping circles
|
44 |
+
param1=param1, # User-defined edge threshold
|
45 |
+
param2=param2, # User-defined accumulator threshold
|
46 |
minRadius=min_radius,
|
47 |
maxRadius=max_radius
|
48 |
)
|
|
|
51 |
circles = np.round(circles[0, :]).astype("int")
|
52 |
# Filter circles: only keep those centered near the image center
|
53 |
filtered_circles = []
|
|
|
54 |
for (x, y, r) in circles:
|
55 |
if (abs(x - image_center[0]) < center_tolerance and
|
56 |
abs(y - image_center[1]) < center_tolerance):
|
|
|
58 |
return filtered_circles if filtered_circles else None
|
59 |
return None
|
60 |
|
61 |
+
def analyze_gif(gif_file, lower_bound, upper_bound, param1, param2, center_tolerance, morph_iterations):
|
62 |
"""Analyze a GIF for growing concentric circles of mid-to-light pixels."""
|
63 |
try:
|
64 |
# Handle Gradio file input
|
|
|
83 |
|
84 |
# Process frames and detect circles
|
85 |
for i in range(len(frames) - 1):
|
86 |
+
frame1 = preprocess_frame(frames[i], lower_bound, upper_bound, morph_iterations)
|
87 |
+
frame2 = preprocess_frame(frames[i + 1], lower_bound, upper_bound, morph_iterations)
|
88 |
|
89 |
# Compute absolute difference between consecutive frames
|
90 |
frame_diff = cv2.absdiff(frame2, frame1)
|
|
|
92 |
frame_diff = cv2.convertScaleAbs(frame_diff, alpha=3.0, beta=0)
|
93 |
|
94 |
# Detect circles centered at the Sun
|
95 |
+
circles = detect_circles(frame_diff, image_center, center_tolerance, param1, param2, min_radius, max_radius)
|
96 |
|
97 |
if circles:
|
98 |
# Take the largest circle (most prominent CME feature)
|
|
|
117 |
|
118 |
# Generate output frames and report
|
119 |
results = []
|
120 |
+
report = "Analysis Report (as of 07:44 PM PDT, May 24, 2025):\n"
|
121 |
if growing_circle_data:
|
122 |
report += f"Detected {len(growing_circle_data)} frames with growing concentric circles of mid-to-light pixels:\n"
|
123 |
for c in growing_circle_data:
|
|
|
137 |
except Exception as e:
|
138 |
return f"Error during analysis: {str(e)}", []
|
139 |
|
140 |
+
# Gradio interface with user controls
|
141 |
iface = gr.Interface(
|
142 |
fn=analyze_gif,
|
143 |
+
inputs=[
|
144 |
+
gr.File(label="Upload Solar GIF", file_types=[".gif"]),
|
145 |
+
gr.Slider(minimum=0, maximum=255, value=100, step=1, label="Lower Intensity Bound (0-255)"),
|
146 |
+
gr.Slider(minimum=0, maximum=255, value=200, step=1, label="Upper Intensity Bound (0-255)"),
|
147 |
+
gr.Slider(minimum=10, maximum=200, value=80, step=1, label="Hough Param1 (Edge Threshold)"),
|
148 |
+
gr.Slider(minimum=1, maximum=50, value=15, step=1, label="Hough Param2 (Accumulator Threshold)"),
|
149 |
+
gr.Slider(minimum=10, maximum=100, value=30, step=1, label="Center Tolerance (Pixels)"),
|
150 |
+
gr.Slider(minimum=1, maximum=5, value=2, step=1, label="Morphological Dilation Iterations")
|
151 |
+
],
|
152 |
outputs=[
|
153 |
gr.Textbox(label="Analysis Report"),
|
154 |
gr.Gallery(label="Frames with Growing Circles")
|
155 |
],
|
156 |
title="Solar CME Detection",
|
157 |
+
description="Upload a GIF of solar images to detect growing concentric circles of mid-to-light pixels indicative of Earth-directed coronal mass ejections (CMEs). Adjust the sliders to fine-tune detection."
|
158 |
)
|
159 |
|
160 |
if __name__ == "__main__":
|