Spaces:
Sleeping
Sleeping
Download app.py from pacomesimon/FlyingBirdDetection: direct link, hf CLI and curl.
- Browser
- Download file 6.21 kB
-
https://huggingface.co/spaces/pacomesimon/FlyingBirdDetection/resolve/main/app.py
- Command line
-
hf download hf://spaces/pacomesimon/FlyingBirdDetection/app.py
-
curl -L -o app.py https://huggingface.co/spaces/pacomesimon/FlyingBirdDetection/resolve/main/app.py
6.21 kB
| import os | |
| import cv2 | |
| import numpy as np | |
| import time | |
| import gradio as gr | |
| import tempfile | |
| ENVIRONMENT = "pi" | |
| try: | |
| from sensor import Sensor | |
| except ImportError: | |
| Sensor = lambda : None | |
| ENVIRONMENT = "dev" | |
| from agent import Agent | |
| sensor = Sensor() | |
| pano_agent = Agent(sensor = sensor) | |
| if ENVIRONMENT == "dev": | |
| def work_once(self, state=[]): | |
| if len(state) < 2: | |
| return np.random.normal(loc=128, scale=30, size=(300,400,3)).clip(0,255).astype(np.uint8) | |
| prev_image = state[-2] | |
| current_image = state[-1] | |
| coco_bboxes = self.predict(current_image, prev_image) | |
| artifacts = self.handle_prediction(current_image, prev_image, coco_bboxes,0) | |
| return artifacts | |
| pano_agent.work_once = work_once.__get__(pano_agent) | |
| with gr.Blocks() as demo: | |
| with gr.Row(): | |
| threshold_slider = gr.Slider( | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=pano_agent.bird_detector.threshold, | |
| step=0.01, | |
| label="Threshold" | |
| ) | |
| def change_detection_threshold(threshold): | |
| pano_agent.bird_detector.threshold = threshold | |
| threshold_slider.change(change_detection_threshold, | |
| inputs=threshold_slider, | |
| outputs=None) | |
| percentile_slider = gr.Slider( | |
| minimum=0, | |
| maximum=100, | |
| value=pano_agent.bird_detector.percentile, | |
| step=1, | |
| label="Percentile" | |
| ) | |
| def change_detection_percentile(percentile): | |
| pano_agent.bird_detector.percentile = percentile | |
| percentile_slider.change(change_detection_percentile, | |
| inputs=percentile_slider, | |
| outputs=None) | |
| with gr.Row(): | |
| with gr.Tab("Upload Video"): | |
| gr.Markdown("### Video Bird Detector (Demo Version)") | |
| with gr.Row(): | |
| with gr.Column(): | |
| video_input = gr.Video(label="Upload Video") | |
| with gr.Column(): | |
| gr.Examples( | |
| examples=[["nyagatare_2025_11_24_video.mp4"]], | |
| inputs=video_input, | |
| ) | |
| process_button = gr.Button("Process Video") | |
| with gr.Row(): | |
| video_output = gr.Video(label="Processed Output") | |
| def process_video_dummy(video): | |
| """ | |
| Processes the input video by extracting frames at 2fps, running pano_agent.work_once | |
| on each pair of consecutive frames, and returning the processed video. | |
| """ | |
| # video is generally a path in Gradio, but can sometimes be a numpy array. | |
| # Assume it's a file path. | |
| cap = cv2.VideoCapture(video) | |
| if not cap.isOpened(): | |
| raise RuntimeError(f"Cannot open video {video}") | |
| # Get video properties | |
| input_fps = cap.get(cv2.CAP_PROP_FPS) | |
| frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| if frame_count < 0: | |
| input_fps = 20.0 | |
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | |
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |
| new_fps = 2.0 | |
| frame_interval = int(round(input_fps / new_fps)) if input_fps > new_fps else 1 | |
| frames = [] | |
| success, frame = cap.read() | |
| idx = 0 | |
| while success: | |
| if idx % frame_interval == 0: | |
| frames.append(frame) | |
| success, frame = cap.read() | |
| idx += 1 | |
| cap.release() | |
| if len(frames) < 2: | |
| # Not enough frames, just return the original video | |
| return video | |
| output_frames = [] | |
| prev_frame = frames[0] | |
| for current_frame in frames[1:]: | |
| out_frame = pano_agent.work_once([prev_frame, current_frame]) | |
| output_frames.append(out_frame if out_frame is not None else current_frame) | |
| prev_frame = current_frame | |
| # Write result to a temporary file | |
| temp_file = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) | |
| temp_path = temp_file.name | |
| temp_file.close() | |
| fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
| writer = cv2.VideoWriter(temp_path, fourcc, new_fps, (output_frames[0].shape[1], output_frames[0].shape[0])) | |
| for f in output_frames: | |
| # If output frame is grayscale, convert to BGR | |
| if len(f.shape) == 2: | |
| f = cv2.cvtColor(f, cv2.COLOR_GRAY2BGR) | |
| writer.write(f) | |
| writer.release() | |
| return temp_path | |
| process_button.click( | |
| process_video_dummy, | |
| inputs=video_input, | |
| outputs=video_output, | |
| ) | |
| with gr.Tab("Real-Time (Webcam Only)"): | |
| with gr.Row(): | |
| # start_agent_btn = gr.Button("Submit") | |
| # stop_button = gr.Button("Stop Process", variant="stop") | |
| text_info = gr.Markdown("### Welcome to the Bird Detector Demo!") | |
| with gr.Row(): | |
| input_img = gr.Image(label="webcam input", sources=["webcam"], type="numpy") | |
| dummy_img = gr.Image(visible=False) | |
| img_state = gr.State([]) | |
| agent_view = gr.Image(label="Detection output", type="numpy") | |
| input_img.stream( | |
| lambda img, state: ((state[-1:] + [img]), | |
| pano_agent.work_once(state[-1:] + [img])), | |
| inputs=[input_img, img_state], | |
| outputs=[img_state, agent_view], | |
| ) | |
| if ENVIRONMENT == "pi": | |
| with gr.Blocks() as demo: | |
| with gr.Row(): | |
| start_agent_btn = gr.Button("Submit") | |
| stop_button = gr.Button("Stop Process", variant="stop") | |
| with gr.Row(): | |
| agent_view = gr.Image() | |
| agent_work = start_agent_btn.click(pano_agent.work, | |
| inputs = None, | |
| outputs = agent_view | |
| ) | |
| stop_button.click( | |
| fn=None, # No function to execute on stop, just cancel | |
| inputs=None, | |
| outputs=None, | |
| cancels=[agent_work] | |
| ) | |
| demo.launch( | |
| # debug = True, | |
| server_name="0.0.0.0", | |
| ) | |