broadfield-dev commited on
Commit
5a1c0ee
·
verified ·
1 Parent(s): de961c3

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -0
app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ from PIL import Image
5
+ import io
6
+ import matplotlib.pyplot as plt
7
+
8
+ def extract_frames(gif_path):
9
+ """Extract frames from a GIF and return as a list of numpy arrays."""
10
+ try:
11
+ img = Image.open(gif_path)
12
+ frames = []
13
+ while True:
14
+ frame = img.convert('L') # Convert to grayscale
15
+ frames.append(np.array(frame))
16
+ try:
17
+ img.seek(img.tell() + 1)
18
+ except EOFError:
19
+ break
20
+ return frames
21
+ except Exception as e:
22
+ return None, f"Error loading GIF: {str(e)}"
23
+
24
+ def preprocess_frame(frame):
25
+ """Preprocess a frame: apply Gaussian blur to reduce noise."""
26
+ return cv2.GaussianBlur(frame, (5, 5), 0)
27
+
28
+ def detect_circles(frame_diff, min_radius=20, max_radius=200):
29
+ """Detect circles in a frame difference image using Hough Circle Transform."""
30
+ circles = cv2.HoughCircles(
31
+ frame_diff,
32
+ cv2.HOUGH_GRADIENT,
33
+ dp=1.2, # Inverse ratio of resolution
34
+ minDist=50, # Minimum distance between detected centers
35
+ param1=50, # Canny edge detector threshold
36
+ param2=30, # Accumulator threshold for circle detection
37
+ minRadius=min_radius,
38
+ maxRadius=max_radius
39
+ )
40
+ return circles
41
+
42
+ def analyze_gif(gif_file):
43
+ """Analyze a GIF for growing concentric circles."""
44
+ try:
45
+ # Save uploaded GIF to temporary file
46
+ with open("temp.gif", "wb") as f:
47
+ f.write(gif_file.read())
48
+
49
+ # Extract frames
50
+ frames, error = extract_frames("temp.gif")
51
+ if error:
52
+ return error
53
+
54
+ if len(frames) < 2:
55
+ return "GIF must have at least 2 frames for analysis."
56
+
57
+ # Initialize results
58
+ results = []
59
+ circle_data = []
60
+ min_radius = 20
61
+ max_radius = min(max(frames[0].shape) // 2, 200) # Limit max radius based on image size
62
+
63
+ # Process frames
64
+ for i in range(len(frames) - 1):
65
+ frame1 = preprocess_frame(frames[i])
66
+ frame2 = preprocess_frame(frames[i + 1])
67
+
68
+ # Compute absolute difference between consecutive frames
69
+ frame_diff = cv2.absdiff(frame2, frame1)
70
+ # Enhance contrast for lighter pixels
71
+ frame_diff = cv2.convertScaleAbs(frame_diff, alpha=2.0, beta=0)
72
+
73
+ # Detect circles in the difference image
74
+ circles = detect_circles(frame_diff, min_radius, max_radius)
75
+
76
+ if circles is not None:
77
+ circles = np.round(circles[0, :]).astype("int")
78
+ for (x, y, r) in circles:
79
+ circle_data.append({
80
+ "frame": i + 1,
81
+ "center": (x, y),
82
+ "radius": r
83
+ })
84
+
85
+ # Optional: Save frame with detected circles for visualization
86
+ output_frame = cv2.cvtColor(frames[i + 1], cv2.COLOR_GRAY2RGB)
87
+ if circles is not None:
88
+ for (x, y, r) in circles:
89
+ cv2.circle(output_frame, (x, y), r, (0, 255, 0), 2)
90
+ # Convert to PIL Image for Gradio
91
+ output_frame = Image.fromarray(output_frame)
92
+ results.append(output_frame)
93
+
94
+ # Analyze circle data for growth
95
+ report = "Analysis Report:\n"
96
+ if circle_data:
97
+ radii = [c["radius"] for c in circle_data]
98
+ centers = [c["center"] for c in circle_data]
99
+ frames_with_circles = [c["frame"] for c in circle_data]
100
+
101
+ # Check if radii are increasing over frames
102
+ is_growing = all(radii[i] < radii[i + 1] for i in range(len(radii) - 1))
103
+ center_consistent = all(
104
+ abs(centers[i][0] - centers[0][0]) < 20 and
105
+ abs(centers[i][1] - centers[0][1]) < 20
106
+ for i in range(1, len(centers))
107
+ )
108
+
109
+ report += f"Detected {len(circle_data)} circles across frames.\n"
110
+ for c in circle_data:
111
+ report += f"Frame {c['frame']}: Center at {c['center']}, Radius {c['radius']} pixels\n"
112
+ if is_growing and center_consistent:
113
+ report += "\nConclusion: Growing concentric circles detected, indicative of a potential Earth-directed CME."
114
+ else:
115
+ report += "\nConclusion: Detected circles, but growth pattern or center consistency does not confirm a clear CME."
116
+ else:
117
+ report += "No concentric circles detected."
118
+
119
+ return report, results
120
+ except Exception as e:
121
+ return f"Error during analysis: {str(e)}", []
122
+
123
+ # Gradio interface
124
+ iface = gr.Interface(
125
+ fn=analyze_gif,
126
+ inputs=gr.File(label="Upload Solar GIF"),
127
+ outputs=[
128
+ gr.Textbox(label="Analysis Report"),
129
+ gr.Gallery(label="Frames with Detected Circles")
130
+ ],
131
+ title="Solar CME Detection",
132
+ description="Upload a GIF of solar images to detect growing concentric circles indicative of Earth-directed coronal mass ejections (CMEs)."
133
+ )
134
+
135
+ if __name__ == "__main__":
136
+ iface.launch()