File size: 3,938 Bytes
c7f34f1
 
 
 
5252e41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c7f34f1
 
5252e41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c7f34f1
 
5252e41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import streamlit as st
import cv2
import numpy as np
import mediapipe as mp
import joblib
import pandas as pd
from numpy.linalg import norm

# Function to load the Random Forest model
@st.cache_resource
def load_model():
    try:
        return joblib.load('best_random_forest_model.pkl')
    except Exception as e:
        st.error(f"Error loading model: {e}")
        return None

# Load the model using the cached function
model = load_model()

# Ensure the model is loaded before proceeding
if model is None:
    st.stop()

# Initialize MediaPipe Hands
@st.cache_resource
def load_mediapipe_model():
    mp_hands = mp.solutions.hands
    return mp_hands.Hands(static_image_mode=True, max_num_hands=1, min_detection_confidence=0.5)

hands = load_mediapipe_model()
mp_drawing = mp.solutions.drawing_utils

# Function to normalize landmarks
def normalize_landmarks(landmarks):
    # Center the landmarks
    center = np.mean(landmarks, axis=0)
    landmarks_centered = landmarks - center

    # Scale the landmarks to unit variance
    std_dev = np.std(landmarks_centered, axis=0)
    landmarks_normalized = landmarks_centered / std_dev

    # Replace NaN values with 0 (in case of division by zero)
    landmarks_normalized = np.nan_to_num(landmarks_normalized)

    return landmarks_normalized

# Function to calculate angles between landmarks
def calculate_angles(landmarks):
    angles = []
    for i in range(20):
        for j in range(i + 1, 21):
            vector = landmarks[j] - landmarks[i]
            angle_x = np.arccos(np.clip(vector[0] / norm(vector), -1.0, 1.0))
            angle_y = np.arccos(np.clip(vector[1] / norm(vector), -1.0, 1.0))
            angles.extend([angle_x, angle_y])
    return angles

# Streamlit app
st.title("ASL Recognition App")

# Upload image using Streamlit's file uploader
uploaded_file = st.file_uploader("Upload an image of an ASL sign", type=["jpg", "jpeg", "png"])

if uploaded_file is not None:
    try:
        # Read the image
        image = cv2.imdecode(np.frombuffer(uploaded_file.read(), np.uint8), cv2.IMREAD_COLOR)
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        
        # Process the image and find hand landmarks
        results = hands.process(image_rgb)
        
        if results.multi_hand_landmarks:
            for hand_landmarks in results.multi_hand_landmarks:
                # Draw landmarks on the image
                mp_drawing.draw_landmarks(image, hand_landmarks, mp.solutions.hands.HAND_CONNECTIONS)
                
                # Extract and normalize landmarks
                landmarks = np.array([[lm.x, lm.y] for lm in hand_landmarks.landmark])
                landmarks_normalized = normalize_landmarks(landmarks)
                
                # Calculate angles using normalized landmarks
                angles = calculate_angles(landmarks_normalized)
                
                # Prepare input with feature names
                angle_columns = [f'angle_{i}' for i in range(len(angles))]
                angles_df = pd.DataFrame([angles], columns=angle_columns)
                
                # Predict the alphabet
                probabilities = model.predict_proba(angles_df)[0]
                top_indices = np.argsort(probabilities)[::-1][:5]
                top_probabilities = probabilities[top_indices]
                top_classes = model.classes_[top_indices]
                
                # Display the top 5 predictions
                st.write("Top 5 Predicted Alphabets:")
                for i in range(5):
                    st.write(f"{top_classes[i]}: {top_probabilities[i]:.2f}")
            
            # Display the image with landmarks
            st.image(image, caption="Processed Image with Landmarks", use_column_width=True)
        else:
            st.write("No hands detected. Please try another image.")
    except Exception as e:
        st.error(f"Error processing image: {e}")