Janiopi commited on
Commit
2b6099a
·
verified ·
1 Parent(s): cfe94cc

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +9 -35
  2. app.py +54 -131
  3. haarcascade_frontalcatface.xml +0 -0
  4. requirements.txt +5 -6
Dockerfile CHANGED
@@ -1,42 +1,16 @@
1
- # Use a Python base image with slim variant to reduce size
2
- FROM python:3.12-slim
3
-
4
- # Set environment variables
5
- ENV PYTHONDONTWRITEBYTECODE=1 \
6
- PYTHONUNBUFFERED=1 \
7
- PIP_NO_CACHE_DIR=1 \
8
- PIP_DISABLE_PIP_VERSION_CHECK=1 \
9
- TORCH_HOME=/tmp/.torch
10
-
11
- # Install system dependencies required for OpenCV
12
- RUN apt-get update && apt-get install -y --no-install-recommends \
13
- libgl1-mesa-glx \
14
- libglib2.0-0 \
15
- && rm -rf /var/lib/apt/lists/*
16
-
17
- # Set the working directory
18
  WORKDIR /code
19
 
20
- # Copy the requirements file
21
  COPY ./requirements.txt /code/requirements.txt
22
-
23
- # Install dependencies
24
  RUN pip install --no-cache-dir -r /code/requirements.txt
 
25
 
26
- # Copy the application code
27
- COPY . /code
28
-
29
- # Create a non-root user
30
- RUN groupadd -r appuser && useradd -r -g appuser appuser
31
-
32
- # Change ownership of /code to the non-root user
33
- RUN chown -R appuser:appuser /code
34
-
35
- # Switch to the non-root user
36
- USER appuser
37
 
38
- # Expose the port the app runs on
39
- EXPOSE 7860
40
 
41
- # Command to run the application
42
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ # Usa una imagen base de Python
2
+ FROM python:3.12.7
3
+ # Establece el directorio de trabajo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  WORKDIR /code
5
 
6
+ # Copia los archivos necesarios al contenedor
7
  COPY ./requirements.txt /code/requirements.txt
 
 
8
  RUN pip install --no-cache-dir -r /code/requirements.txt
9
+ RUN pip install fastapi uvicorn
10
 
11
+ COPY . .
 
 
 
 
 
 
 
 
 
 
12
 
13
+ RUN chmod -R 777 /code
 
14
 
15
+ # Comando para ejecutar la aplicación
16
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py CHANGED
@@ -1,144 +1,67 @@
1
  from fastapi import FastAPI, File, UploadFile, HTTPException, Query
 
 
 
 
2
  from PIL import Image
3
- from io import BytesIO
4
  import numpy as np
5
- import torch
6
- from torchvision.models import detection
7
- from torchvision.transforms import functional as F
8
- import gradio as gr
9
- from typing import List, Dict
10
 
11
- # FastAPI app
12
  app = FastAPI()
13
 
14
- # Make sure torch knows where to cache models
15
- import os
16
- os.environ['TORCH_HOME'] = '/tmp/.torch'
17
-
18
- # Load model with error handling
19
- try:
20
- # Use the new 'weights' parameter instead of 'pretrained'
21
- print("Loading object detection model...")
22
- model = detection.fasterrcnn_resnet50_fpn(weights="DEFAULT")
23
- model.eval()
24
- print("Model loaded successfully")
25
- except Exception as e:
26
- print(f"Error loading model: {e}")
27
- # Fallback to non-pretrained model if loading fails
28
- print("Attempting to load model without pretrained weights...")
29
- model = detection.fasterrcnn_resnet50_fpn(weights=None)
30
- model.eval()
31
- print("Using model without pretrained weights")
32
-
33
- # Load COCO class labels
34
- COCO_LABELS = [
35
- '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
36
- 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign',
37
- 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
38
- 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag',
39
- 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite',
40
- 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
41
- 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana',
42
- 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
43
- 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table',
44
- 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
45
- 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock',
46
- 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
47
- ]
48
-
49
- def predict_objects(image, target_label="book", confidence_threshold=0.5):
50
- """Predicts objects in the given image and filters for a specific label."""
51
- if image is None:
52
- return []
53
-
54
- # Convert to RGB if needed
55
- if image.mode != "RGB":
56
- image = image.convert("RGB")
57
 
58
- img_tensor = F.to_tensor(image).unsqueeze(0)
 
59
 
60
- with torch.no_grad():
61
- prediction = model(img_tensor)[0]
62
-
63
- detected_objects = []
64
- for i in range(len(prediction['labels'])):
65
- score = prediction['scores'][i].item()
66
- label_index = prediction['labels'][i].item()
67
- label = COCO_LABELS[label_index]
68
-
69
- # Check if score exceeds threshold and label matches target (if target is not empty)
70
- if score > confidence_threshold and (not target_label or label == target_label):
71
- bbox = [int(b) for b in prediction['boxes'][i].tolist()]
72
- detected_objects.append({'label': label, 'bbox': bbox, 'score': score})
73
-
74
- return detected_objects
 
 
 
 
 
 
 
75
 
76
  @app.post('/predict/')
77
- async def predict_api(file: UploadFile = File(...), target_label: str = Query("book")):
78
- """FastAPI endpoint to detect objects in an uploaded image."""
 
 
 
79
  try:
80
- image_bytes = await file.read()
81
- image = Image.open(BytesIO(image_bytes))
82
- predictions = predict_objects(image, target_label)
83
- return {"predictions": predictions}
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  except Exception as e:
85
  raise HTTPException(status_code=500, detail=str(e))
86
-
87
- def detect_objects(input_image, target_object="book", confidence=0.5):
88
- """Gradio interface function for object detection."""
89
- if input_image is None:
90
- return None, []
91
-
92
- # Process the image
93
- predictions = predict_objects(input_image, target_object, confidence)
94
-
95
- # Draw bounding boxes on the image
96
- img_with_boxes = input_image.copy()
97
- import numpy as np
98
- from PIL import ImageDraw
99
- draw = ImageDraw.Draw(img_with_boxes)
100
-
101
- results = []
102
- for obj in predictions:
103
- label = obj['label']
104
- score = obj['score']
105
- bbox = obj['bbox']
106
-
107
- # Draw rectangle
108
- draw.rectangle(bbox, outline="red", width=3)
109
-
110
- # Draw label
111
- text = f"{label}: {score:.2f}"
112
- draw.text((bbox[0], bbox[1] - 10), text, fill="red")
113
-
114
- # Format results for display
115
- results.append(f"{label}: {score:.2f} at position {bbox}")
116
-
117
- return img_with_boxes, results
118
-
119
- # Create Gradio interface
120
- demo = gr.Interface(
121
- fn=detect_objects,
122
- inputs=[
123
- gr.Image(type="pil", label="Upload Image"),
124
- gr.Dropdown(
125
- choices=COCO_LABELS[1:], # Skip background
126
- value="book",
127
- label="Target Object"
128
- ),
129
- gr.Slider(minimum=0.1, maximum=0.9, value=0.5, step=0.1, label="Confidence Threshold")
130
- ],
131
- outputs=[
132
- gr.Image(type="pil", label="Detection Result"),
133
- gr.JSON(label="Detected Objects")
134
- ],
135
- title="Object Detection API",
136
- description="Upload an image to detect objects. By default, we'll highlight books, but you can select any object type.",
137
- examples=[
138
- ["https://images.unsplash.com/photo-1507842217343-583bb7270b66?q=80&w=2670&auto=format&fit=crop", "book", 0.5],
139
- ["https://images.unsplash.com/photo-1524578271613-d550eacf6090?q=80&w=2670&auto=format&fit=crop", "book", 0.5],
140
- ]
141
- )
142
-
143
- # Mount FastAPI app to Gradio for compatibility with both
144
- app = gr.mount_gradio_app(app, demo, path="/")
 
1
  from fastapi import FastAPI, File, UploadFile, HTTPException, Query
2
+ from fastapi.responses import HTMLResponse
3
+ from pydantic import BaseModel
4
+ from typing import List
5
+ import cv2
6
  from PIL import Image
 
7
  import numpy as np
8
+ from io import BytesIO
 
 
 
 
9
 
 
10
  app = FastAPI()
11
 
12
+ def detect_cat(image, draw_rectangles=False):
13
+ existe = "NO"
14
+ print("resultado: ", image.shape)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ # Load the cat face cascade classifier
17
+ cat_cascade = cv2.CascadeClassifier('haarcascade_frontalcatface.xml')
18
 
19
+ # Convert to grayscale
20
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
21
+
22
+ # Detect cat faces
23
+ cats = cat_cascade.detectMultiScale(
24
+ gray,
25
+ scaleFactor=1.1,
26
+ minNeighbors=3,
27
+ minSize=(30, 30)
28
+ )
29
+
30
+ # Draw rectangles around detected cats if requested
31
+ if draw_rectangles:
32
+ for (x, y, w, h) in cats:
33
+ cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
34
+
35
+ # Return more detailed information
36
+ return {
37
+ "found": "SI" if len(cats) > 0 else "NO",
38
+ "count": len(cats),
39
+ "locations": cats.tolist() if len(cats) > 0 else []
40
+ }
41
 
42
  @app.post('/predict/')
43
+ async def predict(
44
+ file: UploadFile = File(...),
45
+ tipo: str = Query(...),
46
+ draw_boxes: bool = Query(False)
47
+ ):
48
  try:
49
+ image = Image.open(BytesIO(await file.read()))
50
+ image = np.asarray(image)
51
+ prediction = detect_cat(image, draw_rectangles=draw_boxes)
52
+
53
+ if draw_boxes:
54
+ # Convert back to PIL Image and then to bytes
55
+ result_image = Image.fromarray(image)
56
+ img_byte_arr = BytesIO()
57
+ result_image.save(img_byte_arr, format='PNG')
58
+ img_byte_arr = img_byte_arr.getvalue()
59
+
60
+ return {
61
+ "prediction": prediction,
62
+ "image": img_byte_arr
63
+ }
64
+
65
+ return {"prediction": prediction}
66
  except Exception as e:
67
  raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
haarcascade_frontalcatface.xml ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt CHANGED
@@ -1,8 +1,7 @@
1
  fastapi
2
- uvicorn
3
- Pillow
4
- opencv-python
5
- torch
6
- torchvision
7
- gradio>=5.29.0
8
  python-multipart
 
 
1
  fastapi
2
+ numpy
3
+ pydantic
4
+ opencv-python-headless
5
+ uvicorn[standard]
 
 
6
  python-multipart
7
+ pillow