affaan-m/ECC · error · ValueError
expected (N, 3) pixels, got
Error message
expected (N, 3) pixels, got {pixels.shape} What it means
analyze_pixels() is the masked-pixel variant of the analysis and expects a 2-D (N, 3) array of pooled RGB pixels. It validates the shape up front because grain estimation, Lab conversion, and reshaping all assume exactly that layout; anything else (1-D, (N,4) RGBA, (H,W,3)) is rejected.
Solutions
- Reshape/flatten your pixels to (N, 3) before calling: pixels.reshape(-1, 3)
- Strip the alpha channel: arr[..., :3] for RGBA inputs
- Check the mask kept pixels: if pixels.shape[0] == 0, widen the mask or skip the clip
- Verify you are not passing a full frame; use analyze() for frame lists instead
Example fix
// before stats = analyze_pixels(rgba_frame, ...) # (H, W, 4) // after pixels = rgba_frame[..., :3].reshape(-1, 3).astype(np.float32) stats = analyze_pixels(pixels, ...)
Defensive patterns
Strategy: type-guard
Validate before calling
import numpy as np
if not (isinstance(pixels, np.ndarray) and pixels.ndim == 2 and pixels.shape[1] == 3):
raise TypeError("analyze_pixels expects (N, 3) float array") Type guard
def is_pixel_matrix(x) -> bool:
return isinstance(x, np.ndarray) and x.ndim == 2 and x.shape[1] == 3 and x.shape[0] > 0 Try / catch
try:
stats = analyze_pixels(pixels, ...)
except ValueError as e:
if "expected (N, 3) pixels" in str(e):
pixels = np.asarray(pixels)[..., :3].reshape(-1, 3)
stats = analyze_pixels(pixels, ...)
else: raise Prevention
- Always flatten frames with arr[..., :3].reshape(-1, 3) before pooling
- Strip alpha channels before pixel pooling
- Check the mask kept >0 pixels before calling
- Use analyze() for frame lists and analyze_pixels() only for pooled (N,3) matrices
When it happens
Trigger: Passing an RGBA frame's pixels (4 channels), a single 1-D pixel array, a (H, W, 3) image instead of flattened pixels, or an empty (0, 3) array produced by a mask that kept no pixels.
Common situations: Forgetting to slice [:, :3] off RGBA arrays; calling analyze_pixels with a raw frame instead of pooled pixel matrix; over-aggressive content masks leaving zero surviving pixels; float/uint8 confusion doesn't trigger this but often accompanies it.
Understand the failure class
Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.
Related errors
- analyze() needs at least one frame
- analyze() needs at least one frame
- asset fps differs from timeline
- asset must contain a video stream
- cannot open
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/806a3a190b51655a.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-distillation/scripts/taste/grade.py:615
def load_stats(path: str | Path) -> GradeStats:
return GradeStats.from_dict(json.loads(Path(path).read_text(encoding="utf-8")))
def analyze_pixels(
pixels: np.ndarray,
noise_frames: list[np.ndarray] | None = None,
palette_pixels: np.ndarray | None = None,
) -> GradeStats:
"""Same statistics as :func:`analyze`, but from a flat (N, 3) pixel array.
This is the masked path: callers pool only the pixels that survived
content masking, across references of differing frame sizes, and pass
them here. Grain still needs 2-D neighbourhoods, so ``noise_frames``
carries a handful of cropped frames purely for that estimate.
"""
if pixels.ndim != 2 or pixels.shape[1] != 3:
raise ValueError(f"expected (N, 3) pixels, got {pixels.shape}")
lab = _to_lab(np.ascontiguousarray(pixels.reshape(1, -1, 3), np.float32)).reshape(-1, 3)
L, a, b = lab[:, 0], lab[:, 1], lab[:, 2]
chroma = np.sqrt(a.astype(np.float64) ** 2 + b.astype(np.float64) ** 2)
pal_src = palette_pixels if palette_pixels is not None else pixels
pal = _palette([pal_src.reshape(1, -1, 3)])
return GradeStats(
zones=_zone_stats(L, a, b),
lab_mean=[float(L.mean()), float(a.mean()), float(b.mean())],
lab_std=[float(L.std()), float(a.std()), float(b.std())],
l_cdf=[float(v) for v in _cdf_of_l(L)],
black_point=float(np.percentile(L, 1)),
white_point=float(np.percentile(L, 99)),
contrast=float(L.std()),
saturation=float(chroma.mean()),
warmth=float(b.mean()),View on GitHub (pinned to 8321021c54)