{"record":{"id":"313bff601da05663","repo":"roboflow/supervision","slug":"name-has-shape-arr-shape-expected-n-4-2","errorCode":null,"errorMessage":"`{name}` has shape {arr.shape}; expected (N, 4, 2) — each box must have exactly 4 corners with (x, y) coordinates.","messagePattern":"`(.+?)` has shape (.+?); expected \\(N, 4, 2\\) — each box must have exactly 4 corners with \\(x, y\\) coordinates\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/iou_and_nms.py","lineNumber":536,"sourceCode":"        ValueError: If ``overlap_metric`` is not\n            :attr:`~supervision.config.OverlapMetric.IOU` or\n            :attr:`~supervision.config.OverlapMetric.IOS`.\n\n    Examples:\n        ```pycon\n        >>> import numpy as np\n        >>> import supervision as sv\n        >>> a = np.array([[[0, 0], [2, 0], [2, 2], [0, 2]]], dtype=np.float32)\n        >>> b = np.array([[[1, 0], [3, 0], [3, 2], [1, 2]]], dtype=np.float32)\n        >>> sv.oriented_box_iou_batch(a, b)  # doctest: +ELLIPSIS\n        array([[0.333...]])\n\n        ```\n    \"\"\"\n\n    for name, arr in ((\"boxes_true\", boxes_true), (\"boxes_detection\", boxes_detection)):\n        if arr.ndim == 3 and arr.shape[1:] != (4, 2):\n            raise ValueError(\n                f\"`{name}` has shape {arr.shape}; expected (N, 4, 2) \"\n                f\"— each box must have exactly 4 corners with (x, y) coordinates.\"\n            )\n        elif arr.ndim == 2 and arr.shape[1] != 8:\n            raise ValueError(\n                f\"`{name}` has shape {arr.shape}; expected (N, 8) for flat \"\n                f\"YOLO format or (N, 4, 2) for corner format.\"\n            )\n        elif arr.ndim not in (2, 3):\n            raise ValueError(\n                f\"`{name}` must be 2-D (N, 8) or 3-D (N, 4, 2), got shape {arr.shape}.\"\n            )\n\n    if overlap_metric == OverlapMetric.IOU:\n        normalize_by_union = True\n    elif overlap_metric == OverlapMetric.IOS:\n        normalize_by_union = False\n    else:","sourceCodeStart":518,"sourceCodeEnd":554,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/iou_and_nms.py#L518-L554","documentation":"`oriented_box_iou_batch` accepts oriented (rotated) boxes only as 3-D arrays of shape (N, 4, 2) — one box per row, exactly 4 corners, each an (x, y) pair — or as flat 2-D (N, 8). This error fires when the input is 3-D but the trailing dimensions are not (4, 2), e.g. (N, 2, 4), (N, 8, 1), or (N, 4, 3). The shape check exists because the algorithm reshapes to (-1, 4, 2) and treats each row as a quadrilateral; a wrong layout would silently produce garbage IoU values.","triggerScenarios":"Passing corners in (x, y, w, h, angle) order rolled into an array, transposing corner/coordinate axes (shape (N, 2, 4)), stacking polygons with more than 4 points from `cv2.findContours`, or reshaping an (N, 8) flat array incorrectly to (N, 8, 1).","commonSituations":"Converting from OpenCV rotated-rect or contour outputs (contours can have many points and must be approximated to 4); consuming OBB output from models (YOLO-OBB gives 8 floats per box) and reshaping with the wrong axis order; test fixtures hand-built with wrong axis order.","solutions":["Reshape flat (N, 8) input to corners: `boxes.reshape(-1, 4, 2)`.","If your array is (N, 2, 4), transpose the last two axes: `arr.transpose(0, 2, 1)`.","If your polygons come from contours, first reduce each to exactly 4 vertices (e.g. `cv2.approxPolyDP` or `sv.approximate_polygon` with a 4-point target) before calling this function."],"exampleFix":"# before\nious = sv.oriented_box_iou_batch(corners.transpose(0, 2, 1), b)  # shape (N, 2, 4)\n\n# after\nious = sv.oriented_box_iou_batch(corners.transpose(0, 2, 1).reshape(-1, 4, 2), b)","handlingStrategy":"validation","validationCode":"def to_corner_format(arr):\n    arr = np.asarray(arr, dtype=float)\n    assert arr.ndim == 2 and arr.shape[1] == 8 or (arr.ndim == 3 and arr.shape[1:] == (4, 2))\n    return arr.reshape(-1, 4, 2)\n\na = to_corner_format(a)","typeGuard":"def is_valid_obb_array(arr) -> bool:\n    arr = np.asarray(arr)\n    return (arr.ndim == 3 and arr.shape[1:] == (4, 2)) or (arr.ndim == 2 and arr.shape[1] == 8)","tryCatchPattern":null,"preventionTips":["Standardize on reshape(-1, 4, 2) in every adapter before calling oriented-box APIs.","Never forward raw cv2 contour arrays; reduce to 4 vertices first."],"tags":["shape-validation","oriented-boxes","iou","numpy","detection"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}