Loading...
Searching...
No Matches
yolo_dataset_internal.h
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 Artificial Intelligence Techniques, S.L. and Roberto López González
3
4#pragma once
5
7
9{
10
11
12inline float clamp_unit(const float value)
13{
14 return min(1.0f, max(0.0f, value));
15}
16
17inline void append_mosaic_boxes(span<const YoloDataset::Box> source,
18 const array<float, 2>& tile_origin,
19 const array<float, 2>& tile_size,
20 vector<YoloDataset::Box>& destination)
21{
22 // Intersect each interval with the source image before placing it in the
23 // mosaic. Work in source coordinates so clipping is independent of the tile.
24 const auto project_interval = [](float center, float length, float origin, float scale)
25 {
26 const float first = max(0.0f, center - length / 2.0f);
27 const float last = min(1.0f, center + length / 2.0f);
28 return pair{origin + (first + last) * scale / 2.0f, (last - first) * scale};
29 };
30
31 for (const YoloDataset::Box& box : source)
32 {
33 const auto horizontal = project_interval(box.x, box.w, tile_origin[0], tile_size[0]);
34 const auto vertical = project_interval(box.y, box.h, tile_origin[1], tile_size[1]);
35 if (horizontal.second < 1e-3f || vertical.second < 1e-3f) continue;
36 destination.push_back({box.class_id, horizontal.first, vertical.first,
37 horizontal.second, vertical.second});
38 }
39}
40
41#pragma pack(push, 1)
43{
44 char magic[8];
45 uint32_t version;
46 uint32_t height;
47 uint32_t width;
48 uint32_t channels;
49 uint64_t samples;
50 uint64_t record_bytes;
51 uint64_t sources_hash;
52 uint8_t pad[16];
53};
54
56{
57 char magic[8];
58 uint32_t version;
59 uint32_t grid_size;
62 uint64_t samples;
63 uint64_t target_floats;
64 uint64_t anchors_hash;
67};
68
70{
71 char magic[8];
72 uint32_t version;
73 uint32_t reserved;
74 uint64_t samples;
75 uint64_t total_boxes;
78 uint8_t pad[16];
79};
80
82{
83 int32_t class_id;
84 float x;
85 float y;
86 float w;
87 float h;
88};
89#pragma pack(pop)
90
91static_assert(sizeof(YoloImageCacheHeader) == 64);
92static_assert(sizeof(YoloTargetCacheHeader) == 64);
93static_assert(sizeof(YoloBoxesCacheHeader) == 64);
94static_assert(sizeof(YoloBoxRecord) == 20);
95
96constexpr uint32_t YOLO_CACHE_VERSION = 3;
97constexpr char YOLO_IMAGE_MAGIC[8] = {'O','P','E','N','N','Y','I','M'};
98constexpr char YOLO_TARGET_MAGIC[8] = {'O','P','E','N','N','Y','T','G'};
99constexpr char YOLO_BOXES_MAGIC[8] = {'O','P','E','N','N','Y','B','X'};
100inline float yolo_iou_wh(const array<float, 2>& box, const array<float, 2>& anchor)
101{
102 const float inter = min(box[0], anchor[0]) * min(box[1], anchor[1]);
103 const float area = box[0] * box[1] + anchor[0] * anchor[1] - inter;
104 return area > 0.0f ? inter / area : 0.0f;
105}
106inline Index best_anchor_for_box(const YoloDataset::Box& box,
107 const vector<array<float, 2>>& anchors)
108{
109 float best_iou = -1.0f;
110 Index best = 0;
111
112 for (Index i = 0; i < ssize(anchors); ++i)
113 {
114 const float iou = yolo_iou_wh({box.w, box.h}, anchors[size_t(i)]);
115 if (iou > best_iou)
116 {
117 best_iou = iou;
118 best = i;
119 }
120 }
121
122 return best;
123}
124inline Index grid_cell(float coordinate, Index grid)
125{
126 return min<Index>(grid - 1, max<Index>(0, Index(floor(coordinate * grid))));
127}
128
129inline void write_box_target(float* cell, const YoloDataset::Box& box,
130 Index grid, Index col, Index row, float objectness)
131{
132 cell[0] = box.x * grid - float(col);
133 cell[1] = box.y * grid - float(row);
134 cell[2] = box.w;
135 cell[3] = box.h;
136 cell[4] = objectness;
137 cell[5 + box.class_id] = 1.0f;
138}
139
141 const vector<array<float, 2>>& anchors,
142 Index grid, Index head_offset,
143 Index values_per_box, Index head_channels,
144 Index skip_anchor, float* target)
145{
146 for (Index j = 0; j < ssize(anchors); ++j)
147 {
148 if (j == skip_anchor) continue;
149 // YOLOv3 ignore rule: only anchors whose shape overlaps the box by at
150 // least 0.5 are masked. Written as "< 0.5 -> skip" so a NaN IoU still
151 // reaches the marking code.
152 if (yolo_iou_wh({box.w, box.h}, anchors[size_t(j)]) < 0.5f) continue;
153 const Index col = grid_cell(box.x, grid);
154 const Index row = grid_cell(box.y, grid);
155 const Index base = head_offset + (row * grid + col) * head_channels + j * values_per_box;
156 if (target[base + 4] < 0.5f)
157 target[base + 4] = -1.0f;
158 }
159}
160
162{
163 float iou = -1.0f;
164 size_t head = 0;
165 Index anchor = 0;
166};
167
169 const vector<vector<array<float, 2>>>& head_anchors)
170{
171 AnchorMatch match;
172 for (size_t i = 0; i < head_anchors.size(); ++i)
173 {
174 const vector<array<float, 2>>& anchors_h = head_anchors[i];
175 for (Index j = 0; j < ssize(anchors_h); ++j)
176 {
177 const float iou = yolo_iou_wh({box.w, box.h}, anchors_h[size_t(j)]);
178 if (iou > match.iou)
179 match = {iou, i, j};
180 }
181 }
182 return match;
183}
184
185inline void make_target(const vector<YoloDataset::Box>& boxes,
186 const vector<array<float, 2>>& anchors,
187 Index grid_size,
188 Index boxes_per_cell,
189 Index classes_number,
190 float* target)
191{
192 if (boxes_per_cell <= 0) return;
193
194 const Index values_per_box = 5 + classes_number;
195 const Index channels = boxes_per_cell * values_per_box;
196 fill_n(target, grid_size * grid_size * channels, 0.0f);
197
198 for (const auto& box : boxes)
199 {
200 throw_if(box.class_id < 0 || box.class_id >= classes_number,
201 "YOLO target contains class id {} outside the valid range 0..{}.",
202 box.class_id, classes_number - 1);
203
204 const Index col = grid_cell(box.x, grid_size);
205 const Index row = grid_cell(box.y, grid_size);
206 const Index anchor = best_anchor_for_box(box, anchors);
207 const float best_iou = yolo_iou_wh({box.w, box.h}, anchors[size_t(anchor)]);
208 const Index base = (row * grid_size + col) * channels + anchor * values_per_box;
209
210 write_box_target(target + base, box, grid_size, col, row,
211 max(best_iou, 0.5f));
212 mark_ignored_anchors(box, anchors, grid_size, 0,
213 values_per_box, channels, anchor, target);
214 }
215}
216
217inline void make_target_multi_scale(const vector<YoloDataset::Box>& boxes,
218 const vector<vector<array<float, 2>>>& head_anchors,
219 const vector<Index>& head_grid_sizes,
220 Index boxes_per_head,
221 Index classes_number,
222 float* target)
223{
224 const Index values_per_box = 5 + classes_number;
225 const Index head_channels = boxes_per_head * values_per_box;
226
227 Index total_floats = 0;
228 vector<Index> head_offsets(head_grid_sizes.size() + 1, 0);
229 for (size_t i = 0; i < head_grid_sizes.size(); ++i)
230 {
231 const Index head_floats = head_grid_sizes[i] * head_grid_sizes[i] * head_channels;
232 head_offsets[i + 1] = head_offsets[i] + head_floats;
233 total_floats += head_floats;
234 }
235 fill_n(target, total_floats, 0.0f);
236
237 for (const auto& box : boxes)
238 {
239 throw_if(box.class_id < 0 || box.class_id >= classes_number,
240 "YOLO target contains class id {} outside the valid range 0..{}.",
241 box.class_id, classes_number - 1);
242
243 const AnchorMatch best = best_anchor_across_heads(box, head_anchors);
244
245 const Index grid_h = head_grid_sizes[best.head];
246 const Index col = grid_cell(box.x, grid_h);
247 const Index row = grid_cell(box.y, grid_h);
248 const Index base = head_offsets[best.head]
249 + (row * grid_h + col) * head_channels
250 + best.anchor * values_per_box;
251
252 write_box_target(target + base, box, grid_h, col, row,
253 max(best.iou, 0.5f));
254
255 for (size_t i = 0; i < head_anchors.size(); ++i)
256 mark_ignored_anchors(box, head_anchors[i], head_grid_sizes[i], head_offsets[i],
257 values_per_box, head_channels,
258 i == best.head ? best.anchor : Index(-1), target);
259 }
260}
261
262inline void make_target_v8_gtlist(const vector<YoloDataset::Box>& boxes,
263 Index classes_number,
264 float* target)
265{
266 constexpr Index MAX_GT = YoloDataset::MAX_GT_BOXES;
267 fill_n(target, MAX_GT * 5, 0.0f);
268 const Index n = min<Index>(ssize(boxes), MAX_GT);
269 for (Index i = 0; i < n; ++i)
270 {
271 const auto& b = boxes[size_t(i)];
272 throw_if(b.class_id < 0 || b.class_id >= classes_number,
273 "YOLO target contains class id {} outside the valid range 0..{}.",
274 b.class_id, classes_number - 1);
275 target[i*5 + 0] = b.x;
276 target[i*5 + 1] = b.y;
277 target[i*5 + 2] = b.w;
278 target[i*5 + 3] = b.h;
279 target[i*5 + 4] = float(b.class_id + 1);
280 }
281}
282
283}
static constexpr Index MAX_GT_BOXES
Definition yolo_dataset.h:98
Definition yolo_dataset_internal.h:9
Index grid_cell(float coordinate, Index grid)
Definition yolo_dataset_internal.h:124
void mark_ignored_anchors(const YoloDataset::Box &box, const vector< array< float, 2 > > &anchors, Index grid, Index head_offset, Index values_per_box, Index head_channels, Index skip_anchor, float *target)
Definition yolo_dataset_internal.h:140
float clamp_unit(const float value)
Definition yolo_dataset_internal.h:12
constexpr char YOLO_IMAGE_MAGIC[8]
Definition yolo_dataset_internal.h:97
float yolo_iou_wh(const array< float, 2 > &box, const array< float, 2 > &anchor)
Definition yolo_dataset_internal.h:100
constexpr char YOLO_TARGET_MAGIC[8]
Definition yolo_dataset_internal.h:98
void write_box_target(float *cell, const YoloDataset::Box &box, Index grid, Index col, Index row, float objectness)
Definition yolo_dataset_internal.h:129
Index best_anchor_for_box(const YoloDataset::Box &box, const vector< array< float, 2 > > &anchors)
Definition yolo_dataset_internal.h:106
void append_mosaic_boxes(span< const YoloDataset::Box > source, const array< float, 2 > &tile_origin, const array< float, 2 > &tile_size, vector< YoloDataset::Box > &destination)
Definition yolo_dataset_internal.h:17
void make_target(const vector< YoloDataset::Box > &boxes, const vector< array< float, 2 > > &anchors, Index grid_size, Index boxes_per_cell, Index classes_number, float *target)
Definition yolo_dataset_internal.h:185
void make_target_multi_scale(const vector< YoloDataset::Box > &boxes, const vector< vector< array< float, 2 > > > &head_anchors, const vector< Index > &head_grid_sizes, Index boxes_per_head, Index classes_number, float *target)
Definition yolo_dataset_internal.h:217
AnchorMatch best_anchor_across_heads(const YoloDataset::Box &box, const vector< vector< array< float, 2 > > > &head_anchors)
Definition yolo_dataset_internal.h:168
constexpr char YOLO_BOXES_MAGIC[8]
Definition yolo_dataset_internal.h:99
constexpr uint32_t YOLO_CACHE_VERSION
Definition yolo_dataset_internal.h:96
void make_target_v8_gtlist(const vector< YoloDataset::Box > &boxes, Index classes_number, float *target)
Definition yolo_dataset_internal.h:262
Eigen::array< T, N > array
Definition tensor_types.h:736
void scale(const TensorView &, const TensorView &, const TensorView &, const TensorView &, const TensorView &, const TensorView &, float, float, TensorView &)
#define throw_if(condition,...)
Definition opennn_types.h:243
Definition yolo_dataset.h:60
float h
Definition yolo_dataset.h:65
Index class_id
Definition yolo_dataset.h:61
float w
Definition yolo_dataset.h:64
float y
Definition yolo_dataset.h:63
float x
Definition yolo_dataset.h:62
Definition yolo_dataset_internal.h:162
size_t head
Definition yolo_dataset_internal.h:164
float iou
Definition yolo_dataset_internal.h:163
Index anchor
Definition yolo_dataset_internal.h:165
Definition yolo_dataset_internal.h:82
float x
Definition yolo_dataset_internal.h:84
float y
Definition yolo_dataset_internal.h:85
int32_t class_id
Definition yolo_dataset_internal.h:83
float w
Definition yolo_dataset_internal.h:86
float h
Definition yolo_dataset_internal.h:87
Definition yolo_dataset_internal.h:70
uint64_t total_boxes
Definition yolo_dataset_internal.h:75
uint32_t reserved
Definition yolo_dataset_internal.h:73
uint64_t offsets_byte_offset
Definition yolo_dataset_internal.h:76
uint8_t pad[16]
Definition yolo_dataset_internal.h:78
char magic[8]
Definition yolo_dataset_internal.h:71
uint64_t boxes_byte_offset
Definition yolo_dataset_internal.h:77
uint64_t samples
Definition yolo_dataset_internal.h:74
uint32_t version
Definition yolo_dataset_internal.h:72
Definition yolo_dataset_internal.h:43
uint64_t samples
Definition yolo_dataset_internal.h:49
uint32_t height
Definition yolo_dataset_internal.h:46
uint64_t sources_hash
Definition yolo_dataset_internal.h:51
char magic[8]
Definition yolo_dataset_internal.h:44
uint64_t record_bytes
Definition yolo_dataset_internal.h:50
uint32_t width
Definition yolo_dataset_internal.h:47
uint8_t pad[16]
Definition yolo_dataset_internal.h:52
uint32_t channels
Definition yolo_dataset_internal.h:48
uint32_t version
Definition yolo_dataset_internal.h:45
Definition yolo_dataset_internal.h:56
uint64_t anchors_offset
Definition yolo_dataset_internal.h:65
uint64_t samples
Definition yolo_dataset_internal.h:62
uint64_t targets_offset
Definition yolo_dataset_internal.h:66
char magic[8]
Definition yolo_dataset_internal.h:57
uint64_t target_floats
Definition yolo_dataset_internal.h:63
uint32_t classes_number
Definition yolo_dataset_internal.h:61
uint32_t version
Definition yolo_dataset_internal.h:58
uint32_t grid_size
Definition yolo_dataset_internal.h:59
uint64_t anchors_hash
Definition yolo_dataset_internal.h:64
uint32_t boxes_per_cell
Definition yolo_dataset_internal.h:60