lllyasviel/ControlNet · error · Exception

Image must have H x W x 3, H x W x 1 or H x W dimensions.

Error message

Image must have H x W x 3, H x W x 1 or H x W dimensions.

What it means

Raised by write_pfm when the numpy array's shape is not 2D (H x W grayscale), 3D with 3 channels (H x W x 3 color), or 3D with 1 channel (H x W x 1). The PFM writer cannot serialize arrays with other channel counts or dimensions, such as batched 4D tensors or multi-channel non-RGB data.

Source

Thrown at ldm/modules/midas/utils.py:82

        scale (int, optional): Scale. Defaults to 1.
    """

    with open(path, "wb") as file:
        color = None

        if image.dtype.name != "float32":
            raise Exception("Image dtype must be float32.")

        image = np.flipud(image)

        if len(image.shape) == 3 and image.shape[2] == 3:  # color image
            color = True
        elif (
            len(image.shape) == 2 or len(image.shape) == 3 and image.shape[2] == 1
        ):  # greyscale
            color = False
        else:
            raise Exception("Image must have H x W x 3, H x W x 1 or H x W dimensions.")

        file.write("PF\n" if color else "Pf\n".encode())
        file.write("%d %d\n".encode() % (image.shape[1], image.shape[0]))

        endian = image.dtype.byteorder

        if endian == "<" or endian == "=" and sys.byteorder == "little":
            scale = -scale

        file.write("%f\n".encode() % scale)

        image.tofile(file)


def read_image(path):
    """Read image and output RGB image (0-1).

    Args:

View on GitHub (pinned to ed85cd1e25)

Solutions

  1. Remove batch/channel dimensions: image = image.squeeze() or image = image[0] as appropriate
  2. If writing a single channel from a multi-channel map, select it first: image = feat[:, :, 0]
  3. Assert the shape before saving: assert image.ndim == 2 or (image.ndim == 3 and image.shape[2] in (1, 3))
  4. For non-visual N-channel tensors, save with np.save instead of PFM

Example fix

# before
write_depth(path, prediction)  # prediction.shape == (1, 384, 384)
# after
write_depth(path, prediction.squeeze())  # or prediction[0] if batch dim
Defensive patterns

Strategy: validation

Validate before calling

def valid_pfm_shape(img) -> bool:
    import numpy as np
    return img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (1, 3))

Type guard

from typing import Protocol
import numpy as np

def pfm_image_ok(img: np.ndarray) -> bool:
    return valid_pfm_shape(img) and img.dtype == np.float32

Prevention

When it happens

Trigger: Calling write_pfm(path, image) with image.shape of length 4 (e.g. (1, H, W, 1) batched depth), length 3 with shape[2] not in (1, 3) (e.g. H x W x 2 or H x W x 38 MiDaS raw channels), or a 1D/0D array.

Common situations: Passing a raw MiDaS model output with an extra batch dimension, forgetting to squeeze a (H, W, 1) prediction, or writing attention/feature maps with arbitrary channel counts.

Related errors


AI-assisted analysis of lllyasviel/ControlNet@ed85cd1e25 (2026-08-27). Data as JSON: /api/errors/849aeacb7e5130bf. Report an issue: GitHub.