|
|
|
|
|
import cv2 |
|
|
import tensorflow as tf |
|
|
import time |
|
|
import base64 |
|
|
import datetime |
|
|
import os |
|
|
|
|
|
|
|
|
MODEL_PATH = os.getenv('MODEL_PATH', 'model') |
|
|
RESOLUTION = int(os.getenv('RESOLUTION', 172)) |
|
|
CONFIDENCE_THRESHOLD = 0.65 |
|
|
|
|
|
print(f"Loading MoViNet from {MODEL_PATH}...") |
|
|
model = tf.saved_model.load(MODEL_PATH) |
|
|
infer = model.signatures['serving_default'] |
|
|
print("Model loaded!") |
|
|
|
|
|
def get_init_states(): |
|
|
dummy = tf.zeros([1, 1, RESOLUTION, RESOLUTION, 3], dtype=tf.float32) |
|
|
return model.init_states(tf.shape(dummy)) |
|
|
os.environ["OPENCV_FFMPEG_INTERRUPT_TIMEOUT"] = "60000" |
|
|
os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "rtsp_transport;tcp" |
|
|
class VideoProcessor: |
|
|
def __init__(self): |
|
|
self.running = False |
|
|
|
|
|
def start_processing(self, rtsp_url, result_queue): |
|
|
self.running = True |
|
|
print(f"Trying to open: {rtsp_url}") |
|
|
cap = cv2.VideoCapture(rtsp_url, cv2.CAP_FFMPEG) |
|
|
if not cap.isOpened(): |
|
|
result_queue.put({"error": "Cannot open RTSP URL"}) |
|
|
return |
|
|
print("RTSP Stream Opened successfully with TCP!") |
|
|
states = get_init_states() |
|
|
|
|
|
|
|
|
in_event = False |
|
|
event_start_time = None |
|
|
cooldown_counter = 0 |
|
|
COOLDOWN_LIMIT = 30 |
|
|
|
|
|
while self.running: |
|
|
ret, frame = cap.read() |
|
|
if not ret: |
|
|
break |
|
|
|
|
|
|
|
|
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) |
|
|
resized = tf.image.resize(rgb, [RESOLUTION, RESOLUTION]) |
|
|
input_tensor = tf.cast(resized, tf.float32) / 255.0 |
|
|
input_tensor = input_tensor[tf.newaxis, tf.newaxis, ...] |
|
|
|
|
|
outputs = infer(image=input_tensor, **states) |
|
|
logits = outputs['logits'] |
|
|
states = {k: v for k, v in outputs.items() if k != 'logits'} |
|
|
probs = tf.nn.softmax(logits, axis=-1)[0] |
|
|
|
|
|
fight_conf = float(probs[0]) |
|
|
norm_conf = float(probs[1]) |
|
|
is_violence = (fight_conf > norm_conf) and (fight_conf > CONFIDENCE_THRESHOLD) |
|
|
|
|
|
|
|
|
current_time = datetime.datetime.now() |
|
|
msg = None |
|
|
|
|
|
if is_violence: |
|
|
cooldown_counter = 0 |
|
|
if not in_event: |
|
|
in_event = True |
|
|
event_start_time = current_time |
|
|
|
|
|
|
|
|
small_frame = cv2.resize(frame, (640, 360)) |
|
|
_, buffer = cv2.imencode('.jpg', small_frame) |
|
|
img_base64 = base64.b64encode(buffer).decode('utf-8') |
|
|
|
|
|
msg = { |
|
|
"type": "START", |
|
|
"timestamp": current_time.isoformat(), |
|
|
"score": fight_conf, |
|
|
"image": img_base64 |
|
|
} |
|
|
else: |
|
|
if in_event: |
|
|
cooldown_counter += 1 |
|
|
if cooldown_counter >= COOLDOWN_LIMIT: |
|
|
|
|
|
duration = (current_time - event_start_time).total_seconds() |
|
|
msg = { |
|
|
"type": "END", |
|
|
"timestamp": current_time.isoformat(), |
|
|
"duration": duration |
|
|
} |
|
|
in_event = False |
|
|
|
|
|
|
|
|
if msg: |
|
|
result_queue.put(msg) |
|
|
|
|
|
|
|
|
|
|
|
cap.release() |
|
|
result_queue.put({"status": "Stream stopped"}) |
|
|
|