Tun Ye Minn commited on
Commit
aea2878
·
1 Parent(s): d786717

Clean deploy to Hugging Face Space

Browse files
Anomaly/resnet50_final.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1607839eb06288892d0201d3a2eefb6db8b1d27eba5d3a0d733ca7ed0e4b62f3
3
+ size 330551545
anomaly_gradio.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import cv2
3
+ import os
4
+ import tempfile
5
+ from torchvision.models.detection import fasterrcnn_resnet50_fpn, FastRCNNPredictor
6
+ from torchvision.transforms import functional as F
7
+
8
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
9
+ num_classes = 14
10
+
11
+ def load_anomaly_model():
12
+ model = fasterrcnn_resnet50_fpn(pretrained=False)
13
+ in_features = model.roi_heads.box_predictor.cls_score.in_features
14
+ model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
15
+ checkpoint = torch.load("Anomaly/resnet50_final.pth", map_location=device)
16
+ model.load_state_dict(checkpoint["model_state_dict"])
17
+ model.to(device).eval()
18
+ return model
19
+
20
+ model = load_anomaly_model()
21
+
22
+ def draw_boxes(frame, outputs, threshold=0.5):
23
+ for box, label, score in zip(outputs['boxes'], outputs['labels'], outputs['scores']):
24
+ if score >= threshold:
25
+ x1, y1, x2, y2 = map(int, box.tolist())
26
+ cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
27
+ cv2.putText(frame, f'{label.item()}:{score:.2f}', (x1, y1 - 10),
28
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
29
+ return frame
30
+
31
+ def detect_anomalies(video_file):
32
+ input_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
33
+ input_path.write(video_file.read())
34
+ input_path.close()
35
+
36
+ cap = cv2.VideoCapture(input_path.name)
37
+ fps = cap.get(cv2.CAP_PROP_FPS)
38
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
39
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
40
+ out_path = os.path.join(tempfile.gettempdir(), "anomaly_output.mp4")
41
+ out = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height))
42
+
43
+ while cap.isOpened():
44
+ ret, frame = cap.read()
45
+ if not ret:
46
+ break
47
+ img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
48
+ tensor = F.to_tensor(img).to(device)
49
+ with torch.no_grad():
50
+ pred = model([tensor])[0]
51
+ result = draw_boxes(frame, pred)
52
+ out.write(result)
53
+
54
+ cap.release()
55
+ out.release()
56
+ return out_path
app.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import gradio as gr
3
+ from anomaly_gradio import detect_anomalies
4
+ from segmentation_gradio import segment_video
5
+
6
+ anomaly_app = gr.Interface(
7
+ fn=detect_anomalies,
8
+ inputs=gr.Video(label="Upload video for anomaly detection"),
9
+ outputs=gr.Video(label="Processed anomaly video"),
10
+ title="Anomaly Detection with Faster R-CNN"
11
+ )
12
+
13
+ segmentation_app = gr.Interface(
14
+ fn=segment_video,
15
+ inputs=[
16
+ gr.Video(label="Upload video for segmentation"),
17
+ gr.Radio(["MobileNet", "ResNet34"], label="Choose segmentation model")
18
+ ],
19
+ outputs=gr.Video(label="Segmented output video"),
20
+ title="Semantic Segmentation with UNet"
21
+ )
22
+
23
+ demo = gr.TabbedInterface(
24
+ [anomaly_app, segmentation_app],
25
+ ["Anomaly Detection", "Segmentation"]
26
+ )
27
+
28
+ demo.launch()
pages/anomaly_detction.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import cv2
3
+ import torch
4
+ import os
5
+ import tempfile
6
+ import numpy as np
7
+ from torchvision.models.detection import fasterrcnn_resnet50_fpn, FastRCNNPredictor
8
+ from torchvision.transforms import functional as F
9
+
10
+ # ─────────────────────────────────────────────────────────────
11
+ # Streamlit UI Setup
12
+ st.set_page_config(page_title="Anomaly Detection", layout="centered")
13
+ st.title("📹 Anomaly Detection with Faster R-CNN")
14
+
15
+ # ─────────────────────────────────────────────────────────────
16
+ # Model Setup
17
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
18
+ num_classes = 14 # 13 classes + background
19
+
20
+ @st.cache_resource
21
+ def load_model():
22
+ model = fasterrcnn_resnet50_fpn(pretrained=False)
23
+ in_features = model.roi_heads.box_predictor.cls_score.in_features
24
+ model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
25
+
26
+ checkpoint = torch.load("Anomaly/resnet50_final.pth", map_location=device)
27
+ model.load_state_dict(checkpoint["model_state_dict"])
28
+ model.to(device)
29
+ model.eval()
30
+ return model
31
+
32
+ model = load_model()
33
+
34
+ # ─────────────────────────────────────────────────────────────
35
+ # Utility
36
+ def draw_boxes(frame, outputs, threshold=0.5):
37
+ for box, label, score in zip(outputs['boxes'], outputs['labels'], outputs['scores']):
38
+ if score >= threshold:
39
+ x1, y1, x2, y2 = map(int, box.tolist())
40
+ cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
41
+ cv2.putText(frame, f'{label.item()}:{score:.2f}', (x1, y1 - 10),
42
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
43
+ return frame
44
+
45
+ # ─────────────────────────────────────────────────────────────
46
+ # Interface
47
+ video_file = st.file_uploader("Upload a video for anomaly detection", type=["mp4", "mov", "avi"])
48
+
49
+ if video_file:
50
+ st.video(video_file)
51
+ start_button = st.button("▶ Start Anomaly Detection")
52
+
53
+ if start_button:
54
+ stframe = st.empty()
55
+ progress = st.progress(0)
56
+
57
+ temp_input = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
58
+ temp_input.write(video_file.read())
59
+ temp_input.close()
60
+
61
+ cap = cv2.VideoCapture(temp_input.name)
62
+ fps = cap.get(cv2.CAP_PROP_FPS)
63
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
64
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
65
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
66
+
67
+ output_path = os.path.join(tempfile.gettempdir(), "anomaly_output.mp4")
68
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
69
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
70
+
71
+ frame_count = 0
72
+
73
+ while cap.isOpened():
74
+ ret, frame = cap.read()
75
+ if not ret:
76
+ break
77
+
78
+ image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
79
+ tensor = F.to_tensor(image).to(device)
80
+
81
+ with torch.no_grad():
82
+ prediction = model([tensor])[0]
83
+
84
+ annotated = draw_boxes(frame.copy(), prediction)
85
+ out.write(annotated)
86
+
87
+ resized = cv2.resize(annotated, (960, 540))
88
+ stframe.image(cv2.cvtColor(resized, cv2.COLOR_BGR2RGB), channels="RGB")
89
+
90
+ frame_count += 1
91
+ progress.progress(min(frame_count / total_frames, 1.0))
92
+
93
+ cap.release()
94
+ out.release()
95
+
96
+ st.success("✅ Anomaly detection complete!")
97
+
98
+ with open(output_path, "rb") as f:
99
+ st.download_button(
100
+ label="📥 Download Annotated Video",
101
+ data=f,
102
+ file_name="anomaly_output.mp4",
103
+ mime="video/mp4"
104
+ )
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch==2.7.1
3
+ torchvision==0.22.1
4
+ segmentation-models-pytorch==0.3.4
5
+ opencv-python-headless==4.8.0.76
6
+ numpy==1.26.4
7
+ Pillow
segmentation_gradio.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import cv2
3
+ import os
4
+ import tempfile
5
+ import numpy as np
6
+ from PIL import Image
7
+ from torchvision import transforms as T
8
+ import segmentation_models_pytorch as smp
9
+
10
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
11
+ resize_w, resize_h = 640, 384
12
+ mean = [0.485, 0.456, 0.406]
13
+ std = [0.229, 0.224, 0.225]
14
+ transform = T.Compose([
15
+ T.ToTensor(),
16
+ T.Normalize(mean, std)
17
+ ])
18
+ color_map = np.random.RandomState(42).randint(0, 255, size=(23, 3), dtype=np.uint8)
19
+
20
+ def apply_mask(image, mask):
21
+ mask_color = color_map[mask]
22
+ return cv2.addWeighted(image, 0.6, mask_color, 0.4, 0)
23
+
24
+ def load_segmentation_model(name):
25
+ model = smp.Unet(
26
+ encoder_name="mobilenet_v2" if name == "MobileNet" else "resnet34",
27
+ encoder_weights=None,
28
+ in_channels=3,
29
+ classes=23
30
+ )
31
+ path = "unet_mobilenet_final_50.pt" if name == "MobileNet" else "unet_resnet34_final_50.pt"
32
+ model.load_state_dict(torch.load(path, map_location=device))
33
+ model.to(device).eval()
34
+ return model
35
+
36
+ def segment_video(video_file, model_name):
37
+ model = load_segmentation_model(model_name)
38
+ input_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
39
+ input_path.write(video_file.read())
40
+ input_path.close()
41
+
42
+ cap = cv2.VideoCapture(input_path.name)
43
+ fps = cap.get(cv2.CAP_PROP_FPS)
44
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
45
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
46
+ out_path = os.path.join(tempfile.gettempdir(), "segmentation_output.mp4")
47
+ out = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height))
48
+
49
+ while cap.isOpened():
50
+ ret, frame = cap.read()
51
+ if not ret:
52
+ break
53
+ resized = cv2.resize(frame, (resize_w, resize_h))
54
+ rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
55
+ pil = Image.fromarray(rgb)
56
+ tensor = transform(pil).unsqueeze(0).to(device)
57
+ with torch.no_grad():
58
+ mask = torch.argmax(model(tensor), dim=1).squeeze().cpu().numpy()
59
+ resized_mask = cv2.resize(mask.astype(np.uint8), (width, height), interpolation=cv2.INTER_NEAREST)
60
+ overlay = apply_mask(frame, resized_mask)
61
+ out.write(overlay)
62
+
63
+ cap.release()
64
+ out.release()
65
+ return out_path
unet_mobilenet_final_50.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c977bc416a64415fd756eafecf9d07499350f64c35ef3106cc90f87899d30e25
3
+ size 26813798
unet_resnet34_final_50.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0e3a9ee76eeb1bff57338dace892d0ab9f2f90f5829ddb6d8c7bff836248c2c7
3
+ size 97936012