PaddlePaddle/PaddleOCR · error · ValueError

degenerate text crop (zero width/height)

Error message

degenerate text crop (zero width/height)

What it means

Raised by the calibration-sample builder for the iOS ONNX demo when a perspective-crop of a detected text quadrilateral degenerates: the computed crop width or height (max of opposing edge lengths via np.linalg.norm) rounds down below 1 pixel. This means the detected box is collapsed, collinear, or so tiny that a valid crop rectangle cannot be formed.

Source

Thrown at deploy/ios_demo/scripts/build_onnx_calib_npy.py:143

    else:
        index_b, index_c = 3, 2
    box = [pts[index_a], pts[index_b], pts[index_c], pts[index_d]]
    pts4 = [np.array(p, dtype=np.float32) for p in box]
    assert len(pts4) == 4, "shape of points must be 4*2"
    img_crop_width = int(
        max(
            np.linalg.norm(pts4[0] - pts4[1]),
            np.linalg.norm(pts4[2] - pts4[3]),
        )
    )
    img_crop_height = int(
        max(
            np.linalg.norm(pts4[0] - pts4[3]),
            np.linalg.norm(pts4[1] - pts4[2]),
        )
    )
    if img_crop_width < 1 or img_crop_height < 1:
        raise ValueError("degenerate text crop (zero width/height)")
    pts_std = np.float32(
        [
            [0, 0],
            [img_crop_width, 0],
            [img_crop_width, img_crop_height],
            [0, img_crop_height],
        ]
    )
    pstack = np.stack(pts4, axis=0)
    m = cv2.getPerspectiveTransform(pstack, pts_std)
    dst = cv2.warpPerspective(
        img,
        m,
        (img_crop_width, img_crop_height),
        borderMode=cv2.BORDER_REPLICATE,
        flags=cv2.INTER_CUBIC,
    )
    dh, dw = dst.shape[0:2]

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Sanitize the input annotations: drop quads whose width or height norms are < 1px before running the script.
  2. Skip the degenerate crop instead of aborting: wrap the check in a filter and continue with remaining samples.
  3. If boxes should be valid, inspect the offending quad coordinates (print pts4) and fix the upstream detector/labels.

Example fix

# before
if img_crop_width < 1 or img_crop_height < 1:
    raise ValueError("degenerate text crop (zero width/height)")

# after
if img_crop_width < 1 or img_crop_height < 1:
    print(f"skip degenerate crop: {pts4.tolist()}")
    continue
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def crop_is_valid(pts4: np.ndarray, min_px: float = 1.0) -> bool:
    w = max(np.linalg.norm(pts4[0] - pts4[1]), np.linalg.norm(pts4[2] - pts4[3]))
    h = max(np.linalg.norm(pts4[0] - pts4[3]), np.linalg.norm(pts4[1] - pts4[2]))
    return w >= min_px and h >= min_px

# filter before cropping
samples = [s for s in samples if crop_is_valid(np.asarray(s["polygon"], np.float32))]

Type guard

def is_valid_quad(pts) -> bool:
    import numpy as np
    p = np.asarray(pts, dtype=np.float32)
    return p.shape == (4, 2) and np.all(np.isfinite(p)) and len(np.unique(p, axis=0)) >= 3

Try / catch

try:
    crop = make_crop(img, pts4)
except ValueError as e:
    if "degenerate" in str(e):
        continue  # skip this sample, keep processing the calibration set
    raise

Prevention

When it happens

Trigger: A detection quad whose opposing edges have length < 1.0 — e.g. all four points nearly identical, points collinear (zero height), or sub-pixel boxes produced by a downscaled/quantized detector during ONNX calibration-set generation.

Common situations: Running build_onnx_calib_npy.py over annotation files that contain degenerate or corrupted boxes; calibration images resized so small that legitimate boxes shrink below 1px; hand-edited label files with duplicated corner coordinates.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/ffe5c7648431db8e. Report an issue: GitHub.