@@ -54,6 +54,12 @@ if ImageVision.ortex_configured?() do
5454 @ num_classes 80
5555 @ default_min_score 0.5
5656
57+ # 10-colour high-contrast palette for `draw_bbox_with_labels/3`.
58+ @ default_palette ~w(
59+ #e6194b #3cb44b #4363d8 #f58231 #911eb4
60+ #42d4f4 #f032e6 #bfef45 #469990 #9a6324
61+ )
62+
5763 # Standard 80-class COCO labels in the order produced by the
5864 # HuggingFace RT-DETR `id2label` map. Baked at compile time so
5965 # the module works without `priv/` lookups.
@@ -155,8 +161,23 @@ if ImageVision.ortex_configured?() do
155161
156162 * `image` is the image upon which detection was run.
157163
158- * `options` is a keyword list of options. Currently unused;
159- accepted for forward compatibility.
164+ * `options` is a keyword list of options.
165+
166+ ### Options
167+
168+ * `:opacity` is the opacity of the label background, a float in
169+ `[0.0, 1.0]`. The default is `0.85`. Use `1.0` for fully
170+ opaque label backgrounds.
171+
172+ * `:stroke_width` is the bounding box stroke width in pixels.
173+ The default is `2`.
174+
175+ * `:font_size` is the label text size in pixels. The default
176+ is `13`.
177+
178+ * `:palette` is a list of CSS colour strings used to assign
179+ colours to labels. Cycles if there are more labels than
180+ colours. The default is a 10-colour high-contrast palette.
160181
161182 ### Returns
162183
@@ -174,14 +195,17 @@ if ImageVision.ortex_configured?() do
174195
175196 """
176197 @ spec draw_bbox_with_labels ( [ detection ( ) ] , Vimage . t ( ) , Keyword . t ( ) ) :: Vimage . t ( )
177- def draw_bbox_with_labels ( detections , % Vimage { } = image , _options \\ [ ] ) do
198+ def draw_bbox_with_labels ( detections , % Vimage { } = image , options \\ [ ] ) do
199+ opacity = Keyword . get ( options , :opacity , 0.85 )
200+ stroke_width = Keyword . get ( options , :stroke_width , 2 )
201+ font_size = Keyword . get ( options , :font_size , 13 )
202+ palette = Keyword . get ( options , :palette , @ default_palette )
203+
178204 width = Image . width ( image )
179205 height = Image . height ( image )
180206
181- palette = ~w(
182- #e6194b #3cb44b #4363d8 #f58231 #911eb4
183- #42d4f4 #f032e6 #bfef45 #469990 #9a6324
184- )
207+ label_height = font_size + 5
208+ text_baseline = font_size + 1
185209
186210 label_colors =
187211 detections
@@ -194,15 +218,16 @@ if ImageVision.ortex_configured?() do
194218 Enum . map ( detections , fn % { label: label , score: score , box: { x , y , w , h } } ->
195219 color = Map . fetch! ( label_colors , label )
196220 text = "#{ label } #{ Float . round ( score * 100 , 1 ) } %"
197- label_y = max ( 0 , y - 20 )
198- label_w = String . length ( text ) * 8 + 8
221+ label_y = max ( 0 , y - label_height )
222+ label_w = round ( String . length ( text ) * font_size * 0.55 ) + 8
199223
200224 """
201225 <rect x="#{ x } " y="#{ y } " width="#{ w } " height="#{ h } "
202- fill="none" stroke="#{ color } " stroke-width="2"/>
203- <rect x="#{ x } " y="#{ label_y } " width="#{ label_w } " height="20" fill="#{ color } "/>
204- <text x="#{ x + 4 } " y="#{ label_y + 14 } "
205- font-family="sans-serif" font-size="13" font-weight="bold" fill="white">#{ text } </text>
226+ fill="none" stroke="#{ color } " stroke-width="#{ stroke_width } "/>
227+ <rect x="#{ x } " y="#{ label_y } " width="#{ label_w } " height="#{ label_height } "
228+ fill="#{ color } " opacity="#{ opacity } "/>
229+ <text x="#{ x + 4 } " y="#{ label_y + text_baseline } "
230+ font-family="sans-serif" font-size="#{ font_size } " font-weight="bold" fill="white">#{ text } </text>
206231 """
207232 end )
208233 |> Enum . join ( )
0 commit comments