(mask, origin_x, origin_y, expected_count)
| 325 | if len(comps) >= expected_count: |
| 326 | comps = sorted(comps, key=lambda c: c['bbox'][0] if horizontal else c['bbox'][1]) |
| 327 | if len(comps) > expected_count: |
| 328 | comps = sorted(comps, key=lambda c: c['area'], reverse=True)[:expected_count] |
| 329 | comps = sorted(comps, key=lambda c: c['bbox'][0] if horizontal else c['bbox'][1]) |
| 330 | |
| 331 | boxes = [] |
| 332 | for comp in comps: |
| 333 | x, y, cw, ch = comp['bbox'] |
| 334 | boxes.append((origin_x + x, origin_y + y, cw, ch)) |
| 335 | return boxes |
| 336 | |
| 337 | axis = 0 if horizontal else 1 |
| 338 | projection = mask.sum(axis=axis).astype(np.float32) / 255.0 |
| 339 | projection = smooth_projection(projection, window=5) |
| 340 | if projection.size == 0: |
| 341 | return [] |
| 342 | |
| 343 | threshold = max(1.0, float(projection.max()) * 0.12) |
| 344 | active = projection >= threshold |
| 345 | runs = [run for run in contiguous_runs(active) if (run[1] - run[0]) >= 2] |
| 346 | |
| 347 | boxes = [] |
| 348 | if len(runs) >= expected_count: |
| 349 | chosen_runs = runs[:expected_count] |
| 350 | for start, end in chosen_runs: |
| 351 | if horizontal: |
| 352 | part = mask[:, start:end] |
| 353 | bbox = bbox_from_mask(part) |
| 354 | if bbox is None: |
| 355 | boxes.append((origin_x + start, origin_y, max(1, end - start), h)) |
| 356 | else: |
| 357 | x, y, pw, ph = bbox |
| 358 | boxes.append((origin_x + start + x, origin_y + y, pw, ph)) |
| 359 | else: |
| 360 | part = mask[start:end, :] |
| 361 | bbox = bbox_from_mask(part) |
| 362 | if bbox is None: |
| 363 | boxes.append((origin_x, origin_y + start, w, max(1, end - start))) |
| 364 | else: |
| 365 | x, y, pw, ph = bbox |
| 366 | boxes.append((origin_x + x, origin_y + start + y, pw, ph)) |
| 367 | return boxes |
| 368 | |
| 369 | if horizontal: |
| 370 | edges = np.linspace(0, w, expected_count + 1).astype(int) |
| 371 | for idx in range(expected_count): |
| 372 | start, end = edges[idx], edges[idx + 1] |
| 373 | part = mask[:, start:end] |
| 374 | bbox = bbox_from_mask(part) |
| 375 | if bbox is None: |
| 376 | boxes.append((origin_x + start, origin_y, max(1, end - start), h)) |
| 377 | else: |
| 378 | x, y, pw, ph = bbox |
| 379 | boxes.append((origin_x + start + x, origin_y + y, pw, ph)) |
| 380 | else: |
| 381 | edges = np.linspace(0, h, expected_count + 1).astype(int) |
| 382 | for idx in range(expected_count): |
| 383 | start, end = edges[idx], edges[idx + 1] |
| 384 | part = mask[start:end, :] |
no test coverage detected