fagrrr's picture
Initial Hugging Face deployment
c802d72
Raw
History Blame Contribute Delete
4.47 kB
import cv2
import torch
import torch.nn.functional as F
import numpy as np
import os
from app.core.config import I3D_WEIGHTS, CLASS_LIST
from app.models.i3d_model import I3DModel
from app.utils.mediapipe_utils import hand_detector_instance
# ---------------- CONFIG ----------------
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
clip_length = 64
MIN_PAUSE_FRAMES = 5
MIN_SIGN_FRAMES = 10
# ---------------- MODEL ----------------
i3d_model = None
def get_i3d_model():
global i3d_model
if i3d_model is None:
print("Loading I3D model...")
i3d_model = I3DModel(I3D_WEIGHTS, device)
return i3d_model
with open(CLASS_LIST, "r") as f:
gloss_list = [line.strip().upper() for line in f.readlines()]
# ---------------- VIDEO LOADING ----------------
def load_video(video_path):
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise ValueError(f"Cannot open video: {video_path}")
frames = []
hand_flags = []
while True:
ret, frame = cap.read()
if not ret:
break
#print("FRAME SHAPE:", frame.shape)
resized = cv2.resize(frame, (224, 224))
norm = (resized.astype(np.float32) / 255.0) * 2 - 1
frames.append(norm)
hand_flags.append(hand_detector_instance.detect(frame))
cap.release()
frames = np.array(frames)
print("TOTAL FRAMES READ:", len(frames))
return frames, hand_flags
# ---------------- SEGMENTATION ----------------
def segment_frames(frames, hand_flags):
segments = []
start = 0
pause = 0
for i in range(len(frames)):
if hand_flags[i]:
pause += 1
else:
if pause >= MIN_PAUSE_FRAMES:
end = i - pause
if end - start >= MIN_SIGN_FRAMES:
segments.append((start, end))
start = i
pause = 0
if len(frames) - start >= MIN_SIGN_FRAMES:
segments.append((start, len(frames) - 1))
return segments
# ---------------- INFERENCE ----------------
def predict_segment(segment_frames, topk=5):
if len(segment_frames) < clip_length:
return []
results_accum = {}
# 🔥 FIX 1: proper sliding window (NOT naive chunking)
stride = clip_length // 2
for start in range(0, len(segment_frames) - clip_length, stride):
clip = segment_frames[start:start + clip_length]
# safety check
if clip.shape[0] != clip_length:
continue
clip = clip.transpose(3, 0, 1, 2)
clip_tensor = torch.from_numpy(clip).unsqueeze(0).to(device)
with torch.no_grad():
model = get_i3d_model()
logits = model(clip_tensor)
logits = torch.mean(logits, dim=2)
probs = F.softmax(logits, dim=1)
top_probs, top_idx = torch.topk(probs, k=topk, dim=1)
# 🔥 FIX 2: accumulate scores properly
for i, p in zip(top_idx[0], top_probs[0]):
idx = int(i)
if idx < len(gloss_list):
word = gloss_list[idx]
if word not in results_accum:
results_accum[word] = 0
results_accum[word] += float(p)
if not results_accum:
return []
# 🔥 FIX 3: sort final results
sorted_results = sorted(results_accum.items(), key=lambda x: x[1], reverse=True)
return sorted_results[:topk]
# ---------------- SELECTION ----------------
def select_best(results, context):
if not results:
return ""
return results[0][0]
# ---------------- PIPELINE ----------------
def run_pipeline(video_path):
print("\nSTARTING PIPELINE")
frames, hand_flags = load_video(video_path)
print("HAND FLAGS SAMPLE:", hand_flags[:20])
print("TRUE COUNT:", sum(hand_flags))
segments = segment_frames(frames, hand_flags)
print("SEGMENTS:", segments)
final_glosses = []
for s, e in segments:
segment = frames[s:e]
results = predict_segment(segment)
if not results:
continue
selected = select_best(results, final_glosses)
final_glosses.append(selected)
gloss_sentence = " ".join(final_glosses)
print("\nGLOSS:", gloss_sentence)
# IMPORTANT: no API test yet
english = "API NOT RUN (testing logic only)"
print("ENGLISH:", english)
return {
"gloss": gloss_sentence,
"english": english
}