VicGerardoPR
commited on
Commit
•
9a43209
1
Parent(s):
fe1a998
Upload 3 files
Browse files- README.md +31 -8
- app.py +230 -0
- requirements.txt +8 -0
README.md
CHANGED
@@ -1,12 +1,35 @@
|
|
1 |
---
|
2 |
-
title: Traffic Sign Classifier
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
-
sdk: streamlit
|
7 |
-
|
8 |
-
app_file: app.py
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: "Traffic Sign Classifier"
|
3 |
+
emoji: "🚦"
|
4 |
+
colorFrom: "blue"
|
5 |
+
colorTo: "green"
|
6 |
+
sdk: "streamlit"
|
7 |
+
app_file: "app.py"
|
|
|
8 |
pinned: false
|
9 |
---
|
10 |
|
11 |
+
# Traffic Sign Classifier
|
12 |
+
|
13 |
+
Esta aplicación clasifica señales de tráfico usando un modelo de CNN.
|
14 |
+
|
15 |
+
## Cómo ejecutar localmente
|
16 |
+
|
17 |
+
1. Clona el repositorio:
|
18 |
+
```bash
|
19 |
+
git clone https://github.com/tu-usuario/tu-repo.git
|
20 |
+
```
|
21 |
+
2. Crea un entorno virtual e instala las dependencias:
|
22 |
+
```bash
|
23 |
+
cd tu-repo
|
24 |
+
python -m venv venv
|
25 |
+
source venv/bin/activate
|
26 |
+
pip install -r requirements.txt
|
27 |
+
```
|
28 |
+
3. Ejecuta la aplicación:
|
29 |
+
```bash
|
30 |
+
streamlit run app.py
|
31 |
+
```
|
32 |
+
|
33 |
+
## Desplegado en Hugging Face Spaces
|
34 |
+
|
35 |
+
Puedes ver la aplicación desplegada en [Hugging Face Spaces](https://huggingface.co/spaces/tu-usuario/tu-repo).
|
app.py
ADDED
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
"""ProyectoAvanzado1.ipynb
|
3 |
+
|
4 |
+
Automatically generated by Colab.
|
5 |
+
|
6 |
+
Original file is located at
|
7 |
+
https://colab.research.google.com/drive/1R5pOFRcOn9faAiaFmIL6GcuWweWYGswX
|
8 |
+
"""
|
9 |
+
|
10 |
+
import os
|
11 |
+
import pickle
|
12 |
+
import numpy as np
|
13 |
+
from sklearn.model_selection import train_test_split
|
14 |
+
from tensorflow.keras.utils import to_categorical
|
15 |
+
import matplotlib.pyplot as plt
|
16 |
+
import seaborn as sns
|
17 |
+
import pandas as pd
|
18 |
+
from sklearn import preprocessing
|
19 |
+
import streamlit as st
|
20 |
+
import tensorflow as tf
|
21 |
+
import numpy as np
|
22 |
+
import cv2
|
23 |
+
from PIL import Image
|
24 |
+
import matplotlib.pyplot as plt
|
25 |
+
import seaborn as sns
|
26 |
+
import tensorflow as tf
|
27 |
+
from tensorflow.keras.models import Sequential
|
28 |
+
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
|
29 |
+
|
30 |
+
# Función para cargar datos desde archivos .p
|
31 |
+
def load_pickle(file_path):
|
32 |
+
with open(file_path, 'rb') as file:
|
33 |
+
data = pickle.load(file)
|
34 |
+
return data
|
35 |
+
|
36 |
+
# Cargar datos de entrenamiento, validación y prueba
|
37 |
+
train_data = load_pickle(os.path.join("/Users/victorg/Documents/DataScience/ProjectoAvanzado/CSV/train.p"))
|
38 |
+
val_data = load_pickle(os.path.join("/Users/victorg/Documents/DataScience/ProjectoAvanzado/CSV/valid.p"))
|
39 |
+
test_data = load_pickle(os.path.join("/Users/victorg/Documents/DataScience/ProjectoAvanzado/CSV/test.p"))
|
40 |
+
|
41 |
+
# Separar imágenes y etiquetas
|
42 |
+
train_images, train_labels = train_data['features'], train_data['labels']
|
43 |
+
val_images, val_labels = val_data['features'], val_data['labels']
|
44 |
+
test_images, test_labels = test_data['features'], test_data['labels']
|
45 |
+
|
46 |
+
# Preprocesar datos
|
47 |
+
def preprocess_data(images, labels):
|
48 |
+
images = images.astype('float32') / 255.0
|
49 |
+
labels = to_categorical(labels, num_classes=43)
|
50 |
+
return images, labels
|
51 |
+
|
52 |
+
train_images, train_labels = preprocess_data(train_images, train_labels)
|
53 |
+
val_images, val_labels = preprocess_data(val_images, val_labels)
|
54 |
+
test_images, test_labels = preprocess_data(test_images, test_labels)
|
55 |
+
|
56 |
+
|
57 |
+
# Convertir etiquetas a DataFrame para visualización
|
58 |
+
train_df = pd.DataFrame({"label": train_labels.argmax(axis=1)})
|
59 |
+
|
60 |
+
# Conteo de imágenes por clase
|
61 |
+
plt.figure(figsize=(10, 6))
|
62 |
+
sns.countplot(x=train_df['label'])
|
63 |
+
plt.title("Conteo de Imágenes por Clase")
|
64 |
+
plt.xlabel("Clase")
|
65 |
+
plt.ylabel("Conteo")
|
66 |
+
plt.show()
|
67 |
+
|
68 |
+
# Visualización 2: Ejemplos de imágenes por clase
|
69 |
+
fig, axes = plt.subplots(5, 5, figsize=(15, 15))
|
70 |
+
axes = axes.ravel()
|
71 |
+
for i in range(25):
|
72 |
+
axes[i].imshow(train_images[i])
|
73 |
+
axes[i].set_title(f"Clase: {train_labels[i].argmax()}")
|
74 |
+
axes[i].axis('off')
|
75 |
+
plt.subplots_adjust(hspace=0.5)
|
76 |
+
plt.show()
|
77 |
+
|
78 |
+
# Visualización 3: Muestra aleatoria de imágenes
|
79 |
+
fig, axes = plt.subplots(3, 3, figsize=(12, 12))
|
80 |
+
axes = axes.ravel()
|
81 |
+
for i in range(9):
|
82 |
+
idx = np.random.randint(0, len(train_images))
|
83 |
+
axes[i].imshow(train_images[idx])
|
84 |
+
axes[i].set_title(f"Clase: {train_labels[idx].argmax()}")
|
85 |
+
axes[i].axis('off')
|
86 |
+
plt.subplots_adjust(hspace=0.5)
|
87 |
+
plt.show()
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
# Definir la arquitectura de la CNN
|
92 |
+
model = Sequential([
|
93 |
+
Conv2D(32, (3, 3), activation="relu", input_shape=(32, 32, 3)),
|
94 |
+
MaxPooling2D((2, 2)),
|
95 |
+
Conv2D(64, (3, 3), activation="relu"),
|
96 |
+
MaxPooling2D((2, 2)),
|
97 |
+
Conv2D(128, (3, 3), activation="relu"),
|
98 |
+
MaxPooling2D((2, 2)),
|
99 |
+
Flatten(),
|
100 |
+
Dense(215, activation="relu"),
|
101 |
+
Dropout(0.5),
|
102 |
+
Dense(43, activation="softmax")
|
103 |
+
])
|
104 |
+
|
105 |
+
# Compilar el modelo
|
106 |
+
model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])
|
107 |
+
|
108 |
+
# Verificar si el modelo ya está guardado
|
109 |
+
model_path = "traffic_sign_classifier.h5"
|
110 |
+
if os.path.exists(model_path):
|
111 |
+
model = tf.keras.models.load_model(model_path)
|
112 |
+
else:
|
113 |
+
model.fit(train_images, train_labels, epochs=10, validation_data=(val_images, val_labels))
|
114 |
+
model.save(model_path)
|
115 |
+
|
116 |
+
# Evaluar el modelo en datos de prueba
|
117 |
+
test_loss, test_acc = model.evaluate(test_images, test_labels)
|
118 |
+
print(f"Test Accuracy: {test_acc:.2f}")
|
119 |
+
|
120 |
+
|
121 |
+
|
122 |
+
|
123 |
+
# Cargar el modelo
|
124 |
+
model = tf.keras.models.load_model("traffic_sign_classifier.h5")
|
125 |
+
|
126 |
+
# Diccionario de clases de señales de tráfico
|
127 |
+
classes = {
|
128 |
+
0: 'Speed limit (20km/h)',
|
129 |
+
1: 'Speed limit (30km/h)',
|
130 |
+
2: 'Speed limit (50km/h)',
|
131 |
+
3: 'Speed limit (60km/h)',
|
132 |
+
4: 'Speed limit (70km/h)',
|
133 |
+
5: 'Speed limit (80km/h)',
|
134 |
+
6: 'End of speed limit (80km/h)',
|
135 |
+
7: 'Speed limit (100km/h)',
|
136 |
+
8: 'Speed limit (120km/h)',
|
137 |
+
9: 'No passing',
|
138 |
+
10: 'No passing for vehicles over 3.5 metric tons',
|
139 |
+
11: 'Right-of-way at the next intersection',
|
140 |
+
12: 'Priority road',
|
141 |
+
13: 'Yield',
|
142 |
+
14: 'Stop',
|
143 |
+
15: 'No vehicles',
|
144 |
+
16: 'Vehicles over 3.5 metric tons prohibited',
|
145 |
+
17: 'No entry',
|
146 |
+
18: 'General caution',
|
147 |
+
19: 'Dangerous curve to the left',
|
148 |
+
20: 'Dangerous curve to the right',
|
149 |
+
21: 'Double curve',
|
150 |
+
22: 'Bumpy road',
|
151 |
+
23: 'Slippery road',
|
152 |
+
24: 'Road narrows on the right',
|
153 |
+
25: 'Road work',
|
154 |
+
26: 'Traffic signals',
|
155 |
+
27: 'Pedestrians',
|
156 |
+
28: 'Children crossing',
|
157 |
+
29: 'Bicycles crossing',
|
158 |
+
30: 'Beware of ice/snow',
|
159 |
+
31: 'Wild animals crossing',
|
160 |
+
32: 'End of all speed and passing limits',
|
161 |
+
33: 'Turn right ahead',
|
162 |
+
34: 'Turn left ahead',
|
163 |
+
35: 'Ahead only',
|
164 |
+
36: 'Go straight or right',
|
165 |
+
37: 'Go straight or left',
|
166 |
+
38: 'Keep right',
|
167 |
+
39: 'Keep left',
|
168 |
+
40: 'Roundabout mandatory',
|
169 |
+
41: 'End of no passing',
|
170 |
+
42: 'End of no passing by vehicles over 3.5 metric tons'
|
171 |
+
}
|
172 |
+
|
173 |
+
# Función para predecir la clase de una imagen
|
174 |
+
def predict(image):
|
175 |
+
image = np.array(image)
|
176 |
+
image = cv2.resize(image, (32, 32))
|
177 |
+
image = image / 255.0
|
178 |
+
image = np.expand_dims(image, axis=0)
|
179 |
+
predictions = model.predict(image)
|
180 |
+
class_idx = np.argmax(predictions)
|
181 |
+
return classes[class_idx]
|
182 |
+
|
183 |
+
# Título y descripción de la aplicación
|
184 |
+
st.title("Traffic Sign Classifier")
|
185 |
+
st.write("Esta aplicación clasifica señales de tráfico usando un modelo de CNN.")
|
186 |
+
|
187 |
+
# Mostrar ejemplos de imágenes del conjunto de datos
|
188 |
+
st.header("Ejemplos de Imágenes del Conjunto de Datos")
|
189 |
+
fig, axes = plt.subplots(2, 5, figsize=(15, 6))
|
190 |
+
axes = axes.ravel()
|
191 |
+
for i in range(10):
|
192 |
+
idx = np.random.randint(0, len(train_images))
|
193 |
+
axes[i].imshow(train_images[idx])
|
194 |
+
axes[i].set_title(f"Clase: {train_labels[idx].argmax()}")
|
195 |
+
axes[i].axis('off')
|
196 |
+
st.pyplot(fig)
|
197 |
+
# Mostrar ejemplos de imágenes del conjunto de datos
|
198 |
+
|
199 |
+
fig, axes = plt.subplots(2, 5, figsize=(15, 6))
|
200 |
+
axes = axes.ravel()
|
201 |
+
for i in range(10):
|
202 |
+
idx = np.random.randint(0, len(train_images))
|
203 |
+
axes[i].imshow(train_images[idx])
|
204 |
+
axes[i].set_title(f"Clase: {train_labels[idx].argmax()}")
|
205 |
+
axes[i].axis('off')
|
206 |
+
st.pyplot(fig)
|
207 |
+
|
208 |
+
# Mostrar algunas visualizaciones de EDA
|
209 |
+
st.header("Visualizaciones de EDA")
|
210 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
211 |
+
sns.countplot(x='label', data=train_df, ax=ax)
|
212 |
+
ax.set_title("Conteo de Imágenes por Clase")
|
213 |
+
ax.set_xlabel("Clase")
|
214 |
+
ax.set_ylabel("Conteo")
|
215 |
+
st.pyplot(fig)
|
216 |
+
|
217 |
+
# Permitir al usuario cargar una imagen
|
218 |
+
st.header("Carga tu Propia Imagen de Señal de Tráfico")
|
219 |
+
uploaded_file = st.file_uploader("Elige una imagen...", type=["jpg", "jpeg", "png"])
|
220 |
+
if uploaded_file is not None:
|
221 |
+
image = Image.open(uploaded_file)
|
222 |
+
st.image(image, caption='Imagen Cargada', use_column_width=True)
|
223 |
+
st.write("")
|
224 |
+
st.write("Clasificando...")
|
225 |
+
label = predict(image)
|
226 |
+
st.write(f"Esta señal es: {label}")
|
227 |
+
|
228 |
+
# Mostrar métricas del modelo
|
229 |
+
st.header("Métricas del Modelo")
|
230 |
+
st.write(f"Exactitud del conjunto de prueba: {test_acc:.2f}")
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
tensorflow
|
3 |
+
pandas
|
4 |
+
numpy
|
5 |
+
matplotlib
|
6 |
+
seaborn
|
7 |
+
pillow
|
8 |
+
opencv-python
|