|
28 | 28 | from albumentations.core.composition import BboxParams, Compose, ReplayCompose
|
29 | 29 | from albumentations.core.transforms_interface import BasicTransform, NoOp
|
30 | 30 |
|
| 31 | +from albumentations.augmentations.dropout.functional import resize_boxes_to_visible_area |
| 32 | + |
| 33 | + |
31 | 34 |
|
32 | 35 | @pytest.mark.parametrize(
|
33 | 36 | "bboxes, image_shape, expected",
|
@@ -2388,3 +2391,82 @@ def test_compose_max_accept_ratio_all_formats(bbox_format, bboxes, shape, max_ac
|
2388 | 2391 |
|
2389 | 2392 | result = transform(**data)
|
2390 | 2393 | np.testing.assert_array_almost_equal(result["bboxes"], expected, decimal=5)
|
| 2394 | + |
| 2395 | + |
| 2396 | +def test_resize_boxes_to_visible_area_removes_fully_covered_boxes(): |
| 2397 | + """Test that resize_boxes_to_visible_area removes boxes with zero visible area.""" |
| 2398 | + # Create bounding boxes with additional columns for encoded labels |
| 2399 | + # Format: [x_min, y_min, x_max, y_max, encoded_label_1, encoded_label_2] |
| 2400 | + boxes = np.array([ |
| 2401 | + [10, 10, 30, 30, 1, 2], # Box 1 with encoded labels 1, 2 - will be fully covered |
| 2402 | + [40, 40, 60, 60, 3, 4], # Box 2 with encoded labels 3, 4 - will remain visible |
| 2403 | + ], dtype=np.float32) |
| 2404 | + |
| 2405 | + # Create a hole mask that completely covers the first box |
| 2406 | + hole_mask = np.zeros((100, 100), dtype=np.uint8) |
| 2407 | + hole_mask[10:30, 10:30] = 1 # Fully cover first box |
| 2408 | + |
| 2409 | + # Update boxes using the function |
| 2410 | + updated_boxes = resize_boxes_to_visible_area(boxes, hole_mask) |
| 2411 | + |
| 2412 | + # Assertions |
| 2413 | + assert len(updated_boxes) == 1, "Should remove fully covered boxes" |
| 2414 | + assert updated_boxes.shape == (1, 6), "Should preserve the shape with correct number of columns" |
| 2415 | + |
| 2416 | + # The remaining box should be the second one |
| 2417 | + np.testing.assert_array_equal(updated_boxes[0, :4], boxes[1, :4], "Second box coordinates should be unchanged") |
| 2418 | + assert updated_boxes[0, 4] == 3, "Second box should preserve first encoded label" |
| 2419 | + assert updated_boxes[0, 5] == 4, "Second box should preserve second encoded label" |
| 2420 | + |
| 2421 | +def test_resize_boxes_to_visible_area_with_partially_covered_boxes(): |
| 2422 | + """Test that resize_boxes_to_visible_area correctly handles partially covered boxes.""" |
| 2423 | + # Create bounding boxes with additional columns for encoded labels |
| 2424 | + boxes = np.array([ |
| 2425 | + [10, 10, 30, 30, 1, 2], # Box that will be partially covered |
| 2426 | + ], dtype=np.float32) |
| 2427 | + |
| 2428 | + # Create a hole mask that covers the left half of the box |
| 2429 | + hole_mask = np.zeros((100, 100), dtype=np.uint8) |
| 2430 | + hole_mask[10:30, 10:20] = 1 # Cover left half of the box |
| 2431 | + |
| 2432 | + # Update boxes using the function |
| 2433 | + updated_boxes = resize_boxes_to_visible_area(boxes, hole_mask) |
| 2434 | + |
| 2435 | + # Assertions |
| 2436 | + assert len(updated_boxes) == 1, "Should keep partially covered boxes" |
| 2437 | + assert updated_boxes.shape == (1, 6), "Should preserve the shape with correct number of columns" |
| 2438 | + assert updated_boxes[0, 0] > boxes[0, 0], "X min should increase (left part covered)" |
| 2439 | + assert updated_boxes[0, 2] == boxes[0, 2], "X max should remain the same" |
| 2440 | + assert updated_boxes[0, 4] == 1, "Should preserve first encoded label" |
| 2441 | + assert updated_boxes[0, 5] == 2, "Should preserve second encoded label" |
| 2442 | + |
| 2443 | +def test_resize_boxes_to_visible_area_with_all_boxes_covered(): |
| 2444 | + """Test that resize_boxes_to_visible_area returns empty array when all boxes are covered.""" |
| 2445 | + # Create bounding boxes with additional columns |
| 2446 | + boxes = np.array([ |
| 2447 | + [10, 10, 30, 30, 1, 2], # Box that will be fully covered |
| 2448 | + ], dtype=np.float32) |
| 2449 | + |
| 2450 | + # Create a hole mask that completely covers the box |
| 2451 | + hole_mask = np.zeros((100, 100), dtype=np.uint8) |
| 2452 | + hole_mask[10:30, 10:30] = 1 # Fully cover the box |
| 2453 | + |
| 2454 | + # Update boxes using the function |
| 2455 | + updated_boxes = resize_boxes_to_visible_area(boxes, hole_mask) |
| 2456 | + |
| 2457 | + # Assertions |
| 2458 | + assert len(updated_boxes) == 0, "Should return empty array when all boxes are covered" |
| 2459 | + assert updated_boxes.shape == (0, 6), "Empty array should have correct shape with all columns" |
| 2460 | + |
| 2461 | +def test_resize_boxes_to_visible_area_with_empty_input(): |
| 2462 | + """Test that resize_boxes_to_visible_area handles empty input correctly.""" |
| 2463 | + # Empty boxes array with correct shape (0 boxes, 6 columns) |
| 2464 | + boxes = np.zeros((0, 6), dtype=np.float32) |
| 2465 | + hole_mask = np.zeros((100, 100), dtype=np.uint8) |
| 2466 | + |
| 2467 | + # Update boxes using the function |
| 2468 | + updated_boxes = resize_boxes_to_visible_area(boxes, hole_mask) |
| 2469 | + |
| 2470 | + # Assertions |
| 2471 | + assert len(updated_boxes) == 0, "Should return empty array" |
| 2472 | + assert updated_boxes.shape == (0, 6), "Should preserve the shape with correct number of columns" |
0 commit comments