gowtham851 commited on
Commit
0a59a90
·
verified ·
1 Parent(s): 388c779

Upload 8 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ model.keras filter=lfs diff=lfs merge=lfs -text
Copy of final_project_isl.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
app.py ADDED
@@ -0,0 +1,607 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import numpy as np
3
+ import cv2
4
+ import tensorflow as tf
5
+ from tensorflow.keras.models import load_model
6
+ import pandas as pd
7
+ from io import BytesIO
8
+ import base64
9
+ import matplotlib.pyplot as plt
10
+ from reportlab.lib.pagesizes import letter
11
+ from reportlab.pdfgen import canvas
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ import urllib.parse
14
+ import json
15
+ import random
16
+ import os
17
+
18
+ # Set page configuration
19
+ st.set_page_config(page_title="Indian Sign Language Classifier", page_icon="🤟", layout="wide")
20
+
21
+ # Define paths
22
+ MODEL_PATH = "C:/Users/Cherukuri Gowtham/OneDrive/project/model.keras" # Update with your actual model path
23
+ DATASET_PATH = "C:\\Users\\Cherukuri Gowtham\\OneDrive\\project\\isl dataset\\Indian" # Verify this path exists
24
+
25
+ # Load the trained model
26
+ try:
27
+ model = load_model(MODEL_PATH)
28
+ except Exception as e:
29
+ st.error(f"Error loading model: {e}")
30
+ st.stop()
31
+
32
+ # Define class labels
33
+ class_labels = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
34
+
35
+ # Translations for prediction output and learning mode
36
+ translations = {
37
+ 'en': {
38
+ 'prediction_text': "The predicted sign is 🤟: {sign}",
39
+ 'confidence_text': "Confidence: {confidence:.2%}",
40
+ 'description_text': "Description: Sign {sign} represents the {type} {sign} in Indian Sign Language.",
41
+ 'top_3_text': "Top 3 Suggestions:",
42
+ 'top_3_item': "- {sign}: {confidence:.2%}",
43
+ 'learning_text': "Practice Sign: {sign}",
44
+ 'learning_description': "Sign {sign} is the {type} {sign} in Indian Sign Language.",
45
+ },
46
+ 'hi': {
47
+ 'prediction_text': "अनुमानित संकेत है 🤟: {sign}",
48
+ 'confidence_text': "आत्मविश्वास: {confidence:.2%}",
49
+ 'description_text': "विवरण: संकेत {sign} भारतीय सांकेतिक भाषा में {type} {sign} को दर्शाता है।",
50
+ 'top_3_text': "शीर्ष 3 सुझाव:",
51
+ 'top_3_item': "- {sign}: {confidence:.2%}",
52
+ 'learning_text': "अभ्यास संकेत: {sign}",
53
+ 'learning_description': "संकेत {sign} भारतीय सांकेतिक भाषा में {type} {sign} है।",
54
+ },
55
+ 'ta': {
56
+ 'prediction_text': "கணிக்கப்பட்ட குறியீடு 🤟: {sign}",
57
+ 'confidence_text': "நம்பிக்கை: {confidence:.2%}",
58
+ 'description_text': "விளக்கம்: குறியீடு {sign} இந்திய சைகை மொழியில் {type} {sign} ஐ பிரதிநிதித்துவப்படுத்துகிறது。",
59
+ 'top_3_text': "முதல் 3 பரிந்துரைகள்:",
60
+ 'top_3_item': "- {sign}: {confidence:.2%}",
61
+ 'learning_text': "பயிற்சி குறியீடு: {sign}",
62
+ 'learning_description': "குறியீடு {sign} இந்திய சைகை மொழியில் {type} {sign} ஆகும்。",
63
+ },
64
+ 'te': {
65
+ 'prediction_text': "అంచనా వేసిన సంజ్ఞ 🤟: {sign}",
66
+ 'confidence_text': "విశ్వాసం: {confidence:.2%}",
67
+ 'description_text': "వివరణ: సంజ్ఞ {sign} భారతీయ సంజ్ఞా భాషలో {type} {sign} ని సూచిస్తుంది。",
68
+ 'top_3_text': "టాప్ 3 సూచనలు:",
69
+ 'top_3_item': "- {sign}: {confidence:.2%}",
70
+ 'learning_text': "అభ్యాస సంజ్ఞ: {sign}",
71
+ 'learning_description': "సంజ్ఞ {sign} భారతీయ సంజ్ఞా భాషలో {type} {sign} గా ఉంది।",
72
+ },
73
+ 'bn': {
74
+ 'prediction_text': "পূর্বাভাসিত সংকেত 🤟: {sign}",
75
+ 'confidence_text': "আত্মবিশ্বাস: {confidence:.2%}",
76
+ 'description_text': "বর্ণনা: সংকেত {sign} ভারতীয় সংকেত ভাষায় {type} {sign} প্রতিনিধিত্ব করে।",
77
+ 'top_3_text': "শীর্ষ 3 পরামর্শ:",
78
+ 'top_3_item': "- {sign}: {confidence:.2%}",
79
+ 'learning_text': "অভ্যাস সংকেত: {sign}",
80
+ 'learning_description': "সংকেত {sign} ভারতীয় সংকেত ভাষায় {type} {sign} হিসেবে প্রতিনিধিত্ব করে।",
81
+ },
82
+ 'mr': {
83
+ 'prediction_text': "अंदाजित संकेत आहे 🤟: {sign}",
84
+ 'confidence_text': "आत्मविश्वास: {confidence:.2%}",
85
+ 'description_text': "वर्णन: स���केत {sign} भारतीय संकेत भाषेत {type} {sign} दर्शवितो।",
86
+ 'top_3_text': "शीर्ष 3 सूचना:",
87
+ 'top_3_item': "- {sign}: {confidence:.2%}",
88
+ 'learning_text': "सराव संकेत: {sign}",
89
+ 'learning_description': "संकेत {sign} भारतीय संकेत भाषेत {type} {sign} आहे।",
90
+ },
91
+ 'gu': {
92
+ 'prediction_text': "આગાહી કરેલ સંકેત છે 🤟: {sign}",
93
+ 'confidence_text': "આત્મવિશ્વાસ: {confidence:.2%}",
94
+ 'description_text': "વર્ણન: સંકેત {sign} ભારતીય સંકેત ભાષામાં {type} {sign} નું પ્રતિનિધિત્વ કરે છે।",
95
+ 'top_3_text': "ટોચના 3 સૂચનો:",
96
+ 'top_3_item': "- {sign}: {confidence:.2%}",
97
+ 'learning_text': "અભ્યાસ સંકેત: {sign}",
98
+ 'learning_description': "સંકેત {sign} ભારતીય સંકેત ભાષામાં {type} {sign} છે।",
99
+ },
100
+ 'kn': {
101
+ 'prediction_text': "ಊಹಿಸಲಾದ ಸಂಕೇತ 🤟: {sign}",
102
+ 'confidence_text': "ವಿಶ್ವಾಸ: {confidence:.2%}",
103
+ 'description_text': "ವಿವರಣೆ: ಸಂಕೇತ {sign} ಭಾರತೀಯ ಸಂಕೇತ ಭಾಷೆಯಲ್ಲಿ {type} {sign} ಗೆ ಪ್ರತಿನಿಧಿಯಾಗಿರುತ್ತದೆ।",
104
+ 'top_3_text': "ಟಾಪ್ 3 ಸಲಹೆಗಳು:",
105
+ 'top_3_item': "- {sign}: {confidence:.2%}",
106
+ 'learning_text': "ಅಭ್ಯಾಸ ಸಂಕೇತ: {sign}",
107
+ 'learning_description': "ಸಂಕೇತ {sign} ಭಾರತೀಯ ಸಂಕೇತ ಭಾಷೆಯಲ್ಲಿ {type} {sign} ಆಗಿದೆ।",
108
+ },
109
+ 'ml': {
110
+ 'prediction_text': "പ്രവചിച്ച ആംഗ്യം 🤟: {sign}",
111
+ 'confidence_text': "ആത്മവിശ്വാസം: {confidence:.2%}",
112
+ 'description_text': "വിവരണം: ആംഗ്യം {sign} ഇന്ത്യൻ ആംഗ്യഭാഷയിൽ {type} {sign} നെ പ്രതിനിധീകരിക്കുന്നു।",
113
+ 'top_3_text': "മികച്ച 3 നിർദ്ദേശങ്ങൾ:",
114
+ 'top_3_item': "- {sign}: {confidence:.2%}",
115
+ 'learning_text': "പരിശീലന ആംഗ്യം: {sign}",
116
+ 'learning_description': "ആംഗ്യം {sign} ഇന്ത്യൻ ആംഗ്യഭাষയിൽ {type} {sign} ആണ്。",
117
+ },
118
+ 'pa': {
119
+ 'prediction_text': "ਅੰਦਾਜ਼ਾ ਲਗਾਇਆ ਸੰਕੇਤ 🤟: {sign}",
120
+ 'confidence_text': "ਵਿਸ਼ਵਾਸ: {confidence:.2%}",
121
+ 'description_text': "ਵੇਰਵਾ: ਸੰਕੇਤ {sign} ਭਾਰਤੀ ਸੰਕੇਤ ਭਾਸ਼ਾ ਵਿੱਚ {type} {sign} ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ।",
122
+ 'top_3_text': "ਸਿਖਰ ਦੇ 3 ਸੁਝਾਅ:",
123
+ 'top_3_item': "- {sign}: {confidence:.2%}",
124
+ 'learning_text': "ਅਭਿਆਸ ਸੰਕੇਤ: {sign}",
125
+ 'learning_description': "ਸੰਕੇਤ {sign} ਭਾਰਤੀ ਸੰਕੇਤ ਭਾਸ਼ਾ ਵਿੱਚ {type} {sign} ਹੈ।",
126
+ },
127
+ 'or': {
128
+ 'prediction_text': "ପୂର୍ବାନୁମାନିତ ଚିହ୍ନ 🤟: {sign}",
129
+ 'confidence_text': "ଆତ୍ମବିଶ୍ୱାସ: {confidence:.2%}",
130
+ 'description_text': "ବିବରଣୀ: ଚିହ୍ନ {sign} ଭାରତୀୟ ସଙ୍କେତ ଭାଷାରେ {type} {sign} କୁ ପ୍ରତିନିଧିତ୍ୱ କରେ।",
131
+ 'top_3_text': "ଶୀର୍ଷ 3 ପରାମର୍ଶ:",
132
+ 'top_3_item': "- {sign}: {confidence:.2%}",
133
+ 'learning_text': "ଅଭ୍ୟାସ ଚିହ୍ନ: {sign}",
134
+ 'learning_description': "ଚିହ୍ନ {sign} ଭାରତୀୟ ସଙ୍କେତ ଭାଷାରେ {type} {sign} ଅଟେ।",
135
+ },
136
+ 'as': {
137
+ 'prediction_text': "পূৰ্বাভাস কৰা সংকেত 🤟: {sign}",
138
+ 'confidence_text': "আত্মবিশ্বাস: {confidence:.2%}",
139
+ 'description_text': "বিৱৰণ: সংকেত {sign} ভাৰতীয় সংকেত ভাষাত {type} {sign} ক প্ৰতিনিধিত্ব কৰে।",
140
+ 'top_3_text': "শীৰ্ষ ৩ পৰামৰ্শ:",
141
+ 'top_3_item': "- {sign}: {confidence:.2%}",
142
+ 'learning_text': "অভ্যাস সংকেত: {sign}",
143
+ 'learning_description': "সংকেত {sign} ভাৰতীয় সংকেত ভাষাত {type} {sign} হয়।",
144
+ }
145
+ }
146
+
147
+ # Preprocess image with caching
148
+ @st.cache_data
149
+ def preprocess_image(image, target_size=(64, 62)):
150
+ image_resized = cv2.resize(image, target_size)
151
+ image_preprocessed = tf.keras.preprocessing.image.img_to_array(image_resized) / 255.0
152
+ return image_resized, image_preprocessed
153
+
154
+ # Load sign image with caching
155
+ @st.cache_data
156
+ def load_sign_image(sign):
157
+ # Debugging: Show attempted paths
158
+ st.write(f"Attempting to load image for sign '{sign}' from {DATASET_PATH}")
159
+
160
+ # Try subfolder structure (e.g., DATASET_PATH/A/image.png)
161
+ subfolder_path = os.path.join(DATASET_PATH, sign)
162
+ if os.path.isdir(subfolder_path):
163
+ st.write(f"Found subfolder: {subfolder_path}")
164
+ for ext in ['png', 'jpg', 'jpeg']:
165
+ images = [f for f in os.listdir(subfolder_path) if f.lower().endswith(f'.{ext}')]
166
+ if images:
167
+ image_path = os.path.join(subfolder_path, images[0])
168
+ st.write(f"Selected image: {image_path}")
169
+ return image_path
170
+ st.write(f"No images found in {subfolder_path}")
171
+
172
+ # Try alternative subfolder names (e.g., letter_A, 0 for numbers)
173
+ alt_subfolder = f"letter_{sign}" if sign.isalpha() else str(int(sign) - 1) if sign.isdigit() else sign
174
+ alt_subfolder_path = os.path.join(DATASET_PATH, alt_subfolder)
175
+ if os.path.isdir(alt_subfolder_path):
176
+ st.write(f"Found alternative subfolder: {alt_subfolder_path}")
177
+ for ext in ['png', 'jpg', 'jpeg']:
178
+ images = [f for f in os.listdir(alt_subfolder_path) if f.lower().endswith(f'.{ext}')]
179
+ if images:
180
+ image_path = os.path.join(alt_subfolder_path, images[0])
181
+ st.write(f"Selected image: {image_path}")
182
+ return image_path
183
+ st.write(f"No images found in {alt_subfolder_path}")
184
+
185
+ # Try single image (e.g., DATASET_PATH/A.png)
186
+ for ext in ['png', 'jpg', 'jpeg']:
187
+ image_path = os.path.join(DATASET_PATH, f"{sign}.{ext}")
188
+ if os.path.exists(image_path):
189
+ st.write(f"Found single image: {image_path}")
190
+ return image_path
191
+
192
+ # Try case-insensitive subfolder
193
+ for folder in os.listdir(DATASET_PATH):
194
+ if folder.lower() == sign.lower() and os.path.isdir(os.path.join(DATASET_PATH, folder)):
195
+ subfolder_path = os.path.join(DATASET_PATH, folder)
196
+ st.write(f"Found case-insensitive subfolder: {subfolder_path}")
197
+ for ext in ['png', 'jpg', 'jpeg']:
198
+ images = [f for f in os.listdir(subfolder_path) if f.lower().endswith(f'.{ext}')]
199
+ if images:
200
+ image_path = os.path.join(subfolder_path, images[0])
201
+ st.write(f"Selected image: {image_path}")
202
+ return image_path
203
+
204
+ st.write(f"No image found for sign '{sign}'")
205
+ return None
206
+
207
+ # Convert image to base64
208
+ def image_to_base64(image):
209
+ image_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
210
+ _, buffer = cv2.imencode('.png', image_bgr)
211
+ return base64.b64encode(buffer).decode('utf-8')
212
+
213
+ # Generate PDF report (English for simplicity)
214
+ def generate_pdf_report(df):
215
+ buffer = BytesIO()
216
+ c = canvas.Canvas(buffer, pagesize=letter)
217
+ c.setFont("Helvetica", 12)
218
+ c.drawString(100, 750, "Indian Sign Language Prediction Report")
219
+ y = 700
220
+ for _, row in df.iterrows():
221
+ c.drawString(100, y, f"Image: {row['Image']}")
222
+ c.drawString(100, y-20, f"Predicted Sign: {row['Predicted Sign']}")
223
+ c.drawString(100, y-40, f"Confidence: {row['Confidence']:.2%}")
224
+ y -= 60
225
+ c.save()
226
+ buffer.seek(0)
227
+ return buffer
228
+
229
+ # Visualization function
230
+ def generate_visualization(df):
231
+ if df.empty:
232
+ st.warning("No predictions to visualize. Please upload images first.")
233
+ return
234
+ chart_type = st.selectbox("Select Chart Type", ["Bar Chart", "Pie Chart", "Confidence Trend"], key="chart_type")
235
+ if chart_type == "Bar Chart":
236
+ sign_counts = df["Predicted Sign"].value_counts()
237
+ fig, ax = plt.subplots()
238
+ ax.bar(sign_counts.index, sign_counts.values)
239
+ ax.set_title("Prediction Distribution (Bar Chart)")
240
+ ax.set_xlabel("Signs")
241
+ ax.set_ylabel("Count")
242
+ plt.xticks(rotation=45)
243
+ st.pyplot(fig)
244
+ elif chart_type == "Pie Chart":
245
+ sign_counts = df["Predicted Sign"].value_counts()
246
+ fig, ax = plt.subplots()
247
+ ax.pie(sign_counts.values, labels=sign_counts.index, autopct='%1.1f%%', startangle=90)
248
+ ax.axis('equal')
249
+ ax.set_title("Prediction Distribution (Pie Chart)")
250
+ st.pyplot(fig)
251
+ else: # Confidence Trend
252
+ selected_sign = st.selectbox("Select Sign for Confidence Trend", options=class_labels, key="trend_sign")
253
+ trend_df = df[df["Predicted Sign"] == selected_sign][["Confidence"]].reset_index(drop=True)
254
+ if trend_df.empty:
255
+ st.warning(f"No predictions for sign {selected_sign}.")
256
+ return
257
+ fig, ax = plt.subplots()
258
+ ax.plot(trend_df.index, trend_df["Confidence"], marker='o')
259
+ ax.set_title(f"Confidence Trend for Sign {selected_sign}")
260
+ ax.set_xlabel("Prediction Instance")
261
+ ax.set_ylabel("Confidence")
262
+ ax.grid(True)
263
+ st.pyplot(fig)
264
+
265
+ # CSS for accessible, visual-first styling
266
+ st.markdown("""
267
+ <style>
268
+ @keyframes slideIn {
269
+ 0% { transform: translateX(-100%); opacity: 0; }
270
+ 100% { transform: translateX(0); opacity: 1; }
271
+ }
272
+ @keyframes flash {
273
+ 0% { border-color: #ff6b6b; }
274
+ 50% { border-color: #4ecdc4; }
275
+ 100% { border-color: #ff6b6b; }
276
+ }
277
+ .stApp {
278
+ transition: all 0.3s ease;
279
+ font-size: 18px;
280
+ }
281
+ .prediction-card {
282
+ animation: slideIn 0.5s ease-out;
283
+ background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45e994);
284
+ color: white;
285
+ padding: 15px;
286
+ border-radius: 10px;
287
+ margin-bottom: 10px;
288
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
289
+ border: 3px solid transparent;
290
+ }
291
+ .prediction-card.flash {
292
+ animation: flash 0.5s;
293
+ }
294
+ .stButton>button {
295
+ background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
296
+ color: white;
297
+ border: none;
298
+ border-radius: 25px;
299
+ padding: 15px 30px;
300
+ font-size: 16px;
301
+ transition: transform 0.2s;
302
+ }
303
+ .stButton>button:hover {
304
+ transform: scale(1.05);
305
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
306
+ }
307
+ .loader {
308
+ border: 4px solid #f3f3f3;
309
+ border-top: 4px solid #ff6b6b;
310
+ border-radius: 50%;
311
+ width: 40px;
312
+ height: 40px;
313
+ animation: spin 1s linear infinite;
314
+ margin: auto;
315
+ }
316
+ @keyframes spin {
317
+ 0% { transform: rotate(0deg); }
318
+ 100% { transform: rotate(360deg); }
319
+ }
320
+ .header {
321
+ background: linear-gradient(to right, #ff7e5f, #feb47b);
322
+ padding: 20px;
323
+ border-radius: 10px;
324
+ text-align: center;
325
+ color: white;
326
+ margin-bottom: 20px;
327
+ }
328
+ .footer {
329
+ background: linear-gradient(to right, #6b7280, #4b5563);
330
+ padding: 10px;
331
+ border-radius: 10px;
332
+ text-align: center;
333
+ color: white;
334
+ margin-top: 20px;
335
+ }
336
+ .search-bar {
337
+ padding: 10px;
338
+ border-radius: 5px;
339
+ border: 1px solid #ccc;
340
+ width: 100%;
341
+ font-size: 16px;
342
+ }
343
+ .learning-card {
344
+ background: linear-gradient(45deg, #4ecdc4, #45e994);
345
+ color: white;
346
+ padding: 20px;
347
+ border-radius: 10px;
348
+ text-align: center;
349
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
350
+ }
351
+ .learning-image {
352
+ max-width: 200px;
353
+ margin: 0 auto;
354
+ display: block;
355
+ }
356
+ @media (max-width: 600px) {
357
+ .stSidebar {
358
+ width: 100%;
359
+ height: auto;
360
+ }
361
+ .stApp {
362
+ font-size: 16px;
363
+ }
364
+ .learning-image {
365
+ max-width: 150px;
366
+ }
367
+ }
368
+ </style>
369
+ """, unsafe_allow_html=True)
370
+
371
+ # Header
372
+ st.markdown("<div class='header'><h1>Indian Sign Language Classifier</h1></div>", unsafe_allow_html=True)
373
+
374
+ # Sidebar
375
+ st.sidebar.header("Settings & Instructions")
376
+ st.sidebar.markdown("""
377
+ 1. Select the language for prediction output and learning content (English by default).
378
+ 2. Use the Image Upload tab to classify signs.
379
+ 3. Adjust settings for image processing.
380
+ 4. Set confidence threshold for predictions.
381
+ 5. Search prediction history by sign, image name, or confidence in the Image Upload tab.
382
+ 6. Use the Visualization tab for prediction distribution or confidence trends.
383
+ 7. Export results as CSV or PDF in the Image Upload tab.
384
+ 8. Practice signs with images from the dataset in the Learning tab.
385
+ 9. Provide feedback in the Feedback tab.
386
+ """)
387
+ language_options = {
388
+ 'en': 'English',
389
+ 'hi': 'Hindi',
390
+ 'ta': 'Tamil',
391
+ 'te': 'Telugu',
392
+ 'bn': 'Bengali',
393
+ 'mr': 'Marathi',
394
+ 'gu': 'Gujarati',
395
+ 'kn': 'Kannada',
396
+ 'ml': 'Malayalam',
397
+ 'pa': 'Punjabi',
398
+ 'or': 'Odia',
399
+ 'as': 'Assamese'
400
+ }
401
+ if 'selected_language' not in st.session_state:
402
+ st.session_state.selected_language = 'en'
403
+ selected_language = st.sidebar.selectbox(
404
+ "Prediction Language",
405
+ options=list(language_options.values()),
406
+ index=list(language_options.keys()).index(st.session_state.selected_language),
407
+ help="Choose the language for prediction output and learning content"
408
+ )
409
+ st.session_state.selected_language = list(language_options.keys())[list(language_options.values()).index(selected_language)]
410
+ theme = st.sidebar.selectbox("Theme", ["Light", "Dark", "High Contrast"], help="Choose a theme for better visibility")
411
+ if theme == "Dark":
412
+ st.markdown("<style>.stApp { background-color: #1E1E1E; color: white; }</style>", unsafe_allow_html=True)
413
+ elif theme == "High Contrast":
414
+ st.markdown("<style>.stApp { background-color: #000; color: #FFF; }</style>", unsafe_allow_html=True)
415
+ target_size = st.sidebar.slider("Target Image Height (px)", 16, 64, 64, step=8, help="Set image height (width fixed at 62)")
416
+ target_size = (target_size, 62)
417
+ confidence_threshold = st.sidebar.slider("Minimum Confidence Threshold", 0.0, 1.0, 0.5, 0.05, help="Filter low-confidence predictions")
418
+
419
+ # Initialize session state
420
+ if 'predictions_df' not in st.session_state:
421
+ st.session_state.predictions_df = pd.DataFrame(columns=["Image", "Predicted Sign", "Confidence", "Image Base64"])
422
+ if 'current_sign' not in st.session_state:
423
+ st.session_state.current_sign = random.choice(class_labels)
424
+
425
+ # Process single image
426
+ def process_single_image(uploaded_file, target_size, confidence_threshold):
427
+ try:
428
+ file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
429
+ image = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
430
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
431
+ image_resized, image_preprocessed = preprocess_image(image, target_size)
432
+ prediction = model.predict(np.expand_dims(image_preprocessed, axis=0), verbose=0)
433
+ predicted_class = class_labels[np.argmax(prediction)]
434
+ confidence = np.max(prediction)
435
+ top_3 = np.argsort(prediction[0])[-3:][::-1]
436
+ top_3_signs = [(class_labels[i], prediction[0][i]) for i in top_3]
437
+ if confidence >= confidence_threshold:
438
+ image_base64 = image_to_base64(image_resized)
439
+ return {
440
+ "Image": uploaded_file.name,
441
+ "Predicted Sign": predicted_class,
442
+ "Confidence": confidence,
443
+ "Image Base64": image_base64,
444
+ "Top 3 Signs": top_3_signs
445
+ }
446
+ else:
447
+ return {"error": f"Prediction for {uploaded_file.name} below confidence threshold ({confidence:.2%} < {confidence_threshold:.2%})"}
448
+ except Exception as e:
449
+ return {"error": f"Error processing {uploaded_file.name}: {e}"}
450
+
451
+ # Tabs
452
+ tab1, tab2, tab3, tab4 = st.tabs(["Image Upload", "Visualization", "Feedback", "Learning"])
453
+
454
+ # Tab 1: Image Upload
455
+ with tab1:
456
+ st.subheader("Classify Signs")
457
+ uploaded_files = st.file_uploader("Upload image(s)", type=["jpg", "png", "jpeg"], accept_multiple_files=True, help="Upload images of signs")
458
+
459
+ if st.button("Reset History", help="Clear all predictions"):
460
+ st.session_state.predictions_df = pd.DataFrame(columns=["Image", "Predicted Sign", "Confidence", "Image Base64"])
461
+ st.success("Prediction history reset.")
462
+ st.rerun()
463
+
464
+ if uploaded_files:
465
+ st.subheader("Prediction Results")
466
+ progress_bar = st.progress(0)
467
+ total_files = len(uploaded_files)
468
+ with ThreadPoolExecutor() as executor:
469
+ results = list(executor.map(lambda f: process_single_image(f, target_size, confidence_threshold), uploaded_files))
470
+ for i, result in enumerate(results):
471
+ if "error" not in result:
472
+ new_row = pd.DataFrame([{k: v for k, v in result.items() if k != "Top 3 Signs"}])
473
+ st.session_state.predictions_df = pd.concat([st.session_state.predictions_df, new_row], ignore_index=True)
474
+
475
+ # Display prediction in the selected language
476
+ lang = st.session_state.selected_language
477
+ sign_type = "number" if result['Predicted Sign'].isdigit() else "letter"
478
+ st.markdown(f"""
479
+ <div class='prediction-card flash'>
480
+ <h3>{translations[lang]['prediction_text'].format(sign=result['Predicted Sign'])}</h3>
481
+ <p>{translations[lang]['confidence_text'].format(confidence=result['Confidence'])}</p>
482
+ </div>
483
+ """, unsafe_allow_html=True)
484
+ st.markdown(translations[lang]['description_text'].format(sign=result['Predicted Sign'], type=sign_type))
485
+ st.markdown(translations[lang]['top_3_text'])
486
+ for s, c in result["Top 3 Signs"]:
487
+ st.markdown(translations[lang]['top_3_item'].format(sign=s, confidence=c))
488
+ else:
489
+ st.error(result["error"])
490
+ progress_bar.progress((i + 1) / total_files)
491
+
492
+ if not st.session_state.predictions_df.empty:
493
+ st.subheader("Prediction Summary")
494
+ st.markdown("**Search Prediction History**")
495
+ search_query = st.text_input("Search by sign, image name, or confidence (e.g., 'A', 'image1.jpg', '0.9')", "", help="Enter a sign, image name, or confidence value")
496
+ filter_sign = st.multiselect("Filter by Predicted Sign", options=class_labels, default=[], help="Filter predictions by sign")
497
+ filtered_df = st.session_state.predictions_df
498
+ if filter_sign:
499
+ filtered_df = filtered_df[filtered_df["Predicted Sign"].isin(filter_sign)]
500
+ if search_query:
501
+ try:
502
+ confidence_search = float(search_query) if search_query.replace('.', '', 1).isdigit() else None
503
+ filtered_df = filtered_df[
504
+ (filtered_df["Predicted Sign"].str.contains(search_query, case=False)) |
505
+ (filtered_df["Image"].str.contains(search_query, case=False)) |
506
+ (filtered_df["Confidence"].apply(lambda x: abs(x - confidence_search) < 0.05) if confidence_search is not None else False)
507
+ ]
508
+ except ValueError:
509
+ filtered_df = filtered_df[
510
+ (filtered_df["Predicted Sign"].str.contains(search_query, case=False)) |
511
+ (filtered_df["Image"].str.contains(search_query, case=False))
512
+ ]
513
+ selected_row = st.dataframe(
514
+ filtered_df[["Image", "Predicted Sign", "Confidence"]].style.format({"Confidence": "{:.2%}"}),
515
+ on_select="rerun",
516
+ selection_mode="single-row",
517
+ use_container_width=True
518
+ )
519
+ if selected_row["selection"]["rows"]:
520
+ idx = selected_row["selection"]["rows"][0]
521
+ row = filtered_df.iloc[idx]
522
+ st.image(base64.b64decode(row["Image Base64"]), caption="Processed Image", width=200)
523
+ st.markdown(f"**Sign**: {row['Predicted Sign']}")
524
+ st.markdown(f"**Confidence**: {row['Confidence']:.2%}")
525
+ st.markdown(f"**Description**: Sign {row['Predicted Sign']} represents the {'number' if row['Predicted Sign'].isdigit() else 'letter'} {row['Predicted Sign']} in Indian Sign Language.")
526
+
527
+ st.subheader("Export Results")
528
+ col1, col2, col3 = st.columns(3)
529
+ with col1:
530
+ st.download_button(
531
+ label="Download Predictions as CSV",
532
+ data=st.session_state.predictions_df[["Image", "Predicted Sign", "Confidence"]].to_csv(index=False).encode('utf-8'),
533
+ file_name="predictions.csv",
534
+ mime="text/csv",
535
+ help="Download predictions as CSV"
536
+ )
537
+ with col2:
538
+ st.download_button(
539
+ label="Download PDF Report",
540
+ data=generate_pdf_report(st.session_state.predictions_df),
541
+ file_name="isl_report.pdf",
542
+ mime="application/pdf",
543
+ help="Download predictions as PDF"
544
+ )
545
+ with col3:
546
+ if st.button("Share Prediction", help="Share the latest prediction"):
547
+ latest_prediction = st.session_state.predictions_df.iloc[-1].to_dict()
548
+ prediction_json = json.dumps(latest_prediction)
549
+ encoded = urllib.parse.quote(prediction_json)
550
+ share_url = f"{st.get_option('server.baseUrlPath')}?prediction={encoded}"
551
+ st.markdown(f"Share this prediction: [Link]({share_url})")
552
+
553
+ # Tab 2: Visualization
554
+ with tab2:
555
+ st.subheader("Prediction History Visualization")
556
+ generate_visualization(st.session_state.predictions_df)
557
+
558
+ # Tab 3: Feedback
559
+ with tab3:
560
+ st.subheader("Feedback")
561
+ with st.form("feedback_form"):
562
+ st.markdown("Help us improve the app!")
563
+ rating = st.slider("Rate this app (1-5) ⭐", 1, 5, help="Rate your experience")
564
+ comments = st.text_area("Comments 💬", help="Share your thoughts (processed in English)")
565
+ submitted = st.form_submit_button("Submit Feedback")
566
+ if submitted:
567
+ st.success("Thank you for your feedback!")
568
+ with open("feedback.txt", "a") as f:
569
+ f.write(f"Rating: {rating}, Comments: {comments}\n")
570
+
571
+ # Tab 4: Learning
572
+ with tab4:
573
+ st.subheader("Sign Learning Mode")
574
+ st.markdown("Practice Indian Sign Language signs by viewing images and descriptions from the dataset.")
575
+ lang = st.session_state.selected_language
576
+ sign = st.session_state.current_sign
577
+ sign_type = "number" if sign.isdigit() else "letter"
578
+
579
+ # Load and display sign image
580
+ image_path = load_sign_image(sign)
581
+ if image_path:
582
+ st.image(
583
+ image_path,
584
+ caption=f"Indian Sign Language Sign: {sign}",
585
+ width=200,
586
+ use_column_width=False,
587
+ output_format="auto",
588
+ clamp=True,
589
+ channels="RGB"
590
+ )
591
+ else:
592
+ st.warning(f"Image for sign {sign} not found in {DATASET_PATH}. Ensure a subfolder '{sign}' or file '{sign}.png/jpg' exists.")
593
+
594
+ # Display text description
595
+ st.markdown(f"""
596
+ <div class='learning-card'>
597
+ <h3>{translations[lang]['learning_text'].format(sign=sign)}</h3>
598
+ <p>{translations[lang]['learning_description'].format(sign=sign, type=sign_type)}</p>
599
+ </div>
600
+ """, unsafe_allow_html=True)
601
+
602
+ if st.button("Show New Sign", help="Display a new random sign"):
603
+ st.session_state.current_sign = random.choice(class_labels)
604
+ st.rerun()
605
+
606
+ # Footer
607
+ st.markdown("<div class='footer'>Powered by Streamlit, TensorFlow, OpenCV.</div>", unsafe_allow_html=True)
feedback.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ Rating: 3, Comments:
model.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:62080bdc993096063431743337ac555cfefc473bc346a8ca1af42f450e295a49
3
+ size 9924263
report.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+
2
+ <h1>Indian Sign Language Classification Report</h1>
3
+ <p>Generated on: 2025-04-15 13:M:45</p>
4
+ <table border='1'>
5
+ <tr><th>Image</th><th>Predicted Sign</th><th>Confidence</th></tr>
6
+ <tr><td>0.jpg</td><td>R</td><td>100.00%</td></tr>
7
+ </table>
8
+
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ streamlit
2
+ numpy
3
+ opencv-python
4
+ tensorflow
sign_language_model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5045bf665f989babd4ee5abd87b84a9e30adfaf15dbf3b62c8166eb2eb1f4350
3
+ size 29700184
test1.jpeg ADDED