🤟 Sign Language Interpreter
Real-time sign language recognition using computer vision
import streamlit as st from streamlit_webrtc import webrtc_streamer, VideoTransformerBase import cv2 import numpy as np from av import VideoFrame from sign_utils import SignLanguagePredictor, MediaPipeLandmarksModel # Page config st.set_page_config( page_title="Sign Language Interpreter", page_icon="🤟", layout="wide" ) # Custom CSS for better UI st.markdown(""" """, unsafe_allow_html=True) # Initialize models @st.cache_resource def load_models(): try: predictor = SignLanguagePredictor( model_path="models/model.tflite", labels_path="models/labels.txt" ) return predictor except Exception as e: st.error(f"Error loading models: {str(e)}") return None predictor = load_models() class SignInterpreter(VideoTransformerBase): def __init__(self, confidence_threshold=0.7): self.predictor = predictor self.landmark_model = MediaPipeLandmarksModel() self.result_text = "Show your hand sign" self.confidence = 0.0 self.landmarks = None self.prediction_counter = {} self.last_prediction = None self.confidence_threshold = confidence_threshold self.frame_count = 0 self.prediction_history = [] self.stable_prediction = None self.stable_confidence = 0.0 # Enhanced prediction smoothing self.prediction_buffer = [] self.buffer_size = 8 # Reduced for faster response self.min_consistent_frames = 3 # Reduced for faster response def recv(self, frame: VideoFrame) -> VideoFrame: image = frame.to_ndarray(format="bgr24") self.frame_count += 1 if self.predictor: # Get landmarks self.landmarks = self.landmark_model.predict_landmarks(image) # Get prediction if hand is detected if self.landmarks: try: # Use temporal prediction instead of static prediction, raw_confidence = self.predictor.predict(image) # Add to prediction buffer with higher threshold for confidence if raw_confidence > 0.4: # Only add predictions with decent confidence self.prediction_buffer.append((prediction, raw_confidence)) if len(self.prediction_buffer) > self.buffer_size: self.prediction_buffer.pop(0) # Get smoothed prediction smoothed_prediction, smoothed_confidence = self._get_smoothed_prediction() # Update current values self.confidence = smoothed_confidence # Check if prediction meets confidence threshold if smoothed_confidence > self.confidence_threshold: # Count consecutive predictions if smoothed_prediction not in self.prediction_counter: self.prediction_counter = {smoothed_prediction: 1} else: self.prediction_counter[smoothed_prediction] += 1 # Update stable prediction if we have enough consistent frames max_pred = max(self.prediction_counter.items(), key=lambda x: x[1]) if max_pred[1] >= self.min_consistent_frames: self.stable_prediction = smoothed_prediction self.stable_confidence = smoothed_confidence self.result_text = f"Sign: {smoothed_prediction}" self.last_prediction = smoothed_prediction else: # Reset if confidence is too low if self.frame_count % 30 == 0: # Reset every 30 frames self.prediction_counter = {} self.result_text = "Show your hand sign" except Exception as e: self.result_text = "Processing..." self.confidence = 0.0 self.prediction_counter = {} else: self.result_text = "No hand detected" self.confidence = 0.0 self.prediction_counter = {} self.prediction_buffer = [] # Draw landmarks with better visualization if self.landmarks: image = self.landmark_model.draw_landmarks(image, self.landmarks) # Enhanced text overlay with better positioning self._draw_prediction_overlay(image) return VideoFrame.from_ndarray(image, format="bgr24") def _get_smoothed_prediction(self): """Get smoothed prediction from buffer""" if not self.prediction_buffer: return "No prediction", 0.0 # Get predictions from last few frames recent_predictions = self.prediction_buffer[-5:] if len(self.prediction_buffer) >= 5 else self.prediction_buffer # Count occurrences of each prediction prediction_counts = {} confidence_sums = {} for pred, conf in recent_predictions: if pred not in prediction_counts: prediction_counts[pred] = 0 confidence_sums[pred] = 0.0 prediction_counts[pred] += 1 confidence_sums[pred] += conf # Get most frequent prediction if prediction_counts: most_frequent = max(prediction_counts.items(), key=lambda x: x[1]) avg_confidence = confidence_sums[most_frequent[0]] / prediction_counts[most_frequent[0]] return most_frequent[0], avg_confidence return "No prediction", 0.0 def _draw_prediction_overlay(self, image): """Draw enhanced prediction overlay""" height, width = image.shape[:2] # Background rectangle for better text visibility overlay = image.copy() cv2.rectangle(overlay, (10, 10), (width-10, 100), (0, 0, 0), -1) cv2.addWeighted(overlay, 0.7, image, 0.3, 0, image) # Main prediction text color = (0, 255, 0) if self.confidence > self.confidence_threshold else (0, 165, 255) cv2.putText( image, self.result_text, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 2 ) # Confidence text cv2.putText( image, f"Confidence: {self.confidence:.2f}", (20, 70), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1 ) # Threshold indicator threshold_color = (0, 255, 0) if self.confidence > self.confidence_threshold else (0, 0, 255) cv2.putText( image, f"Threshold: {self.confidence_threshold:.2f}", (20, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.5, threshold_color, 1 ) def main(): # Header st.markdown("""
Real-time sign language recognition using computer vision