tstone87 commited on
Commit
0707d05
·
verified ·
1 Parent(s): 0b2e66c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -138
app.py CHANGED
@@ -1,22 +1,21 @@
1
- import streamlit as st
2
  import cv2
3
- import PIL.Image
4
  from ultralytics import YOLO
5
  import tempfile
6
  import time
7
  import requests
8
  import numpy as np
9
- import streamlink
10
 
11
  # Page Config
12
- st.set_page_config(page_title="AI Fire Watch", page_icon="🌍", layout="wide")
13
 
14
- # Lighter Background CSS with Darker Text
15
  st.markdown(
16
  """
17
  <style>
18
  .stApp {
19
- background-color: #cdc0b0;
20
  color: #1a1a1a;
21
  }
22
  h1 {
@@ -24,7 +23,7 @@ st.markdown(
24
  }
25
  .stTabs > div > button {
26
  background-color: #e0e0e0;
27
- color: #333333; /* Darker tab text */
28
  font-weight: bold;
29
  }
30
  .stTabs > div > button:hover {
@@ -35,22 +34,12 @@ st.markdown(
35
  background-color: #ffffff;
36
  color: #333333;
37
  }
38
- .stButton > button {
39
- background-color: #e0e0e0;
40
- color: #1a1a1a;
41
- font-weight: bold;
42
- }
43
- .stButton > button:hover {
44
- background-color: #d0d0d0;
45
- color: #1a1a1a;
46
- }
47
- /* Fix container height to prevent scrolling */
48
  .main .block-container {
49
  max-height: 100vh;
50
  overflow-y: auto;
51
  }
52
  .stImage > img {
53
- max-height: 50vh; /* Limit image height */
54
  object-fit: contain;
55
  }
56
  </style>
@@ -59,11 +48,12 @@ st.markdown(
59
  )
60
 
61
  # Load Model
62
- model_path = 'https://huggingface.co/spaces/tstone87/ccr-colorado/resolve/main/best.pt'
63
  try:
64
  model = YOLO(model_path)
65
  except Exception as ex:
66
- st.error(f"Model loading failed: {ex}")
 
67
  st.stop()
68
 
69
  # Initialize Session State
@@ -71,77 +61,61 @@ if 'monitoring' not in st.session_state:
71
  st.session_state.monitoring = False
72
  if 'current_webcam_url' not in st.session_state:
73
  st.session_state.current_webcam_url = None
74
- if 'yt_monitoring' not in st.session_state:
75
- st.session_state.yt_monitoring = False
76
 
77
  # Header
78
- st.title("AI Fire Watch")
79
- st.markdown("Monitor fire and smoke in real-time with AI vision models.")
 
 
 
80
 
81
  # Tabs
82
- tabs = st.tabs(["Upload", "Webcam", "YouTube"])
83
 
84
- # Tab 1: Upload
85
  with tabs[0]:
86
- col1, col2 = st.columns([1, 1])
87
  with col1:
88
  st.markdown("**Add Your File**")
89
- st.write("Upload an image or video (max 200MB) to scan for fire or smoke.")
90
- uploaded_file = st.file_uploader("", type=["jpg", "jpeg", "png", "mp4"], label_visibility="collapsed")
91
  confidence = st.slider("Detection Threshold", 0.25, 1.0, 0.4, key="upload_conf")
 
92
  with col2:
93
  frame_placeholder = st.empty()
94
  status_placeholder = st.empty()
95
- if uploaded_file:
96
- try:
97
- # Log file details
98
- file_size_mb = uploaded_file.size / 1024 / 1024
99
- status_placeholder.write(f"File size: {file_size_mb:.2f} MB, Type: {uploaded_file.type}")
100
-
101
- if file_size_mb > 200:
102
- status_placeholder.error("File exceeds 200MB limit. Please use a smaller file.")
 
 
 
 
 
 
 
103
  else:
104
- file_type = uploaded_file.type.split('/')[0]
105
- status_placeholder.write(f"Processing {file_type} file...")
106
-
107
- if file_type == 'image':
108
- image = PIL.Image.open(uploaded_file)
109
- results = model.predict(image, conf=confidence)
110
- detected_frame = results[0].plot()[:, :, ::-1]
111
  frame_placeholder.image(detected_frame, use_column_width=True)
112
- status_placeholder.write(f"Objects detected: {len(results[0].boxes)}")
113
-
114
- elif file_type == 'video':
115
- # Save to temporary file
116
- tfile = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
117
- tfile.write(uploaded_file.read())
118
- tfile.close()
119
-
120
- # Process video
121
- cap = cv2.VideoCapture(tfile.name)
122
- if not cap.isOpened():
123
- status_placeholder.error("Failed to open video file. Check format or codec.")
124
- else:
125
- frame_count = 0
126
- while cap.isOpened():
127
- ret, frame = cap.read()
128
- if not ret:
129
- status_placeholder.write(f"Finished processing video. Processed {frame_count} frames.")
130
- break
131
- results = model.predict(frame, conf=confidence)
132
- detected_frame = results[0].plot()[:, :, ::-1]
133
- frame_placeholder.image(detected_frame, use_column_width=True)
134
- status_placeholder.write(f"Frame {frame_count}: Objects detected: {len(results[0].boxes)}")
135
- frame_count += 1
136
- time.sleep(0.05)
137
- cap.release()
138
- # Clean up
139
- import os
140
- os.unlink(tfile.name)
141
- except Exception as e:
142
- status_placeholder.error(f"Error processing file: {str(e)}")
143
 
144
- # Tab 2: Webcam
145
  with tabs[1]:
146
  col1, col2 = st.columns([1, 1])
147
  with col1:
@@ -166,22 +140,24 @@ with tabs[1]:
166
  timer_placeholder = st.empty()
167
 
168
  if st.session_state.monitoring and st.session_state.current_webcam_url:
169
- # Try as video stream first
170
  cap = cv2.VideoCapture(webcam_url)
171
  is_video_stream = cap.isOpened()
172
 
173
  if is_video_stream:
174
  status_placeholder.write("Connected to video stream...")
175
- while st.session_state.monitoring:
176
  try:
177
  ret, frame = cap.read()
178
  if not ret:
179
  status_placeholder.error("Video stream interrupted.")
180
  break
181
- results = model.predict(frame, conf=confidence)
182
- detected_frame = results[0].plot()[:, :, ::-1]
 
 
 
183
  frame_placeholder.image(detected_frame, use_column_width=True)
184
- status_placeholder.write(f"Objects detected: {len(results[0].boxes)}")
185
  time.sleep(0.1) # Fast update for video
186
  except Exception as e:
187
  status_placeholder.error(f"Video error: {e}")
@@ -189,11 +165,13 @@ with tabs[1]:
189
  break
190
  cap.release()
191
  else:
192
- # Image-based webcam
193
  status_placeholder.write("Monitoring image-based webcam...")
194
  while st.session_state.monitoring:
195
  try:
196
  start_time = time.time()
 
 
 
197
  response = requests.get(webcam_url, timeout=5)
198
  if response.status_code != 200:
199
  status_placeholder.error(f"Fetch failed: HTTP {response.status_code}")
@@ -204,71 +182,22 @@ with tabs[1]:
204
  status_placeholder.error("Image decoding failed.")
205
  break
206
 
207
- results = model.predict(frame, conf=confidence)
208
- detected_frame = results[0].plot()[:, :, ::-1]
209
  frame_placeholder.image(detected_frame, use_column_width=True)
210
- status_placeholder.write(f"Objects detected: {len(results[0].boxes)}")
211
 
212
- # Proper refresh timing for images
213
  elapsed = time.time() - start_time
214
  remaining = max(0, refresh_rate - elapsed)
215
  for i in range(int(remaining), -1, -1):
216
- if not st.session_state.monitoring:
 
217
  break
218
  timer_placeholder.write(f"Next scan: {i}s")
219
  time.sleep(1)
220
-
221
  except Exception as e:
222
  status_placeholder.error(f"Image fetch error: {e}")
223
  st.session_state.monitoring = False
224
  break
225
- if not st.session_state.monitoring:
226
- timer_placeholder.write("Monitoring stopped.")
227
-
228
- # Tab 3: YouTube
229
- with tabs[2]:
230
- col1, col2 = st.columns([1, 1])
231
- with col1:
232
- st.markdown("**YouTube Live**")
233
- st.write("Enter a live YouTube URL to auto-analyze the stream.")
234
- youtube_url = st.text_input("YouTube URL", "https://www.youtube.com/watch?v=<id>", label_visibility="collapsed")
235
- confidence = st.slider("Detection Threshold", 0.25, 1.0, 0.4, key="yt_conf")
236
- start_yt = st.button("Start Analysis", key="yt_start")
237
- stop_yt = st.button("Stop Analysis", key="yt_stop")
238
-
239
- if start_yt:
240
- st.session_state.yt_monitoring = True
241
- if stop_yt:
242
- st.session_state.yt_monitoring = False
243
-
244
- with col2:
245
- frame_placeholder = st.empty()
246
- status_placeholder = st.empty()
247
-
248
- if st.session_state.yt_monitoring and youtube_url and youtube_url != "https://www.youtube.com/watch?v=<id>":
249
- try:
250
- status_placeholder.write("Initializing stream...")
251
- streams = streamlink.streams(youtube_url)
252
- if not streams:
253
- status_placeholder.error("No streams found. Check if the URL is a live stream.")
254
- else:
255
- stream_url = streams["best"].url
256
- cap = cv2.VideoCapture(stream_url)
257
- if not cap.isOpened():
258
- status_placeholder.error("Unable to open stream.")
259
- else:
260
- status_placeholder.write("Analyzing live stream...")
261
- while st.session_state.yt_monitoring and cap.isOpened():
262
- ret, frame = cap.read()
263
- if not ret:
264
- status_placeholder.error("Stream interrupted.")
265
- break
266
- results = model.predict(frame, conf=confidence)
267
- detected_frame = results[0].plot()[:, :, ::-1]
268
- frame_placeholder.image(detected_frame, use_column_width=True)
269
- status_placeholder.write(f"Objects detected: {len(results[0].boxes)}")
270
- time.sleep(0.1)
271
- cap.release()
272
- except Exception as e:
273
- status_placeholder.error(f"Error: {e}")
274
- st.session_state.yt_monitoring = False
 
1
+ import PIL
2
  import cv2
3
+ import streamlit as st
4
  from ultralytics import YOLO
5
  import tempfile
6
  import time
7
  import requests
8
  import numpy as np
 
9
 
10
  # Page Config
11
+ st.set_page_config(page_title="WildfireWatch", page_icon="🔥", layout="wide")
12
 
13
+ # CSS for layout stability and dark tab text
14
  st.markdown(
15
  """
16
  <style>
17
  .stApp {
18
+ background-color: #f5f5f5;
19
  color: #1a1a1a;
20
  }
21
  h1 {
 
23
  }
24
  .stTabs > div > button {
25
  background-color: #e0e0e0;
26
+ color: #333333;
27
  font-weight: bold;
28
  }
29
  .stTabs > div > button:hover {
 
34
  background-color: #ffffff;
35
  color: #333333;
36
  }
 
 
 
 
 
 
 
 
 
 
37
  .main .block-container {
38
  max-height: 100vh;
39
  overflow-y: auto;
40
  }
41
  .stImage > img {
42
+ max-height: 50vh;
43
  object-fit: contain;
44
  }
45
  </style>
 
48
  )
49
 
50
  # Load Model
51
+ model_path = 'https://huggingface.co/spaces/tstone87/ccr-colorado/resolve/main/best.pt' # Your updated model
52
  try:
53
  model = YOLO(model_path)
54
  except Exception as ex:
55
+ st.error(f"Unable to load model. Check the specified path: {model_path}")
56
+ st.error(ex)
57
  st.stop()
58
 
59
  # Initialize Session State
 
61
  st.session_state.monitoring = False
62
  if 'current_webcam_url' not in st.session_state:
63
  st.session_state.current_webcam_url = None
 
 
64
 
65
  # Header
66
+ st.title("WildfireWatch: Detecting Wildfire using AI")
67
+ st.markdown("""
68
+ Wildfires are a major environmental issue, causing substantial losses to ecosystems, human livelihoods, and potentially leading to loss of life. Early detection of wildfires can prevent these losses. Our application uses state-of-the-art YOLOv8 model for real-time wildfire and smoke detection.
69
+ """)
70
+ st.markdown("---")
71
 
72
  # Tabs
73
+ tabs = st.tabs(["Upload", "Webcam"])
74
 
75
+ # Tab 1: Upload (Your original working version)
76
  with tabs[0]:
77
+ col1, col2 = st.columns(2)
78
  with col1:
79
  st.markdown("**Add Your File**")
80
+ st.write("Upload an image or video to scan for fire or smoke.")
81
+ source_file = st.file_uploader("", type=["jpg", "jpeg", "png", "mp4"], label_visibility="collapsed")
82
  confidence = st.slider("Detection Threshold", 0.25, 1.0, 0.4, key="upload_conf")
83
+
84
  with col2:
85
  frame_placeholder = st.empty()
86
  status_placeholder = st.empty()
87
+ if source_file and st.button("Detect Wildfire", key="upload_detect"):
88
+ file_type = source_file.type.split('/')[0]
89
+ if file_type == 'image':
90
+ uploaded_image = PIL.Image.open(source_file)
91
+ res = model.predict(uploaded_image, conf=confidence)
92
+ detected_image = res[0].plot()[:, :, ::-1]
93
+ frame_placeholder.image(detected_image, use_column_width=True)
94
+ status_placeholder.write(f"Objects detected: {len(res[0].boxes)}")
95
+ elif file_type == 'video':
96
+ tfile = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
97
+ tfile.write(source_file.read())
98
+ tfile.close()
99
+ vidcap = cv2.VideoCapture(tfile.name)
100
+ if not vidcap.isOpened():
101
+ status_placeholder.error("Failed to open video file.")
102
  else:
103
+ success, frame = vidcap.read()
104
+ frame_count = 0
105
+ while success:
106
+ res = model.predict(frame, conf=confidence)
107
+ detected_frame = res[0].plot()[:, :, ::-1]
 
 
108
  frame_placeholder.image(detected_frame, use_column_width=True)
109
+ status_placeholder.write(f"Frame {frame_count}: Objects detected: {len(res[0].boxes)}")
110
+ success, frame = vidcap.read()
111
+ frame_count += 1
112
+ time.sleep(0.05)
113
+ vidcap.release()
114
+ import os
115
+ os.unlink(tfile.name)
116
+ status_placeholder.write(f"Video processing complete. Processed {frame_count} frames.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
+ # Tab 2: Webcam (Enhanced with video and image support)
119
  with tabs[1]:
120
  col1, col2 = st.columns([1, 1])
121
  with col1:
 
140
  timer_placeholder = st.empty()
141
 
142
  if st.session_state.monitoring and st.session_state.current_webcam_url:
 
143
  cap = cv2.VideoCapture(webcam_url)
144
  is_video_stream = cap.isOpened()
145
 
146
  if is_video_stream:
147
  status_placeholder.write("Connected to video stream...")
148
+ while st.session_state.monitoring and cap.isOpened():
149
  try:
150
  ret, frame = cap.read()
151
  if not ret:
152
  status_placeholder.error("Video stream interrupted.")
153
  break
154
+ if webcam_url != st.session_state.current_webcam_url:
155
+ status_placeholder.write("URL changed. Stopping video monitoring.")
156
+ break
157
+ res = model.predict(frame, conf=confidence)
158
+ detected_frame = res[0].plot()[:, :, ::-1]
159
  frame_placeholder.image(detected_frame, use_column_width=True)
160
+ status_placeholder.write(f"Objects detected: {len(res[0].boxes)}")
161
  time.sleep(0.1) # Fast update for video
162
  except Exception as e:
163
  status_placeholder.error(f"Video error: {e}")
 
165
  break
166
  cap.release()
167
  else:
 
168
  status_placeholder.write("Monitoring image-based webcam...")
169
  while st.session_state.monitoring:
170
  try:
171
  start_time = time.time()
172
+ if webcam_url != st.session_state.current_webcam_url:
173
+ status_placeholder.write("URL changed. Stopping image monitoring.")
174
+ break
175
  response = requests.get(webcam_url, timeout=5)
176
  if response.status_code != 200:
177
  status_placeholder.error(f"Fetch failed: HTTP {response.status_code}")
 
182
  status_placeholder.error("Image decoding failed.")
183
  break
184
 
185
+ res = model.predict(frame, conf=confidence)
186
+ detected_frame = res[0].plot()[:, :, ::-1]
187
  frame_placeholder.image(detected_frame, use_column_width=True)
188
+ status_placeholder.write(f"Objects detected: {len(res[0].boxes)}")
189
 
 
190
  elapsed = time.time() - start_time
191
  remaining = max(0, refresh_rate - elapsed)
192
  for i in range(int(remaining), -1, -1):
193
+ if not st.session_state.monitoring or webcam_url != st.session_state.current_webcam_url:
194
+ status_placeholder.write("Monitoring interrupted or URL changed.")
195
  break
196
  timer_placeholder.write(f"Next scan: {i}s")
197
  time.sleep(1)
 
198
  except Exception as e:
199
  status_placeholder.error(f"Image fetch error: {e}")
200
  st.session_state.monitoring = False
201
  break
202
+ if not st.session_state.monitoring:
203
+ timer_placeholder.write("Monitoring stopped.")