{"record":{"id":"74cd146f9834b288","repo":"roboflow/supervision","slug":"drawing-points-must-have-shape-n-2-or-n-1-2","errorCode":null,"errorMessage":"Drawing points must have shape (N, 2) or (N, 1, 2)","messagePattern":"Drawing points must have shape \\(N, 2\\) or \\(N, 1, 2\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/_cv2/_drawing.py","lineNumber":56,"sourceCode":"\ndef _paint(image: _ImageArray, mask: npt.NDArray[np.bool_], color: Any) -> _ImageArray:\n    \"\"\"Apply a scalar or multi-channel color to a drawing mask.\"\"\"\n    image[mask] = _color_for_image(image, color)\n    return image\n\n\ndef _point(point: Sequence[int | float]) -> _Point:\n    \"\"\"Convert an OpenCV point to integer Pillow coordinates.\"\"\"\n    return round(point[0]), round(point[1])\n\n\ndef _points(points: npt.NDArray[Any], offset: tuple[int, int] = (0, 0)) -> list[_Point]:\n    \"\"\"Normalize OpenCV polygon shapes to integer Pillow coordinates.\"\"\"\n    values = np.asarray(points)\n    if values.size == 0:\n        return []\n    if values.ndim not in (2, 3) or values.shape[-1] != 2:\n        raise ValueError(\"Drawing points must have shape (N, 2) or (N, 1, 2)\")\n    normalized = np.rint(values.reshape(-1, 2)).astype(np.int64)\n    normalized += np.asarray(offset, dtype=np.int64)\n    return [(int(x), int(y)) for x, y in normalized]\n\n\ndef _validate_shift(shift: int) -> None:\n    \"\"\"Reject fixed-point coordinates not supported by the fallback.\"\"\"\n    if shift != 0:\n        raise ValueError(\"Only unshifted drawing coordinates are supported\")\n\n\ndef _line(\n    img: _ImageArray,\n    pt1: Sequence[int | float],\n    pt2: Sequence[int | float],\n    color: Any,\n    thickness: int = 1,\n    lineType: int = 8,","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/_cv2/_drawing.py#L38-L74","documentation":"supervision ships a pure NumPy/Pillow fallback used when `opencv-python` is not installed. `_points` in src/supervision/_cv2/_drawing.py:56 normalizes point arrays for the Pillow rasterizer and only accepts shapes `(N, 2)` or `(N, 1, 2)` — the shapes OpenCV drawing functions produce. Anything else (1-D, (N, 3), (N, 2, 1), non-numeric) raises ValueError.","triggerScenarios":"Running without opencv installed while annotators or `cv2.polylines`/`fillPoly`/`drawContours` fallbacks receive raw point arrays: passing a flat `[x1, y1, x2, y2]` list, an (N, 3) xyz array, or an (N, 1, 3) array from a mesh/pose pipeline.","commonSituations":"Minimal deployments (Docker slim images, serverless) that omit opencv-python; passing keypoints from a 3D pose model or polygon vertices stored as (N, 3) directly to an annotator that forwards them to drawing.","solutions":["Reshape points to (N, 2): `np.asarray(pts).reshape(-1, 2)`","Drop the extra column before drawing: `pts[:, :2]` for (N, 3) inputs","Install `opencv-python` so the real cv2 backend handles its usual flexible inputs"],"exampleFix":"// before\npoints = np.array([[10, 20, 0], [30, 40, 0]])  # (N, 3)\nscene = sv.draw_polygon(scene, points)\n\n// after\npoints = np.asarray(points).reshape(-1, 2)[:, :2]\nscene = sv.draw_polygon(scene, points)","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\ndef as_drawable_points(points) -> np.ndarray:\n    \"\"\"Coerce point input to the (N, 2) shape drawing APIs require.\"\"\"\n    arr = np.asarray(points)\n    if arr.ndim not in (2, 3) or arr.shape[-1] != 2:\n        arr = arr.reshape(-1, 2)[:, :2]\n    return arr","typeGuard":"def is_drawable_points(points) -> bool:\n    \"\"\"Drawing fallbacks accept only (N, 2) or (N, 1, 2) arrays.\"\"\"\n    arr = np.asarray(points)\n    return arr.ndim in (2, 3) and arr.shape[-1] == 2","tryCatchPattern":null,"preventionTips":["Standardize on (N, 2) float/int arrays for all polygon/keypoint drawing","In cv2-optional deployments, run supervisions's import once and check for the fallback warning"],"tags":["cv2-fallback","drawing","pillow","shape-validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}