JAMC980-UNAH commited on
Commit
176b3e7
·
verified ·
1 Parent(s): b307767

Upload 6 files

Browse files
Files changed (7) hide show
  1. .gitattributes +1 -0
  2. app.py +269 -0
  3. clases_orden_oxford.json +104 -0
  4. flores_modelo (2).h5 +3 -0
  5. img2.png +0 -0
  6. img3.png +3 -0
  7. package-lock.json +6 -0
.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
+ img3.png filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import tensorflow as tf
3
+ import numpy as np
4
+ from PIL import Image
5
+ import json
6
+ import requests
7
+ import io
8
+ import base64
9
+ import os
10
+ os.environ["CUDA_VISIBLE_DEVICES"] = "-1" # Disable GPU
11
+
12
+ # ===== CONFIGURACIÓN =====
13
+ PLANTNET_CONFIG = {
14
+ "base_url": "https://my-api.plantnet.org/v2/identify/all",
15
+ "api_key": "2b10GtUDt6p1whX94wlEiR3CG",
16
+ "timeout": 10,
17
+ "lang": "es" # Español
18
+ }
19
+
20
+ # ===== VARIABLES GLOBALES =====
21
+ MODEL_LOADED = False
22
+ model = None
23
+ labels = []
24
+
25
+ # ===== FUNCIONES DE UTILIDAD =====
26
+ def load_model():
27
+ global model, labels, MODEL_LOADED
28
+ try:
29
+ model = tf.keras.models.load_model("flores_modelo (2).h5")
30
+ with open("clases_orden_oxford.json", "r") as f:
31
+ class_indices = json.load(f)
32
+ labels = [None] * len(class_indices)
33
+ for class_name, idx in class_indices.items():
34
+ labels[idx] = class_name.replace("_", " ").title()
35
+ MODEL_LOADED = True
36
+ except Exception as e:
37
+ print(f"Error al cargar el modelo: {e}")
38
+ MODEL_LOADED = False
39
+
40
+ def image_to_base64(image_path):
41
+ try:
42
+ with open(image_path, "rb") as img_file:
43
+ return base64.b64encode(img_file.read()).decode('utf-8')
44
+ except:
45
+ return None
46
+
47
+ def preprocess_image(image):
48
+ image = image.resize((224, 224))
49
+ img_array = np.array(image) / 255.0
50
+ if img_array.shape[-1] == 4:
51
+ img_array = img_array[..., :3]
52
+ return np.expand_dims(img_array, axis=0)
53
+
54
+ # =====സ
55
+
56
+ # ===== INTEGRACIÓN CON PLANTNET =====
57
+ def get_flower_info_from_plantnet(flower_name, image_array):
58
+ try:
59
+ image_pil = Image.fromarray((image_array[0] * 255).astype(np.uint8))
60
+ img_byte_arr = io.BytesIO()
61
+ image_pil.save(img_byte_arr, format='JPEG')
62
+ img_byte_arr.seek(0)
63
+
64
+ url = f"{PLANTNET_CONFIG['base_url']}?api-key={PLANTNET_CONFIG['api_key']}&lang={PLANTNET_CONFIG['lang']}"
65
+ files = {'images': ('image.jpg', img_byte_arr, 'image/jpeg')}
66
+ data = {'organs': 'flower'}
67
+
68
+ response = requests.post(url, files=files, data=data, timeout=PLANTNET_CONFIG['timeout'])
69
+ if response.status_code == 200:
70
+ return parse_plantnet_response(response.json(), flower_name)
71
+ else:
72
+ print(f"Error en PlantNet: {response.status_code}")
73
+ return get_fallback_info(flower_name)
74
+ except requests.exceptions.Timeout:
75
+ print("Tiempo de espera agotado en PlantNet")
76
+ return get_fallback_info(flower_name)
77
+ except Exception as e:
78
+ print(f"PlantNet error: {e}")
79
+ return get_fallback_info(flower_name)
80
+
81
+ def parse_plantnet_response(data, flower_name):
82
+ if 'results' in data and len(data['results']) > 0:
83
+ results = data['results'][:3]
84
+ info = f"""
85
+ <div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]">
86
+ <div class="flex items-center justify-center">
87
+ <h2 class="text-yellow-400 font-bold text-2xl">🌸 {flower_name}</h2>
88
+ </div>
89
+ <div>
90
+ <h3 class="text-yellow-400 font-bold text-xl mt-4">📊 Identificación Científica</h3>
91
+ """
92
+ for i, result in enumerate(results, 1):
93
+ species = result.get('species', {})
94
+ scientific_name = species.get('scientificNameWithoutAuthor', 'N/A')
95
+ authorship = species.get('scientificNameAuthorship', '')
96
+ common_names = species.get('commonNames', [])
97
+ family = species.get('family', {}).get('scientificNameWithoutAuthor', 'N/A')
98
+ genus = species.get('genus', {}).get('scientificNameWithoutAuthor', 'N/A')
99
+ score = result.get('score', 0)
100
+ common_names_str = ', '.join(common_names[:3]) if common_names else 'No disponible'
101
+
102
+ info += f"""
103
+ <div class="flex items-start mt-4">
104
+ <div class="text-white mr-4">#{i}</div>
105
+ <div>
106
+ <h4 class="text-white font-semibold">{scientific_name} {authorship}</h4>
107
+ <div class="relative h-2 bg-gray-200 rounded mt-2">
108
+ <div class="absolute h-full bg-yellow-400 rounded" style="width: {score*100}%"></div>
109
+ <span class="text-white text-sm mt-2 block">{score:.1%} confianza</span>
110
+ </div>
111
+ <div class="grid grid-cols-1 gap-2 mt-2">
112
+ <div class="text-white"><strong>Nombres comunes:</strong> {common_names_str}</div>
113
+ <div class="text-white"><strong>Familia:</strong> {family}</div>
114
+ <div class="text-white"><strong>Género:</strong> {genus}</div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ """
119
+ info += """
120
+ </div>
121
+ <div class="mt-6">
122
+ <h3 class="text-yellow-400 font-bold text-xl">🌿 Cuidados Generales</h3>
123
+ <div class="grid grid-cols-2 gap-4 mt-2">
124
+ <div class="flex items-start"><div class="text-2xl mr-2">☀️</div><div class="text-white"><strong>Luz:</strong> Luz solar directa o indirecta</div></div>
125
+ <div class="flex items-start"><div class="text-2xl mr-2">💧</div><div class="text-white"><strong>Riego:</strong> Mantener húmedo, evitar exceso</div></div>
126
+ <div class="flex items-start"><div class="text-2xl mr-2">🌡️</div><div class="text-white"><strong>Temperatura:</strong> Evitar cambios bruscos</div></div>
127
+ <div class="flex items-start"><div class="text-2xl mr-2">🌱</div><div class="text-white"><strong>Suelo:</strong> Bien drenado y rico en nutrientes</div></div>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ """
132
+ return info
133
+ return get_fallback_info(flower_name)
134
+
135
+ def get_fallback_info(flower_name):
136
+ return f"""
137
+ <div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]">
138
+ <div class="flex items-center justify-between">
139
+ <h2 class="text-yellow-400 font-bold text-2xl">🌸 {flower_name}</h2>
140
+ <div class="bg-red-600 text-white px-2 py-1 rounded">PlantNet no disponible</div>
141
+ </div>
142
+ <div class="mt-4">
143
+ <h3 class="text-yellow-400 font-bold text-xl">📖 Información General</h3>
144
+ <p class="text-white">Identificado por nuestro modelo de IA entrenado en el conjunto de datos Oxford 102 Flowers.</p>
145
+ <div class="grid grid-cols-2 gap-4 mt-4">
146
+ <div class="text-white">
147
+ <h4 class="font-semibold">🌺 Características</h4>
148
+ <ul class="list-disc ml-5">
149
+ <li>Estructuras reproductivas de la planta</li>
150
+ <li>Varios colores y formas</li>
151
+ <li>Evolucionadas para atraer polinizadores</li>
152
+ </ul>
153
+ </div>
154
+ <div class="text-white">
155
+ <h4 class="font-semibold">🎯 Cuidados Básicos</h4>
156
+ <ul class="list-disc ml-5">
157
+ <li>Buena iluminación según la especie</li>
158
+ <li>Riego regular sin exceso</li>
159
+ <li>Temperatura estable</li>
160
+ <li>Fertilización adecuada</li>
161
+ </ul>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ </div>
166
+ """
167
+
168
+ # ===== LÓGICA DE PREDICCIÓN =====
169
+ def predict(image):
170
+ if not image:
171
+ return "No se cargó ninguna imagen", "0%", """
172
+ <div class="bg-red-600 text-white rounded-2xl p-5 m-[15px_0]">
173
+ <h3 class="text-xl font-bold">⚠️ Imagen requerida</h3>
174
+ <p>Por favor, carga una imagen de una flor para iniciar la identificación.</p>
175
+ </div>
176
+ """
177
+ if not MODEL_LOADED:
178
+ return "Error en el modelo", "0%", """
179
+ <div class="bg-red-600 text-white rounded-2xl p-5 m-[15px_0]">
180
+ <h3 class="text-xl font-bold">🚫 Modelo no disponible</h3>
181
+ <p>No se pudo cargar el modelo de clasificación. Verifica los archivos del modelo.</p>
182
+ </div>
183
+ """
184
+ try:
185
+ img_array = preprocess_image(image)
186
+ preds = model.predict(img_array)
187
+ class_idx = np.argmax(preds[0])
188
+ confidence = preds[0][class_idx]
189
+ label_name = labels[class_idx]
190
+ flower_details = get_flower_info_from_plantnet(label_name, img_array)
191
+ return label_name, f"{confidence:.2%}", flower_details
192
+ except Exception as e:
193
+ return "Error", "0%", f"""
194
+ <div class="bg-red-600 text-white rounded-2xl p-5 m-[15px_0]">
195
+ <h3 class="text-xl font-bold">❌ Error de predicción</h3>
196
+ <p>Error durante el procesamiento: {str(e)}</p>
197
+ </div>
198
+ """
199
+
200
+ # ===== CSS PARA EL FONDO DE LA APLICACIÓN =====
201
+ custom_css = """
202
+ .gradio-container {
203
+ background: #FFFFFF;
204
+ min-height: 100vh;
205
+ }
206
+ """
207
+
208
+ # ===== JAVASCRIPT PARA OPTIMIZACIÓN DE CÁMARA =====
209
+ camera_js_improved = """
210
+ <script>
211
+ function initCameraOptimization() {
212
+ function ensureButtonsVisible() {
213
+ document.querySelectorAll('[data-testid="image"]').forEach(container => {
214
+ container.querySelectorAll('button').forEach(button => {
215
+ button.style.display = 'flex';
216
+ button.style.visibility = 'visible';
217
+ button.style.opacity = '1';
218
+ button.style.zIndex = '999';
219
+ });
220
+ });
221
+ }
222
+ ensureButtonsVisible();
223
+ setInterval(ensureButtonsVisible, 5000);
224
+ }
225
+ if (document.readyState === 'loading') {
226
+ document.addEventListener('DOMContentLoaded', initCameraOptimization);
227
+ } else {
228
+ initCameraOptimization();
229
+ }
230
+ </script>
231
+ """
232
+
233
+ # ===== APLICACIÓN PRINCIPAL =====
234
+ load_model()
235
+ img3_b64 = image_to_base64("img3.png")
236
+ img2_b64 = image_to_base64("img2.png")
237
+
238
+ with gr.Blocks(theme=gr.themes.Soft(), css=custom_css, title="🌸 Flower ") as demo:
239
+ header_html = f'''
240
+ <div style="background: rgba(37, 58, 105); border-radius: 16px; padding: 16px; margin-bottom: 24px; border: 1px solid #e5e7eb; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); max-width: 1024px; margin-left: auto; margin-right: auto;">
241
+ <div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
242
+ {'<div style="flex-shrink: 0; width: 150px; height: 150px;"><img src="data:image/png;base64,' + img3_b64 + '" alt="Logo" style="width: 100%; height: 100%; object-fit: contain; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"></div>' if img3_b64 else '<div style="width: 80px; height: 80px;"></div>'}
243
+ <div style="text-align: center;">
244
+ <h1 style="color: #FFCC00; font-size: 24px; font-weight: bold; margin-bottom: 4px;">IDENTIFICADOR DE FLORES</h1>
245
+ <p style="color: #FFFFFF; font-weight: 500; font-size: 14px; margin-bottom: 4px;">Identifica cualquier flor en cuestión de segundos</p>
246
+ <p style="color: #22c55e; font-size: 12px;">Oxford 102 Flowers + PlantNet</p>
247
+ </div>
248
+ {'<div style="flex-shrink: 0; width: 150px; height: 150px;"><img src="data:image/png;base64,' + img2_b64 + '" alt="Logo" style="width: 100%; height: 100%; object-fit: contain; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"></div>' if img2_b64 else '<div style="width: 48px; height: 48px;"></div>'}
249
+ </div>
250
+ </div>
251
+ '''
252
+ gr.HTML(header_html)
253
+
254
+ with gr.Row():
255
+ with gr.Column(scale=1):
256
+ image_input = gr.Image(type="pil", label="📷 Cargar Imagen de Flor", height=350, sources=["upload", "webcam", "clipboard"])
257
+ predict_btn = gr.Button("🔍 Identificar Flor", variant="primary")
258
+ gr.HTML(f'<div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]"><h3 class="text-yellow-400 font-bold text-xl">📊 Estado del Sistema</h3><p class="text-white">Modelo: {"✅ Activo" if MODEL_LOADED else "❌ Error"}</p><p class="text-white">Clases: {len(labels)}</p></div>')
259
+
260
+ with gr.Column(scale=1):
261
+ result_label = gr.Textbox(label="🌼 Flor Identificada", interactive=False, placeholder="El nombre de la flor aparecerá aquí...")
262
+ result_conf = gr.Textbox(label="📊 Confianza", interactive=False, placeholder="El nivel de confianza aparecerá aquí...")
263
+ flower_info_output = gr.HTML(value='<div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]"><h3 class="text-yellow-400 font-bold text-xl">🌸 ¡Bienvenido!</h3><p class="text-white">Carga una imagen de una flor para iniciar la identificación.</p></div>')
264
+
265
+ predict_btn.click(fn=predict, inputs=image_input, outputs=[result_label, result_conf, flower_info_output])
266
+ gr.HTML(camera_js_improved)
267
+
268
+ if __name__ == "__main__":
269
+ demo.launch(share=False)
clases_orden_oxford.json ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pink_primrose": 0,
3
+ "hard_leaved_pocket_orchid": 1,
4
+ "canterbury_bells": 2,
5
+ "sweet_pea": 3,
6
+ "english_marigold": 4,
7
+ "tiger_lily": 5,
8
+ "moon_orchid": 6,
9
+ "bird_of_paradise": 7,
10
+ "monkshood": 8,
11
+ "globe_thistle": 9,
12
+ "snapdragon": 10,
13
+ "colt's_foot": 11,
14
+ "king_protea": 12,
15
+ "spear_thistle": 13,
16
+ "yellow_iris": 14,
17
+ "globe_flower": 15,
18
+ "purple_coneflower": 16,
19
+ "peruvian_lily": 17,
20
+ "balloon_flower": 18,
21
+ "giant_white_arum_lily": 19,
22
+ "fire_lily": 20,
23
+ "pincushion_flower": 21,
24
+ "fritillary": 22,
25
+ "red_ginger": 23,
26
+ "grape_hyacinth": 24,
27
+ "corn_poppy": 25,
28
+ "prince_of_wales_feathers": 26,
29
+ "stemless_gentian": 27,
30
+ "artichoke": 28,
31
+ "sweet_william": 29,
32
+ "carnation": 30,
33
+ "garden_phlox": 31,
34
+ "love_in_the_mist": 32,
35
+ "mexican_aster": 33,
36
+ "alpine_sea_holly": 34,
37
+ "ruby_lipped_cattleya": 35,
38
+ "cape_flower": 36,
39
+ "great_masterwort": 37,
40
+ "siam_tulip": 38,
41
+ "lenten_rose": 39,
42
+ "barberton_daisy": 40,
43
+ "daffodil": 41,
44
+ "sword_lily": 42,
45
+ "poinsettia": 43,
46
+ "bolero_deep_blue": 44,
47
+ "wallflower": 45,
48
+ "marigold": 46,
49
+ "buttercup": 47,
50
+ "oxeye_daisy": 48,
51
+ "common_dandelion": 49,
52
+ "petunia": 50,
53
+ "wild_pansy": 51,
54
+ "primula": 52,
55
+ "sunflower": 53,
56
+ "pelargonium": 54,
57
+ "bishop_of_llandaff": 55,
58
+ "gaura": 56,
59
+ "geranium": 57,
60
+ "orange_dahlia": 58,
61
+ "pink_yellow_dahlia": 59,
62
+ "cautleya_spicata": 60,
63
+ "japanese_anemone": 61,
64
+ "black_eyed_susan": 62,
65
+ "silverbush": 63,
66
+ "californian_poppy": 64,
67
+ "osteospermum": 65,
68
+ "spring_crocus": 66,
69
+ "bearded_iris": 67,
70
+ "windflower": 68,
71
+ "tree_poppy": 69,
72
+ "gazania": 70,
73
+ "azalea": 71,
74
+ "water_lily": 72,
75
+ "rose": 73,
76
+ "thorn_apple": 74,
77
+ "morning_glory": 75,
78
+ "passion_flower": 76,
79
+ "lotus": 77,
80
+ "toad_lily": 78,
81
+ "anthurium": 79,
82
+ "frangipani": 80,
83
+ "clematis": 81,
84
+ "hibiscus": 82,
85
+ "columbine": 83,
86
+ "desert_rose": 84,
87
+ "tree_mallow": 85,
88
+ "magnolia": 86,
89
+ "cyclamen": 87,
90
+ "watercress": 88,
91
+ "canna_lily": 89,
92
+ "hippeastrum": 90,
93
+ "bee_balm": 91,
94
+ "ball_moss": 92,
95
+ "foxglove": 93,
96
+ "bougainvillea": 94,
97
+ "camellia": 95,
98
+ "mallow": 96,
99
+ "mexican_petunia": 97,
100
+ "bromelia": 98,
101
+ "blanket_flower": 99,
102
+ "trumpet_creeper": 100,
103
+ "blackberry_lily": 101
104
+ }
flores_modelo (2).h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ab59a8c20162846def8e70234e6c01cfe8a99389b4b61d5b114b4286421a8e74
3
+ size 11136704
img2.png ADDED
img3.png ADDED

Git LFS Details

  • SHA256: c925a409ed5a03585ab8ea9c18bac0ec32fccaea104ed598f89ad85743252276
  • Pointer size: 131 Bytes
  • Size of remote file: 201 kB
package-lock.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "name": "demo-clasificador-flores",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {}
6
+ }