AsyncCoder-10 commited on
Commit
2231656
·
verified ·
1 Parent(s): d37cb51

Upload image-processing/object-detector.py

Browse files
Files changed (1) hide show
  1. image-processing/object-detector.py +149 -0
image-processing/object-detector.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from transformers import AutoImageProcessor, AutoModelForObjectDetection
3
+ from PIL import ImageDraw, ImageFont
4
+ import gradio as gr
5
+
6
+ # ---------------------------
7
+ # 1. Load model + processor once
8
+ # ---------------------------
9
+ # Loading outside the function means we download and initialize
10
+ # the model only at startup, not on every prediction.
11
+ MODEL_NAME = "facebook/detr-resnet-50"
12
+
13
+ # Processor: resizes/normalizes the image and converts detection outputs
14
+ # back into real pixel coordinates for the original image size.
15
+ processor = AutoImageProcessor.from_pretrained(MODEL_NAME)
16
+
17
+ # Model: DETR (DEtection TRansformer) - detects objects and draws boxes
18
+ # around them, along with a predicted label and confidence score.
19
+ model = AutoModelForObjectDetection.from_pretrained(MODEL_NAME)
20
+ model.eval() # inference mode - disables dropout etc.
21
+
22
+ # Automatically use GPU if available, otherwise fall back to CPU.
23
+ device = "cuda" if torch.cuda.is_available() else "cpu"
24
+ model.to(device)
25
+
26
+ # A small color palette to cycle through so each box gets a different color.
27
+ COLORS = [
28
+ "#e6194b",
29
+ "#3cb44b",
30
+ "#ffe119",
31
+ "#4363d8",
32
+ "#f58231",
33
+ "#911eb4",
34
+ "#46f0f0",
35
+ "#f032e6",
36
+ "#bcf60c",
37
+ "#fabebe",
38
+ ]
39
+
40
+
41
+ # ---------------------------
42
+ # 2. Define the detection logic
43
+ # ---------------------------
44
+ def detect_objects(image, confidence_threshold: float = 0.7):
45
+ """
46
+ Run object detection on the uploaded image and draw bounding boxes
47
+ around every object detected above the given confidence threshold.
48
+
49
+ Args:
50
+ image: A PIL image uploaded by the user.
51
+ confidence_threshold: Minimum confidence score (0-1) required
52
+ to keep a detected object.
53
+
54
+ Returns:
55
+ annotated: The image with bounding boxes drawn on it.
56
+ summary: A text list of detected objects and their confidence scores.
57
+ """
58
+ # Guard against no image being uploaded.
59
+ if image is None:
60
+ return None, "Please upload an image."
61
+
62
+ # Convert the PIL image into the tensor format DETR expects,
63
+ # and move it to the same device (CPU/GPU) as the model.
64
+ inputs = processor(images=image, return_tensors="pt").to(device)
65
+
66
+ # Run the model without tracking gradients (faster, less memory - we're not training).
67
+ with torch.no_grad():
68
+ outputs = model(**inputs)
69
+
70
+ # DETR predicts boxes in a normalized format; this converts them
71
+ # back to actual pixel coordinates based on the original image size.
72
+ # image.size is (width, height), but target_sizes expects (height, width).
73
+ target_sizes = torch.tensor([image.size[::-1]])
74
+
75
+ # Keep only detections whose confidence is above the threshold.
76
+ results = processor.post_process_object_detection(
77
+ outputs, target_sizes=target_sizes, threshold=confidence_threshold
78
+ )[0]
79
+
80
+ # Make a copy of the image so we can draw on it without changing the original.
81
+ annotated = image.convert("RGB").copy()
82
+ draw = ImageDraw.Draw(annotated)
83
+
84
+ detections = []
85
+ # results["scores"], ["labels"], and ["boxes"] are aligned lists -
86
+ # each index i refers to the same detected object.
87
+ for i, (score, label_id, box) in enumerate(
88
+ zip(results["scores"], results["labels"], results["boxes"])
89
+ ):
90
+ # box is [x_min, y_min, x_max, y_max] in pixel coordinates.
91
+ box = [round(coord, 1) for coord in box.tolist()]
92
+
93
+ # Convert the numeric label ID (e.g. 17) into a readable name (e.g. "cat").
94
+ label = model.config.id2label[label_id.item()]
95
+ confidence = round(score.item(), 3)
96
+
97
+ # Cycle through the color palette so each box looks distinct.
98
+ color = COLORS[i % len(COLORS)]
99
+
100
+ # Draw the bounding box rectangle and a text label above it.
101
+ draw.rectangle(box, outline=color, width=3)
102
+ draw.text((box[0], max(box[1] - 12, 0)), f"{label} ({confidence})", fill=color)
103
+
104
+ detections.append(f"{label}: {confidence}")
105
+
106
+ # Build a readable summary string, or a fallback message if nothing was found.
107
+ summary = (
108
+ "\n".join(detections)
109
+ if detections
110
+ else "No objects detected above the confidence threshold."
111
+ )
112
+ return annotated, summary
113
+
114
+
115
+ # ---------------------------
116
+ # 3. Build the web UI with Gradio
117
+ # ---------------------------
118
+ with gr.Blocks(title="Object Detector") as demo:
119
+ gr.Markdown("## Object Detector")
120
+ gr.Markdown("Powered by Hugging Face DETR (facebook/detr-resnet-50)")
121
+
122
+ with gr.Row():
123
+ # Left side: where the user uploads their image.
124
+ image_input = gr.Image(type="pil", label="Upload Image")
125
+ # Right side: the same image, but with boxes drawn on it.
126
+ image_output = gr.Image(type="pil", label="Detected Objects")
127
+
128
+ # Lets the user control how strict detection should be.
129
+ # Lower threshold = more (possibly less accurate) detections.
130
+ confidence_slider = gr.Slider(
131
+ minimum=0.1, maximum=0.95, value=0.7, step=0.05, label="Confidence Threshold"
132
+ )
133
+ detect_btn = gr.Button("Detect Objects")
134
+ detections_output = gr.Textbox(label="Detections", lines=6)
135
+
136
+ # Wire the button click to the detect_objects function:
137
+ # takes the image + slider value as input, and updates
138
+ # both the annotated image and the text summary.
139
+ detect_btn.click(
140
+ fn=detect_objects,
141
+ inputs=[image_input, confidence_slider],
142
+ outputs=[image_output, detections_output],
143
+ )
144
+
145
+ # ---------------------------
146
+ # 4. Start the web server
147
+ # ---------------------------
148
+ if __name__ == "__main__":
149
+ demo.launch()