Penthes commited on
Commit
72977d0
·
verified ·
1 Parent(s): f3936b5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -52
app.py CHANGED
@@ -164,7 +164,7 @@ def preprocess_image(image_data):
164
  image = Image.open(io.BytesIO(image_data)).convert("RGB")
165
 
166
  # Crop (x1=450, y1=400, x2=1090, y2=1060)
167
- crop_box = (450, 140, 1090, 800) # (left, top, right, bottom)
168
  image = image.crop(crop_box)
169
 
170
  # Resize to model input size
@@ -186,8 +186,7 @@ def preprocess_image(image_data):
186
 
187
  def preprocess_image_test(image_data):
188
  """
189
- Preprocess image to match training pipeline:
190
- - Crop ROI from ESP32 frame (400x296)
191
  - Resize to 224x224
192
  - Convert to numpy array, add batch dim
193
  """
@@ -195,7 +194,7 @@ def preprocess_image_test(image_data):
195
  # Convert bytes to PIL Image
196
  image = Image.open(io.BytesIO(image_data)).convert("RGB")
197
 
198
- # Resize to model input size
199
  image = image.resize((224, 224), Image.Resampling.LANCZOS)
200
 
201
  # Normalize and expand dims
@@ -204,7 +203,6 @@ def preprocess_image_test(image_data):
204
  # Add batch dimension
205
  image = np.expand_dims(image, axis=0)
206
 
207
-
208
  # Model has Rescaling(1./255) layer, so no manual normalization
209
  return image
210
 
@@ -212,6 +210,7 @@ def preprocess_image_test(image_data):
212
  logger.error(f"Image preprocessing error: {e}")
213
  raise HTTPException(status_code=400, detail=f"Image preprocessing failed: {e}")
214
 
 
215
  @app.get("/health")
216
  async def health_check():
217
  """Health check endpoint"""
@@ -240,6 +239,7 @@ async def health_check():
240
  "model_loaded": model is not None,
241
  "classes": class_labels
242
  }
 
243
  @app.on_event("startup")
244
  async def startup_event():
245
  """Load model on startup"""
@@ -314,6 +314,57 @@ async def classify_image(file: UploadFile = File(...)):
314
  content={"error": f"Classification failed: {str(e)}"}
315
  )
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  @app.post("/classify/detailed")
318
  async def classify_detailed(file: UploadFile = File(...)):
319
  """
@@ -356,53 +407,6 @@ async def classify_detailed(file: UploadFile = File(...)):
356
  logger.error(f"Detailed classification error: {str(e)}")
357
  raise HTTPException(status_code=500, detail=f"Classification failed: {str(e)}")
358
 
359
- @app.post("/classify_test")
360
- async def classify_image(file: UploadFile = File(...)):
361
- """
362
- Main classification endpoint for ESP32
363
-
364
- Expected usage:
365
- curl -X POST -F "file=@image.jpg" https://your-space-url.hf.space/classify_test
366
-
367
- Returns:
368
- JSON: {"label": "plastic"} or {"error": "message"}
369
- """
370
- try:
371
- # Validate file type
372
- if not file.content_type or not file.content_type.startswith('image/'):
373
- logger.warning(f"Invalid file type: {file.content_type}")
374
- raise HTTPException(status_code=400, detail="File must be an image")
375
-
376
- # Read image data
377
- image_data = await file.read()
378
- if len(image_data) == 0:
379
- raise HTTPException(status_code=400, detail="Empty image file")
380
-
381
- logger.info(f"Processing image: {file.filename}, size: {len(image_data)} bytes")
382
-
383
- # Preprocess image
384
- processed_image = preprocess_image_test(image_data)
385
-
386
- # Make prediction
387
- predictions = model.predict(processed_image, verbose=0)
388
- predicted_class_index = np.argmax(predictions[0])
389
- predicted_class = class_labels[predicted_class_index]
390
- confidence = float(predictions[0][predicted_class_index])
391
-
392
- logger.info(f"Prediction: {predicted_class} (confidence: {confidence:.3f})")
393
-
394
- # Return simple response for ESP32 - match your ESP32 expectation exactly
395
- return {"label": predicted_class.capitalize()} # Capitalize to match your ESP32 labels
396
-
397
- except HTTPException:
398
- raise
399
- except Exception as e:
400
- logger.error(f"Classification error: {str(e)}")
401
- return JSONResponse(
402
- status_code=500,
403
- content={"error": f"Classification failed: {str(e)}"}
404
- )
405
-
406
  @app.get("/info")
407
  async def get_info():
408
  """API information endpoint"""
 
164
  image = Image.open(io.BytesIO(image_data)).convert("RGB")
165
 
166
  # Crop (x1=450, y1=400, x2=1090, y2=1060)
167
+ crop_box = (450, 400, 1090, 1060)
168
  image = image.crop(crop_box)
169
 
170
  # Resize to model input size
 
186
 
187
  def preprocess_image_test(image_data):
188
  """
189
+ Preprocess image WITHOUT cropping for testing:
 
190
  - Resize to 224x224
191
  - Convert to numpy array, add batch dim
192
  """
 
194
  # Convert bytes to PIL Image
195
  image = Image.open(io.BytesIO(image_data)).convert("RGB")
196
 
197
+ # Resize to model input size (NO CROPPING)
198
  image = image.resize((224, 224), Image.Resampling.LANCZOS)
199
 
200
  # Normalize and expand dims
 
203
  # Add batch dimension
204
  image = np.expand_dims(image, axis=0)
205
 
 
206
  # Model has Rescaling(1./255) layer, so no manual normalization
207
  return image
208
 
 
210
  logger.error(f"Image preprocessing error: {e}")
211
  raise HTTPException(status_code=400, detail=f"Image preprocessing failed: {e}")
212
 
213
+
214
  @app.get("/health")
215
  async def health_check():
216
  """Health check endpoint"""
 
239
  "model_loaded": model is not None,
240
  "classes": class_labels
241
  }
242
+
243
  @app.on_event("startup")
244
  async def startup_event():
245
  """Load model on startup"""
 
314
  content={"error": f"Classification failed: {str(e)}"}
315
  )
316
 
317
+ @app.post("/classify_test")
318
+ async def classify_image_test(file: UploadFile = File(...)): # CHANGED FUNCTION NAME
319
+ """
320
+ Test classification endpoint WITHOUT cropping
321
+
322
+ Expected usage:
323
+ curl -X POST -F "file=@image.jpg" https://your-space-url.hf.space/classify_test
324
+
325
+ Returns:
326
+ JSON: {"label": "plastic"} or {"error": "message"}
327
+ """
328
+ try:
329
+ # Validate file type
330
+ if not file.content_type or not file.content_type.startswith('image/'):
331
+ logger.warning(f"Invalid file type: {file.content_type}")
332
+ raise HTTPException(status_code=400, detail="File must be an image")
333
+
334
+ # Read image data
335
+ image_data = await file.read()
336
+ if len(image_data) == 0:
337
+ raise HTTPException(status_code=400, detail="Empty image file")
338
+
339
+ logger.info(f"TEST MODE - Processing image: {file.filename}, size: {len(image_data)} bytes")
340
+
341
+ # Preprocess image WITHOUT cropping
342
+ processed_image = preprocess_image_test(image_data)
343
+
344
+ # Make prediction
345
+ predictions = model.predict(processed_image, verbose=0)
346
+ predicted_class_index = np.argmax(predictions[0])
347
+ predicted_class = class_labels[predicted_class_index]
348
+ confidence = float(predictions[0][predicted_class_index])
349
+
350
+ logger.info(f"TEST MODE - Prediction: {predicted_class} (confidence: {confidence:.3f})")
351
+
352
+ # Return simple response for ESP32 - match your ESP32 expectation exactly
353
+ return {
354
+ "label": predicted_class.capitalize(),
355
+ "confidence": round(confidence, 3),
356
+ "mode": "test_no_crop"
357
+ }
358
+
359
+ except HTTPException:
360
+ raise
361
+ except Exception as e:
362
+ logger.error(f"Classification error: {str(e)}")
363
+ return JSONResponse(
364
+ status_code=500,
365
+ content={"error": f"Classification failed: {str(e)}"}
366
+ )
367
+
368
  @app.post("/classify/detailed")
369
  async def classify_detailed(file: UploadFile = File(...)):
370
  """
 
407
  logger.error(f"Detailed classification error: {str(e)}")
408
  raise HTTPException(status_code=500, detail=f"Classification failed: {str(e)}")
409
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  @app.get("/info")
411
  async def get_info():
412
  """API information endpoint"""