Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Dec 4, 2025

📄 12% (0.12x) speedup for _extract_segmentation_annotation in ultralytics/utils/callbacks/comet.py

⏱️ Runtime : 1.74 milliseconds 1.56 milliseconds (best of 250 runs)

📝 Explanation and details

The optimized code achieves an 11% speedup by replacing inefficient list comprehensions with a single explicit loop and using more direct array operations.

Key optimizations applied:

  1. Eliminated double list comprehensions: The original code used two chained list comprehensions that created intermediate arrays and lists. The optimized version uses a single loop that processes each polygon once.

  2. Replaced np.array().squeeze().ravel() with reshape(-1): The original approach unnecessarily copied data and performed multiple array transformations. Since cv2.findContours already returns numpy arrays, reshape(-1) directly flattens them without copying when possible.

  3. Pre-allocated output list: Instead of building intermediate lists through comprehensions, the optimized version directly appends to a pre-allocated result list, reducing memory allocations.

Why this leads to speedup:

  • Reduced array copying: reshape(-1) avoids the copy operations inherent in np.array().squeeze().ravel()
  • Fewer temporary objects: Single loop eliminates intermediate lists created by chained comprehensions
  • Better memory locality: Direct appending to output list reduces memory fragmentation

Performance impact based on test results:
The optimization shows the most significant gains (15-25% speedup) for cases with multiple polygons, such as masks with many small shapes or complex segmentation scenarios. Even simple single-polygon cases see 12-22% improvements. The function is called from _format_prediction_annotations during YOLO prediction processing, where segmentation masks are converted for visualization - making this optimization valuable for real-time inference pipelines processing many segmented objects.

Best performance gains observed in:

  • Multiple polygon scenarios (15-25% faster)
  • Large masks with many small shapes (21-24% faster)
  • Complex shapes and irregular polygons (13-22% faster)

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 40 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import cv2
import numpy as np

# imports
from ultralytics.utils.callbacks.comet import _extract_segmentation_annotation

# function to test
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license


class DummyLogger:
    def __init__(self):
        self.messages = []

    def warning(self, msg):
        self.messages.append(msg)


LOGGER = DummyLogger()

# unit tests

# ---- Basic Test Cases ----


def test_single_square_polygon():
    # Test with a simple square mask
    def decode(raw):
        # 10x10 mask, square in center
        mask = np.zeros((10, 10), dtype=np.uint8)
        mask[3:7, 3:7] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 20.5μs -> 16.7μs (22.9% faster)


def test_multiple_polygons():
    # Test with two separate squares
    def decode(raw):
        mask = np.zeros((10, 10), dtype=np.uint8)
        mask[1:4, 1:4] = 255
        mask[6:9, 6:9] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 20.8μs -> 18.0μs (15.5% faster)
    for poly in result:
        pass


def test_empty_mask():
    # Test with an all-zero mask (no polygons)
    def decode(raw):
        return np.zeros((10, 10), dtype=np.uint8)

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 8.11μs -> 6.92μs (17.1% faster)


def test_non_square_mask():
    # Test with a non-square mask containing a rectangle
    def decode(raw):
        mask = np.zeros((10, 20), dtype=np.uint8)
        mask[2:8, 5:15] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 18.0μs -> 14.7μs (22.5% faster)


def test_polygon_with_hole():
    # Test with a mask containing a filled square and a hole inside
    def decode(raw):
        mask = np.zeros((10, 10), dtype=np.uint8)
        mask[2:8, 2:8] = 255
        mask[4:6, 4:6] = 0  # hole
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 19.4μs -> 16.5μs (17.9% faster)


# ---- Edge Test Cases ----


def test_decode_raises_exception():
    # Test if decode raises an exception
    def decode(raw):
        raise ValueError("Decode error!")

    codeflash_output = _extract_segmentation_annotation("bad", decode)
    result = codeflash_output  # 32.3μs -> 32.0μs (0.957% faster)


def test_decode_returns_non_array():
    # Test if decode returns an invalid type
    def decode(raw):
        return "not an array"

    codeflash_output = _extract_segmentation_annotation("bad", decode)
    result = codeflash_output  # 42.9μs -> 42.3μs (1.28% faster)


def test_mask_with_less_than_3_points():
    # Test if mask contains only pixels that form less than 3-point contours
    def decode(raw):
        mask = np.zeros((10, 10), dtype=np.uint8)
        mask[5, 5] = 255  # single pixel
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 17.0μs -> 15.2μs (12.3% faster)


def test_mask_with_line():
    # Test with mask containing a line (not a polygon)
    def decode(raw):
        mask = np.zeros((10, 10), dtype=np.uint8)
        mask[2:8, 5] = 255  # vertical line
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 15.0μs -> 13.3μs (12.5% faster)


def test_mask_with_touching_polygons():
    # Test with two polygons touching at one point
    def decode(raw):
        mask = np.zeros((10, 10), dtype=np.uint8)
        mask[1:5, 1:5] = 255
        mask[4:8, 4:8] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 18.7μs -> 16.2μs (15.9% faster)


# ---- Large Scale Test Cases ----


def test_large_mask_single_polygon():
    # Large mask with a big filled rectangle
    def decode(raw):
        mask = np.zeros((500, 500), dtype=np.uint8)
        mask[100:400, 100:400] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 68.6μs -> 65.2μs (5.31% faster)


def test_large_mask_many_small_polygons():
    # Large mask with many small squares
    def decode(raw):
        mask = np.zeros((100, 100), dtype=np.uint8)
        for i in range(0, 100, 10):
            for j in range(0, 100, 10):
                mask[i : i + 5, j : j + 5] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 206μs -> 165μs (24.4% faster)
    for poly in result:
        pass


def test_large_mask_no_polygons():
    # Large mask, all zeros
    def decode(raw):
        return np.zeros((1000, 1000), dtype=np.uint8)

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 147μs -> 143μs (2.44% faster)


def test_large_mask_complex_shape():
    # Large mask with a complex shape (circle)
    def decode(raw):
        mask = np.zeros((500, 500), dtype=np.uint8)
        cv2.circle(mask, (250, 250), 100, 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 81.4μs -> 78.5μs (3.75% faster)


def test_large_mask_multiple_complex_shapes():
    # Large mask with several circles
    def decode(raw):
        mask = np.zeros((500, 500), dtype=np.uint8)
        for i in range(100, 401, 100):
            cv2.circle(mask, (i, i), 40, 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 86.0μs -> 82.5μs (4.27% faster)
    for poly in result:
        pass


# ---- Miscellaneous ----


def test_decode_returns_none():
    # Test if decode returns None
    def decode(raw):
        return None

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 6.53μs -> 5.62μs (16.1% faster)


def test_decode_returns_empty_array():
    # Test if decode returns an empty array
    def decode(raw):
        return np.array([], dtype=np.uint8)

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 9.83μs -> 9.22μs (6.64% faster)


def test_mask_with_irregular_polygon():
    # Test with mask containing an irregular polygon
    def decode(raw):
        mask = np.zeros((20, 20), dtype=np.uint8)
        points = np.array([[5, 5], [15, 5], [10, 15]], np.int32)
        cv2.fillPoly(mask, [points], 255)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 26.3μs -> 23.1μs (13.5% faster)


def test_mask_with_overlapping_polygons():
    # Test with overlapping polygons
    def decode(raw):
        mask = np.zeros((20, 20), dtype=np.uint8)
        cv2.rectangle(mask, (2, 2), (10, 10), 255, -1)
        cv2.rectangle(mask, (6, 6), (14, 14), 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 19.6μs -> 16.3μs (20.6% faster)


def test_mask_with_diagonal_line():
    # Test with a diagonal line (should not be detected as polygon)
    def decode(raw):
        mask = np.zeros((10, 10), dtype=np.uint8)
        for i in range(10):
            mask[i, i] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode)
    result = codeflash_output  # 14.6μs -> 13.3μs (9.84% faster)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
# function to test
# (copied from above, with no changes)
import cv2
import numpy as np

# imports
import pytest  # used for our unit tests
from ultralytics.utils.callbacks.comet import _extract_segmentation_annotation


class DummyLogger:
    def __init__(self):
        self.last_warning = None

    def warning(self, msg):
        self.last_warning = msg


LOGGER = DummyLogger()

# ------------------------------
# unit tests
# ------------------------------


# Helper decode functions for testing
def decode_square(segmentation_raw):
    # Returns a mask with a filled square in the center
    mask = np.zeros((10, 10), dtype=np.uint8)
    mask[3:7, 3:7] = 255
    return mask


def decode_empty(segmentation_raw):
    # Returns a mask with no foreground
    return np.zeros((10, 10), dtype=np.uint8)


def decode_triangle(segmentation_raw):
    # Returns a mask with a triangle
    mask = np.zeros((10, 10), dtype=np.uint8)
    pts = np.array([[2, 8], [8, 8], [5, 2]], np.int32)
    cv2.fillPoly(mask, [pts], 255)
    return mask


def decode_multiple_shapes(segmentation_raw):
    # Returns a mask with two distinct shapes: a square and a triangle
    mask = np.zeros((20, 20), dtype=np.uint8)
    cv2.rectangle(mask, (2, 2), (7, 7), 255, -1)
    pts = np.array([[12, 18], [18, 18], [15, 12]], np.int32)
    cv2.fillPoly(mask, [pts], 255)
    return mask


def decode_small_shape(segmentation_raw):
    # Returns a mask with a tiny shape (less than 3 points)
    mask = np.zeros((10, 10), dtype=np.uint8)
    mask[5, 5] = 255
    return mask


def decode_invalid(segmentation_raw):
    # Raises an exception to simulate decode failure
    raise ValueError("Invalid segmentation data")


def decode_large_mask(segmentation_raw):
    # Returns a large mask with a big rectangle
    mask = np.zeros((500, 500), dtype=np.uint8)
    cv2.rectangle(mask, (50, 50), (450, 450), 255, -1)
    return mask


def decode_many_shapes(segmentation_raw):
    # Returns a mask with many small squares
    mask = np.zeros((50, 50), dtype=np.uint8)
    for i in range(0, 50, 5):
        cv2.rectangle(mask, (i, i), (i + 2, i + 2), 255, -1)
    return mask


# ------------------------------
# Basic Test Cases
# ------------------------------


def test_basic_square_extraction():
    """
    Test extraction of a simple square shape.
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_square)
    polygons = codeflash_output  # 17.6μs -> 15.3μs (14.8% faster)


def test_basic_triangle_extraction():
    """
    Test extraction of a simple triangle shape.
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_triangle)
    polygons = codeflash_output  # 21.8μs -> 19.1μs (13.9% faster)


def test_multiple_shapes_extraction():
    """
    Test extraction of multiple shapes (square and triangle).
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_multiple_shapes)
    polygons = codeflash_output  # 26.1μs -> 22.2μs (17.7% faster)
    for poly in polygons:
        pass


def test_empty_mask_extraction():
    """
    Test extraction from an empty mask (no shapes).
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_empty)
    polygons = codeflash_output  # 7.41μs -> 6.19μs (19.7% faster)


# ------------------------------
# Edge Test Cases
# ------------------------------


def test_small_shape_extraction():
    """
    Test extraction from a mask with a shape too small (less than 3 points).
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_small_shape)
    polygons = codeflash_output  # 12.1μs -> 10.8μs (12.1% faster)


def test_decode_failure():
    """
    Test behavior when decode function raises an exception.
    """
    codeflash_output = _extract_segmentation_annotation("bad_data", decode_invalid)
    polygons = codeflash_output  # 31.9μs -> 31.9μs (0.069% faster)


def test_nonstandard_mask_shape():
    """
    Test extraction from a non-square mask.
    """

    def decode_rect(segmentation_raw):
        mask = np.zeros((20, 10), dtype=np.uint8)
        cv2.rectangle(mask, (2, 2), (7, 17), 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode_rect)
    polygons = codeflash_output  # 21.6μs -> 17.3μs (24.5% faster)


def test_mask_with_holes():
    """
    Test extraction from a mask with a hole (donut shape).
    """

    def decode_donut(segmentation_raw):
        mask = np.zeros((20, 20), dtype=np.uint8)
        cv2.circle(mask, (10, 10), 8, 255, -1)
        cv2.circle(mask, (10, 10), 4, 0, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode_donut)
    polygons = codeflash_output  # 23.7μs -> 19.5μs (21.8% faster)
    for poly in polygons:
        pass


def test_mask_with_touching_shapes():
    """
    Test extraction from a mask with touching shapes (should be one contour).
    """

    def decode_touching(segmentation_raw):
        mask = np.zeros((20, 20), dtype=np.uint8)
        cv2.rectangle(mask, (2, 2), (10, 10), 255, -1)
        cv2.rectangle(mask, (10, 2), (18, 10), 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode_touching)
    polygons = codeflash_output  # 17.9μs -> 14.6μs (22.5% faster)


def test_mask_with_multiple_small_shapes():
    """
    Test extraction from a mask with several small shapes (all too small).
    """

    def decode_many_small(segmentation_raw):
        mask = np.zeros((20, 20), dtype=np.uint8)
        for i in range(0, 20, 3):
            mask[i, i] = 255
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode_many_small)
    polygons = codeflash_output  # 19.9μs -> 18.3μs (8.90% faster)


# ------------------------------
# Large Scale Test Cases
# ------------------------------


def test_large_mask_extraction():
    """
    Test extraction from a large mask (single large rectangle).
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_large_mask)
    polygons = codeflash_output  # 75.9μs -> 71.9μs (5.58% faster)


def test_many_shapes_extraction():
    """
    Test extraction from a mask with many small shapes.
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_many_shapes)
    polygons = codeflash_output  # 43.5μs -> 35.9μs (21.3% faster)
    for poly in polygons:
        pass


def test_large_number_of_polygons():
    """
    Test extraction from a mask with hundreds of shapes.
    """

    def decode_hundreds(segmentation_raw):
        mask = np.zeros((100, 100), dtype=np.uint8)
        for i in range(0, 100, 10):
            for j in range(0, 100, 10):
                cv2.rectangle(mask, (i, j), (i + 7, j + 7), 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode_hundreds)
    polygons = codeflash_output  # 236μs -> 194μs (21.1% faster)
    for poly in polygons:
        pass


def test_performance_large_mask():
    """
    Test that extraction from a large mask does not crash or hang.
    """

    def decode_big(segmentation_raw):
        mask = np.zeros((1000, 1000), dtype=np.uint8)
        cv2.rectangle(mask, (100, 100), (900, 900), 255, -1)
        return mask

    codeflash_output = _extract_segmentation_annotation("dummy", decode_big)
    polygons = codeflash_output  # 210μs -> 205μs (2.81% faster)


# ------------------------------
# Determinism Test
# ------------------------------


def test_determinism():
    """
    Test that repeated calls produce the same result.
    """
    codeflash_output = _extract_segmentation_annotation("dummy", decode_square)
    result1 = codeflash_output  # 23.2μs -> 20.6μs (12.9% faster)
    codeflash_output = _extract_segmentation_annotation("dummy", decode_square)
    result2 = codeflash_output  # 5.83μs -> 4.95μs (17.9% faster)


# ------------------------------
# Input Type Robustness
# ------------------------------


@pytest.mark.parametrize("segmentation_raw", ["some string", b"bytes input", 12345, None])
def test_input_type_robustness(segmentation_raw):
    """
    Test that function handles various types of segmentation_raw.
    """
    # decode_square ignores the input and always returns a valid mask
    codeflash_output = _extract_segmentation_annotation(segmentation_raw, decode_square)
    polygons = codeflash_output  # 64.9μs -> 54.9μs (18.3% faster)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-_extract_segmentation_annotation-mirackkx and push.

Codeflash Static Badge

The optimized code achieves an 11% speedup by replacing inefficient list comprehensions with a single explicit loop and using more direct array operations.

**Key optimizations applied:**

1. **Eliminated double list comprehensions**: The original code used two chained list comprehensions that created intermediate arrays and lists. The optimized version uses a single loop that processes each polygon once.

2. **Replaced `np.array().squeeze().ravel()` with `reshape(-1)`**: The original approach unnecessarily copied data and performed multiple array transformations. Since `cv2.findContours` already returns numpy arrays, `reshape(-1)` directly flattens them without copying when possible.

3. **Pre-allocated output list**: Instead of building intermediate lists through comprehensions, the optimized version directly appends to a pre-allocated result list, reducing memory allocations.

**Why this leads to speedup:**
- **Reduced array copying**: `reshape(-1)` avoids the copy operations inherent in `np.array().squeeze().ravel()`
- **Fewer temporary objects**: Single loop eliminates intermediate lists created by chained comprehensions
- **Better memory locality**: Direct appending to output list reduces memory fragmentation

**Performance impact based on test results:**
The optimization shows the most significant gains (15-25% speedup) for cases with multiple polygons, such as masks with many small shapes or complex segmentation scenarios. Even simple single-polygon cases see 12-22% improvements. The function is called from `_format_prediction_annotations` during YOLO prediction processing, where segmentation masks are converted for visualization - making this optimization valuable for real-time inference pipelines processing many segmented objects.

**Best performance gains observed in:**
- Multiple polygon scenarios (15-25% faster)
- Large masks with many small shapes (21-24% faster)  
- Complex shapes and irregular polygons (13-22% faster)
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 December 4, 2025 10:21
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Dec 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant