File size: 5,066 Bytes
5a1c0ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import gradio as gr
import numpy as np
import cv2
from PIL import Image
import io
import matplotlib.pyplot as plt

def extract_frames(gif_path):
    """Extract frames from a GIF and return as a list of numpy arrays."""
    try:
        img = Image.open(gif_path)
        frames = []
        while True:
            frame = img.convert('L')  # Convert to grayscale
            frames.append(np.array(frame))
            try:
                img.seek(img.tell() + 1)
            except EOFError:
                break
        return frames
    except Exception as e:
        return None, f"Error loading GIF: {str(e)}"

def preprocess_frame(frame):
    """Preprocess a frame: apply Gaussian blur to reduce noise."""
    return cv2.GaussianBlur(frame, (5, 5), 0)

def detect_circles(frame_diff, min_radius=20, max_radius=200):
    """Detect circles in a frame difference image using Hough Circle Transform."""
    circles = cv2.HoughCircles(
        frame_diff,
        cv2.HOUGH_GRADIENT,
        dp=1.2,  # Inverse ratio of resolution
        minDist=50,  # Minimum distance between detected centers
        param1=50,  # Canny edge detector threshold
        param2=30,  # Accumulator threshold for circle detection
        minRadius=min_radius,
        maxRadius=max_radius
    )
    return circles

def analyze_gif(gif_file):
    """Analyze a GIF for growing concentric circles."""
    try:
        # Save uploaded GIF to temporary file
        with open("temp.gif", "wb") as f:
            f.write(gif_file.read())

        # Extract frames
        frames, error = extract_frames("temp.gif")
        if error:
            return error

        if len(frames) < 2:
            return "GIF must have at least 2 frames for analysis."

        # Initialize results
        results = []
        circle_data = []
        min_radius = 20
        max_radius = min(max(frames[0].shape) // 2, 200)  # Limit max radius based on image size

        # Process frames
        for i in range(len(frames) - 1):
            frame1 = preprocess_frame(frames[i])
            frame2 = preprocess_frame(frames[i + 1])

            # Compute absolute difference between consecutive frames
            frame_diff = cv2.absdiff(frame2, frame1)
            # Enhance contrast for lighter pixels
            frame_diff = cv2.convertScaleAbs(frame_diff, alpha=2.0, beta=0)

            # Detect circles in the difference image
            circles = detect_circles(frame_diff, min_radius, max_radius)

            if circles is not None:
                circles = np.round(circles[0, :]).astype("int")
                for (x, y, r) in circles:
                    circle_data.append({
                        "frame": i + 1,
                        "center": (x, y),
                        "radius": r
                    })

            # Optional: Save frame with detected circles for visualization
            output_frame = cv2.cvtColor(frames[i + 1], cv2.COLOR_GRAY2RGB)
            if circles is not None:
                for (x, y, r) in circles:
                    cv2.circle(output_frame, (x, y), r, (0, 255, 0), 2)
            # Convert to PIL Image for Gradio
            output_frame = Image.fromarray(output_frame)
            results.append(output_frame)

        # Analyze circle data for growth
        report = "Analysis Report:\n"
        if circle_data:
            radii = [c["radius"] for c in circle_data]
            centers = [c["center"] for c in circle_data]
            frames_with_circles = [c["frame"] for c in circle_data]

            # Check if radii are increasing over frames
            is_growing = all(radii[i] < radii[i + 1] for i in range(len(radii) - 1))
            center_consistent = all(
                abs(centers[i][0] - centers[0][0]) < 20 and
                abs(centers[i][1] - centers[0][1]) < 20
                for i in range(1, len(centers))
            )

            report += f"Detected {len(circle_data)} circles across frames.\n"
            for c in circle_data:
                report += f"Frame {c['frame']}: Center at {c['center']}, Radius {c['radius']} pixels\n"
            if is_growing and center_consistent:
                report += "\nConclusion: Growing concentric circles detected, indicative of a potential Earth-directed CME."
            else:
                report += "\nConclusion: Detected circles, but growth pattern or center consistency does not confirm a clear CME."
        else:
            report += "No concentric circles detected."

        return report, results
    except Exception as e:
        return f"Error during analysis: {str(e)}", []

# Gradio interface
iface = gr.Interface(
    fn=analyze_gif,
    inputs=gr.File(label="Upload Solar GIF"),
    outputs=[
        gr.Textbox(label="Analysis Report"),
        gr.Gallery(label="Frames with Detected Circles")
    ],
    title="Solar CME Detection",
    description="Upload a GIF of solar images to detect growing concentric circles indicative of Earth-directed coronal mass ejections (CMEs)."
)

if __name__ == "__main__":
    iface.launch()