tstone87 commited on
Commit
033d048
·
verified ·
1 Parent(s): 12b472d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -176
app.py CHANGED
@@ -1,207 +1,179 @@
1
  import os
2
  import tempfile
3
  import base64
 
4
  import cv2
5
  import streamlit as st
6
- import PIL
7
  import requests
8
- import imageio
9
  from ultralytics import YOLO
10
  from huggingface_hub import hf_hub_download
 
 
11
 
12
- # Move set_page_config to the very top as it must be the first Streamlit command
13
  st.set_page_config(
14
- page_title="Fire Detection: Original vs. Processed Video",
15
  page_icon="🔥",
16
  layout="wide",
17
  initial_sidebar_state="expanded"
18
  )
19
 
20
- ###############################################################################
21
- # Helper: Embed an HTML5 video that autoplays (muted) with controls.
22
- ###############################################################################
23
- def show_autoplay_video(video_bytes: bytes, title: str = "Video"):
24
  if not video_bytes:
25
  st.warning(f"No {title} video available.")
26
  return
27
  video_base64 = base64.b64encode(video_bytes).decode()
 
28
  video_html = f"""
29
  <h4>{title}</h4>
30
- <video width="100%" controls autoplay muted>
31
  <source src="data:video/mp4;base64,{video_base64}" type="video/mp4">
32
  Your browser does not support the video tag.
33
  </video>
34
  """
35
  st.markdown(video_html, unsafe_allow_html=True)
36
 
37
- ###############################################################################
38
- # Session state initialization (for processed results)
39
- ###############################################################################
40
- if "processed_frames" not in st.session_state:
41
- st.session_state["processed_frames"] = []
42
- if "shortened_video_data" not in st.session_state:
43
- st.session_state["shortened_video_data"] = None
44
- if "shortened_video_ready" not in st.session_state:
45
- st.session_state["shortened_video_ready"] = False
46
-
47
- ###############################################################################
48
- # Download YOLO Model from Hugging Face
49
- ###############################################################################
50
- repo_id = "tstone87/ccr-colorado" # Verify this is correct
51
- model_filename = "best.pt"
52
-
53
- try:
54
- # Add error handling for repository access
55
- local_model_path = hf_hub_download(
56
- repo_id=repo_id,
57
- filename=model_filename,
58
- repo_type="model" # Explicitly specify repo_type
59
- )
60
- model = YOLO(local_model_path)
61
- except Exception as ex:
62
- st.error(f"Unable to load model. Error details: {str(ex)}")
63
- st.error("Please verify:")
64
- st.error("1. Repository 'tstone87/ccr-colorado' exists and is accessible")
65
- st.error("2. 'best.pt' file is uploaded to the repository")
66
- st.error("3. You have proper access permissions")
67
- model = None # Set model to None if loading fails
68
-
69
- ###############################################################################
70
- # SIDEBAR: Video input options
71
- ###############################################################################
72
  with st.sidebar:
73
- st.header("Video Input Options")
74
- example_option = st.selectbox(
75
- "Select Example Pair (optional)",
76
- ["None", "T Example", "LA Example"]
77
- )
78
- source_file = st.file_uploader(
79
- "Or upload your own file...",
80
- type=("mp4", "jpg", "jpeg", "png", "bmp", "webp")
81
- )
82
- confidence = float(st.slider("Select Model Confidence", 25, 100, 40)) / 100
83
- video_option = st.selectbox(
84
- "Select Video Shortening Option",
85
- ["Original FPS", "1 fps", "1 frame per 5 seconds", "1 frame per 10 seconds", "1 frame per 15 seconds"]
86
- )
87
- progress_text = st.empty()
88
- progress_bar = st.progress(0)
89
- download_placeholder = st.empty()
90
-
91
- ###############################################################################
92
- # MAIN TITLE
93
- ###############################################################################
94
- st.title("Fire Detection: Original vs. Processed Video")
95
-
96
- ###############################################################################
97
- # Load Example Video Data
98
- ###############################################################################
99
- original_video_data = None
100
- processed_video_data = None
101
-
102
- if example_option != "None":
103
- example_videos = {
104
- "T Example": ("T1.mp4", "T2.mpg"),
105
- "LA Example": ("LA1.mp4", "LA2.mp4")
106
  }
107
- orig_filename, proc_filename = example_videos.get(example_option, (None, None))
108
-
109
- if orig_filename and proc_filename:
110
- try:
111
- orig_url = f"https://huggingface.co/spaces/tstone87/ccr-colorado/resolve/main/{orig_filename}"
112
- proc_url = f"https://huggingface.co/spaces/tstone87/ccr-colorado/resolve/main/{proc_filename}"
113
- original_video_data = requests.get(orig_url).content
114
- processed_video_data = requests.get(proc_url).content
115
- except Exception as ex:
116
- st.error(f"Error loading example videos: {str(ex)}")
117
- else:
118
- if source_file:
119
- file_type = source_file.type.split('/')[0]
120
- if file_type == 'image':
121
- original_image = PIL.Image.open(source_file)
122
- buf = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
123
- original_image.save(buf.name, format="PNG")
124
- with open(buf.name, "rb") as f:
125
- original_video_data = f.read()
126
- else:
127
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tfile:
128
- tfile.write(source_file.read())
129
- original_video_data = tfile.name
130
-
131
- ###############################################################################
132
- # Layout: Two Columns for Original and Processed Videos
133
- ###############################################################################
134
- col1, col2 = st.columns(2)
135
-
136
- with col1:
137
- st.subheader("Original File")
138
- if original_video_data:
139
- show_autoplay_video(original_video_data, title="Original Video")
140
- else:
141
- st.info("No original video available.")
142
-
143
- with col2:
144
- st.subheader("Result File")
145
- viewer_slot = st.empty()
146
- if example_option != "None":
147
- if processed_video_data:
148
- show_autoplay_video(processed_video_data, title="Processed Video")
149
- else:
150
- st.info("No processed video available in example.")
151
- else:
152
- viewer_slot.info("Processed video will appear here once detection is run.")
153
-
154
- ###############################################################################
155
- # Process Video if No Example is Selected
156
- ###############################################################################
157
- if example_option == "None" and source_file and source_file.type.split('/')[0] != 'image':
158
- if st.sidebar.button("Let's Detect Wildfire") and model is not None:
159
- st.session_state["processed_frames"] = []
160
- processed_frames = st.session_state["processed_frames"]
161
-
162
- vid_reader = imageio.get_reader(original_video_data)
163
- fps = vid_reader.get_meta_data()['fps']
164
- width, height = vid_reader.get_meta_data()['size']
165
-
166
- frame_count = 0
167
- total_frames = vid_reader.get_length()
168
-
169
- for frame in vid_reader:
170
- res = model.predict(frame, conf=confidence)
171
- res_plotted = res[0].plot()[:, :, ::-1]
172
- processed_frames.append(res_plotted)
173
-
174
- progress_pct = int((frame_count / total_frames) * 100)
175
- progress_text.text(f"Processing frame {frame_count} / {total_frames} ({progress_pct}%)")
176
- progress_bar.progress(min(100, progress_pct))
177
- frame_count += 1
178
-
179
- progress_text.text("Video processing complete!")
180
- progress_bar.progress(100)
181
-
182
- if processed_frames:
183
- temp_video_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
184
- fourcc = cv2.VideoWriter_fourcc(*'mp4v')
185
- out = cv2.VideoWriter(temp_video_file.name, fourcc, fps, (width, height))
186
-
187
- for frame in processed_frames:
188
- out.write(frame)
189
- out.release()
190
-
191
- with open(temp_video_file.name, 'rb') as video_file:
192
- st.session_state["shortened_video_data"] = video_file.read()
193
- st.session_state["shortened_video_ready"] = True
194
-
195
- st.success("Processed video created successfully!")
196
- show_autoplay_video(st.session_state["shortened_video_data"], title="Processed Video")
197
-
198
- ###############################################################################
199
- # Show Download Button if Ready
200
- ###############################################################################
201
- if st.session_state["shortened_video_ready"]:
202
- download_placeholder.download_button(
 
 
 
 
 
 
203
  label="Download Processed Video",
204
- data=st.session_state["shortened_video_data"],
205
- file_name="processed_video.mp4",
206
  mime="video/mp4"
207
- )
 
 
 
 
1
  import os
2
  import tempfile
3
  import base64
4
+ import time
5
  import cv2
6
  import streamlit as st
 
7
  import requests
 
8
  from ultralytics import YOLO
9
  from huggingface_hub import hf_hub_download
10
+ import imageio
11
+ import numpy as np
12
 
13
+ # Page config must be first
14
  st.set_page_config(
15
+ page_title="Wildfire Detection Demo",
16
  page_icon="🔥",
17
  layout="wide",
18
  initial_sidebar_state="expanded"
19
  )
20
 
21
+ # Helper function to display videos
22
+ def show_video(video_bytes: bytes, title: str, loop=True):
 
 
23
  if not video_bytes:
24
  st.warning(f"No {title} video available.")
25
  return
26
  video_base64 = base64.b64encode(video_bytes).decode()
27
+ loop_attr = "loop" if loop else ""
28
  video_html = f"""
29
  <h4>{title}</h4>
30
+ <video width="100%" controls autoplay muted {loop_attr}>
31
  <source src="data:video/mp4;base64,{video_base64}" type="video/mp4">
32
  Your browser does not support the video tag.
33
  </video>
34
  """
35
  st.markdown(video_html, unsafe_allow_html=True)
36
 
37
+ # Initialize session state
38
+ for key in ["processed_video", "processing_complete", "start_time", "progress"]:
39
+ if key not in st.session_state:
40
+ st.session_state[key] = None if key in ["processed_video", "start_time"] else False if key == "processing_complete" else 0
41
+
42
+ # Load model
43
+ @st.cache_resource
44
+ def load_model():
45
+ repo_id = "tstone87/ccr-colorado"
46
+ filename = "best.pt"
47
+ try:
48
+ model_path = hf_hub_download(repo_id=repo_id, filename=filename, repo_type="model")
49
+ return YOLO(model_path)
50
+ except Exception as e:
51
+ st.error(f"Failed to load model: {str(e)}")
52
+ return None
53
+
54
+ model = load_model()
55
+
56
+ # Sidebar
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  with st.sidebar:
58
+ st.header("Process Your Own Video")
59
+ uploaded_file = st.file_uploader("Upload a video", type=["mp4"])
60
+ confidence = st.slider("Detection Confidence", 0.25, 1.0, 0.4)
61
+ fps_options = {
62
+ "Original FPS": None,
63
+ "3 FPS": 3,
64
+ "1 FPS": 1,
65
+ "1 frame/4s": 0.25,
66
+ "1 frame/10s": 0.1,
67
+ "1 frame/15s": 0.0667,
68
+ "1 frame/30s": 0.0333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  }
70
+ selected_fps = st.selectbox("Output FPS", list(fps_options.keys()), index=0)
71
+ process_button = st.button("Process Video")
72
+ progress_bar = st.progress(0)
73
+ progress_text = st.empty()
74
+ download_slot = st.empty()
75
+
76
+ # Main content
77
+ st.title("Wildfire Detection Demo")
78
+ st.markdown("Watch our example videos below or upload your own in the sidebar!")
79
+
80
+ # Example videos
81
+ example_videos = {
82
+ "T Example": ("T1.mp4", "T2.mpg"),
83
+ "LA Example": ("LA1.mp4", "LA2.mp4")
84
+ }
85
+
86
+ for example_name in example_videos:
87
+ col1, col2 = st.columns(2)
88
+ orig_file, proc_file = example_videos[example_name]
89
+ try:
90
+ orig_url = f"https://huggingface.co/spaces/tstone87/ccr-colorado/resolve/main/{orig_file}"
91
+ proc_url = f"https://huggingface.co/spaces/tstone87/ccr-colorado/resolve/main/{proc_file}"
92
+ orig_data = requests.get(orig_url).content
93
+ proc_data = requests.get(proc_url).content
94
+
95
+ with col1:
96
+ show_video(orig_data, f"{example_name} - Original", loop=True)
97
+ with col2:
98
+ show_video(proc_data, f"{example_name} - Processed", loop=True)
99
+ except Exception as e:
100
+ st.error(f"Failed to load {example_name}: {str(e)}")
101
+
102
+ # Video processing
103
+ def process_video(video_file, target_fps, confidence):
104
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
105
+ tmp.write(video_file.read())
106
+ tmp_path = tmp.name
107
+
108
+ try:
109
+ reader = imageio.get_reader(tmp_path)
110
+ meta = reader.get_meta_data()
111
+ original_fps = meta['fps']
112
+ width, height = meta['size']
113
+ total_frames = meta['nframes'] if meta['nframes'] != float('inf') else 1000 # Fallback for unknown length
114
+
115
+ output_fps = fps_options[target_fps] if fps_options[target_fps] else original_fps
116
+ frame_interval = max(1, int(original_fps / output_fps)) if output_fps else 1
117
+
118
+ out_path = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False).name
119
+ writer = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*'mp4v'), output_fps or original_fps, (width, height))
120
+
121
+ st.session_state.start_time = time.time()
122
+ processed_count = 0
123
+
124
+ for i, frame in enumerate(reader):
125
+ if i % frame_interval == 0:
126
+ frame_rgb = np.array(frame)
127
+ results = model.predict(frame_rgb, conf=confidence)
128
+ processed_frame = results[0].plot()[:, :, ::-1]
129
+ writer.write(processed_frame)
130
+
131
+ processed_count += 1
132
+ elapsed = time.time() - st.session_state.start_time
133
+ progress = (i + 1) / total_frames
134
+ st.session_state.progress = min(progress, 1.0)
135
+
136
+ if elapsed > 0:
137
+ frames_left = total_frames - i - 1
138
+ time_per_frame = elapsed / processed_count
139
+ eta = frames_left * time_per_frame / frame_interval
140
+ eta_str = f"{int(eta // 60)}m {int(eta % 60)}s"
141
+ else:
142
+ eta_str = "Calculating..."
143
+
144
+ progress_bar.progress(st.session_state.progress)
145
+ progress_text.text(f"Progress: {st.session_state.progress:.1%} | ETA: {eta_str}")
146
+
147
+ writer.release()
148
+ reader.close()
149
+
150
+ with open(out_path, 'rb') as f:
151
+ return f.read()
152
+
153
+ finally:
154
+ if os.path.exists(tmp_path):
155
+ os.unlink(tmp_path)
156
+ if os.path.exists(out_path):
157
+ os.unlink(out_path)
158
+
159
+ # Process uploaded video
160
+ if process_button and uploaded_file and model:
161
+ with st.spinner("Processing video..."):
162
+ st.session_state.processed_video = process_video(uploaded_file, selected_fps, confidence)
163
+ st.session_state.processing_complete = True
164
+ progress_bar.progress(1.0)
165
+ progress_text.text("Processing complete!")
166
+
167
+ # Show processed video and download button
168
+ if st.session_state.processing_complete and st.session_state.processed_video:
169
+ st.subheader("Your Processed Video")
170
+ show_video(st.session_state.processed_video, "Processed Result", loop=False)
171
+ download_slot.download_button(
172
  label="Download Processed Video",
173
+ data=st.session_state.processed_video,
174
+ file_name="processed_wildfire.mp4",
175
  mime="video/mp4"
176
+ )
177
+
178
+ if not model:
179
+ st.error("Model loading failed. Please check the repository and model file availability.")