Skip to content

Commit de5652f

Browse files
Merge pull request #80 from StabRise/79-add-support-labels-for-yolo-onnxdetector
79 add support labels for yolo onnxdetector
2 parents d3039a8 + 9287d29 commit de5652f

7 files changed

Lines changed: 70 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
### 🚀 Features
44

55
- Added param 'returnEmpty' to [ImageCropBoxes](https://scaledp.stabrise.com/en/latest/image/image_crop_boxes.html) for avoid to have exceptions if no boxes are found
6+
- Added labels param to the [YoloOnnxDetector](https://scaledp.stabrise.com/en/latest/models/detectors/yolo_onnx_detector.html)
7+
- Improve displaying labels in [ImageDrawBoxes](https://scaledp.stabrise.com/en/latest/image/image_draw_boxes.html)
68

79
### 🐛 Bug Fixes
810

docs/source/models/detectors/yolo_onnx_detector.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ detected_df = detector.transform(input_df)
4747
| onlyRotated | bool | Return only rotated boxes | False |
4848
| model | str | Model identifier | (required) |
4949
| padding | int | Padding percent to expand detected boxes | 0 |
50+
| labels | list | List of class labels for detected objects | [] |
5051

5152
## Notes
5253
- The detector loads YOLO ONNX models from Hugging Face Hub or local path.
5354
- Supports batch and distributed processing with Spark.
5455
- Padding expands detected bounding boxes by a percentage.
56+
- The `labels` parameter allows you to specify custom class labels for the detected objects. If provided, detection results will use these labels instead of class indices.
5557
- Used as a base for specialized detectors (e.g., [**Face Detector**]
56-
(#FaceDetector), [**Signature Detector**](#SignatureDetector)).
57-
58+
(#FaceDetector), [**Signature Detector**](#SignatureDetector)).

scaledp/image/ImageDrawBoxes.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,33 @@ def draw_boxes(self, data, fill, img1):
179179
self.draw_box(box, color, fill, img1)
180180
text = self.getDisplayText(box)
181181
if text:
182+
tbox = list(
183+
img1.textbbox(
184+
(
185+
box.x,
186+
box.y - self.getTextSize() * 1.2 - self.getPadding(),
187+
),
188+
text,
189+
font_size=self.getTextSize(),
190+
),
191+
)
192+
tbox[3] = tbox[3] + self.getTextSize() / 4
193+
tbox[2] = tbox[2] + self.getTextSize() / 4
194+
tbox[0] = box.x - self.getPadding()
195+
tbox[1] = box.y - self.getTextSize() * 1.2 - self.getPadding()
196+
img1.rounded_rectangle(
197+
tbox,
198+
outline=color,
199+
radius=2,
200+
fill=color,
201+
)
182202
img1.text(
183203
(
184204
box.x,
185205
box.y - self.getTextSize() * 1.2 - self.getPadding(),
186206
),
187207
text,
188-
fill=color,
208+
fill="white",
189209
font_size=self.getTextSize(),
190210
)
191211

scaledp/models/detectors/FaceDetector.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ class FaceDetector(YoloOnnxDetector):
2424
"task": "detect",
2525
"onlyRotated": False,
2626
"model": "StabRise/face_detection",
27+
"labels": ["face"],
2728
},
2829
)

scaledp/models/detectors/SignatureDetector.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ class SignatureDetector(YoloOnnxDetector):
2222
"task": "detect",
2323
"onlyRotated": False,
2424
"model": "StabRise/signature_detection",
25+
"labels": ["signature"],
2526
},
2627
)

scaledp/models/detectors/YoloOnnxDetector.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
from scaledp.enums import Device
1313
from scaledp.models.detectors.BaseDetector import BaseDetector
1414
from scaledp.models.detectors.yolo.yolo import YOLO
15-
from scaledp.params import HasBatchSize, HasDevice
15+
from scaledp.params import HasBatchSize, HasDevice, HasLabels
1616
from scaledp.schemas.Box import Box
1717
from scaledp.schemas.DetectorOutput import DetectorOutput
1818

1919

20-
class YoloOnnxDetector(BaseDetector, HasDevice, HasBatchSize):
20+
class YoloOnnxDetector(BaseDetector, HasDevice, HasBatchSize, HasLabels):
2121
"""YOLO ONNX object detector."""
2222

2323
_model: ClassVar = {}
@@ -54,6 +54,7 @@ class YoloOnnxDetector(BaseDetector, HasDevice, HasBatchSize):
5454
"task": "detect",
5555
"onlyRotated": False,
5656
"padding": 0, # default padding percent
57+
"labels": [], # default empty labels
5758
},
5859
)
5960

@@ -82,7 +83,7 @@ def get_model(cls, params):
8283

8384
logging.info("Model downloaded")
8485

85-
detector = YOLO(model_path_final, params["scoreThreshold"])
86+
detector = YOLO(model_path_final, conf_thres=params["scoreThreshold"])
8687

8788
cls._model[model_path] = detector
8889
return cls._model[model_path]
@@ -102,7 +103,8 @@ def call_detector(cls, images, params):
102103
# Expand boxes by padding percent if provided
103104
pad_percent = int(params.get("padding", 0)) if params is not None else 0
104105
h_img, w_img = image_np.shape[:2]
105-
for box in raw_boxes:
106+
labels = params.get("labels", [])
107+
for i, box in enumerate(raw_boxes):
106108
# Assume box format is [x1, y1, x2, y2]
107109
if pad_percent and len(box) >= 4:
108110
x1, y1, x2, y2 = (
@@ -122,7 +124,14 @@ def call_detector(cls, images, params):
122124
expanded_box = [x1_new, y1_new, x2_new, y2_new]
123125
else:
124126
expanded_box = box
125-
boxes.append(Box.from_bbox(expanded_box))
127+
# Map class_id to label and get score
128+
label = (
129+
labels[class_ids[i]]
130+
if labels and class_ids[i] < len(labels)
131+
else str(class_ids[i])
132+
)
133+
score = scores[i] if scores is not None and i < len(scores) else 0.0
134+
boxes.append(Box.from_bbox(expanded_box, label=label, score=score))
126135
results_final.append(
127136
DetectorOutput(path=image_path, type="yolo", bboxes=boxes),
128137
)

scaledp/params.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,3 +827,31 @@ def getPropagateError(self) -> bool:
827827
def setPropagateError(self, value: bool) -> Any:
828828
"""Sets the value of :py:attr:`propagateError`."""
829829
return self._set(propagateError=value)
830+
831+
832+
class HasLabels(Params):
833+
"""
834+
Mixin for param labels: list of class labels.
835+
"""
836+
837+
labels: "Param[list[str]]" = Param(
838+
Params._dummy(),
839+
"labels",
840+
"List of the labels.",
841+
typeConverter=TypeConverters.toListString,
842+
)
843+
844+
def __init__(self) -> None:
845+
super(HasLabels, self).__init__()
846+
847+
def getLabels(self) -> list[str]:
848+
"""
849+
Gets the value of labels or its default value.
850+
"""
851+
return self.getOrDefault(self.labels)
852+
853+
def setLabels(self, value: list[str]) -> Any:
854+
"""
855+
Sets the value of :py:attr:`labels`.
856+
"""
857+
return self._set(labels=value)

0 commit comments

Comments
 (0)