{"record":{"id":"849aeacb7e5130bf","repo":"lllyasviel/ControlNet","slug":"image-must-have-h-x-w-x-3-h-x-w-x-1-or-h-x-w-dime-849aea","errorCode":null,"errorMessage":"Image must have H x W x 3, H x W x 1 or H x W dimensions.","messagePattern":"Image must have H x W x 3, H x W x 1 or H x W dimensions\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"ldm/modules/midas/utils.py","lineNumber":82,"sourceCode":"        scale (int, optional): Scale. Defaults to 1.\n    \"\"\"\n\n    with open(path, \"wb\") as file:\n        color = None\n\n        if image.dtype.name != \"float32\":\n            raise Exception(\"Image dtype must be float32.\")\n\n        image = np.flipud(image)\n\n        if len(image.shape) == 3 and image.shape[2] == 3:  # color image\n            color = True\n        elif (\n            len(image.shape) == 2 or len(image.shape) == 3 and image.shape[2] == 1\n        ):  # greyscale\n            color = False\n        else:\n            raise Exception(\"Image must have H x W x 3, H x W x 1 or H x W dimensions.\")\n\n        file.write(\"PF\\n\" if color else \"Pf\\n\".encode())\n        file.write(\"%d %d\\n\".encode() % (image.shape[1], image.shape[0]))\n\n        endian = image.dtype.byteorder\n\n        if endian == \"<\" or endian == \"=\" and sys.byteorder == \"little\":\n            scale = -scale\n\n        file.write(\"%f\\n\".encode() % scale)\n\n        image.tofile(file)\n\n\ndef read_image(path):\n    \"\"\"Read image and output RGB image (0-1).\n\n    Args:","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/lllyasviel/ControlNet/blob/ed85cd1e25a5ed592f7d8178495b4483de0331bf/ldm/modules/midas/utils.py#L64-L100","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove batch/channel dimensions: image = image.squeeze() or image = image[0] as appropriate","If writing a single channel from a multi-channel map, select it first: image = feat[:, :, 0]","Assert the shape before saving: assert image.ndim == 2 or (image.ndim == 3 and image.shape[2] in (1, 3))","For non-visual N-channel tensors, save with np.save instead of PFM"],"exampleFix":"# before\nwrite_depth(path, prediction)  # prediction.shape == (1, 384, 384)\n# after\nwrite_depth(path, prediction.squeeze())  # or prediction[0] if batch dim","handlingStrategy":"validation","validationCode":"def valid_pfm_shape(img) -> bool:\n    import numpy as np\n    return img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (1, 3))","typeGuard":"from typing import Protocol\nimport numpy as np\n\ndef pfm_image_ok(img: np.ndarray) -> bool:\n    return valid_pfm_shape(img) and img.dtype == np.float32","tryCatchPattern":null,"preventionTips":["squeeze() batch dims right after model forward","Assert shape before save: assert depth.ndim == 2","Save non-RGB/1-channel tensors with np.save, not PFM"],"tags":["midas","pfm","numpy","shape","depth-estimation"],"backgroundTag":"array-shape-mismatch","analyzedSha":"ed85cd1e25a5ed592f7d8178495b4483de0331bf","analyzedAt":"2026-08-27T12:58:54.167Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}