opendatalab/MinerU · error · ValueError
Unsupported image shape for UnimerSwinImageProcessor: {image
Error message
Unsupported image shape for UnimerSwinImageProcessor: {image.shape} What it means
UnimerSwinImageProcessor.to_normalized_gray_tensor converts arbitrary input arrays to single-channel grayscale before normalization. It accepts 2-D arrays, 3-D with 1 channel, and 3-D with 3 channels; anything else (4-channel RGBA, 2-channel, ndim 1 or 4) is rejected because no defined grayscale conversion exists.
Source
Thrown at mineru/model/mfr/unimernet/unimernet_hf/unimer_swin/image_processing_unimer_swin.py:33
):
self.input_size = [int(_) for _ in image_size]
assert len(self.input_size) == 2
def __call__(self, item):
image = self.prepare_input(item)
return self.to_normalized_gray_tensor(image)
@staticmethod
def to_normalized_gray_tensor(image: np.ndarray) -> torch.Tensor:
"""将图像确定性转灰度、按 UniMERNet 参数归一化,并转为单通道 tensor。"""
if image.ndim == 2:
gray = image
elif image.ndim == 3 and image.shape[2] == 1:
gray = image[:, :, 0]
elif image.ndim == 3 and image.shape[2] == 3:
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
else:
raise ValueError(f"Unsupported image shape for UnimerSwinImageProcessor: {image.shape}")
normalized = (gray.astype(np.float32) - 0.7931 * 255.0) / (0.1738 * 255.0)
return torch.from_numpy(normalized[None, :, :])
@staticmethod
def crop_margin(img: Image.Image) -> Image.Image:
data = np.array(img.convert("L"))
data = data.astype(np.uint8)
max_val = data.max()
min_val = data.min()
if max_val == min_val:
return img
data = (data - min_val) / (max_val - min_val) * 255
gray = 255 * (data < 200).astype(np.uint8)
coords = cv2.findNonZero(gray) # Find all non-zero points (text)
a, b, w, h = cv2.boundingRect(coords) # Find minimum spanning bounding box
return img.crop((a, b, w + a, h + b))View on GitHub (pinned to 4fe4bde114)
Solutions
- Convert to RGB before calling: img = img.convert('RGB') for PIL or cv2.cvtColor(img, cv2.COLOR_RGBA2BGR) then back, dropping alpha.
- If you have a PIL Image, pass modes 'L' or 'RGB' only.
- For batched arrays, iterate and pass one (H, W[, C]) image at a time.
- Composite RGBA onto a white background if alpha carries meaning.
Example fix
# before
crop = pil_page.crop(box) # RGBA page render
feat = processor(crop)
# after
crop = pil_page.crop(box).convert('RGB')
feat = processor(crop) Defensive patterns
Strategy: type-guard
Validate before calling
def normalize_shape(img: np.ndarray) -> np.ndarray:
if img.ndim == 3 and img.shape[2] not in (1, 3):
img = img[:, :, :3]
return img Type guard
def is_supported_gray_input(img: np.ndarray) -> bool:
return img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (1, 3)) Try / catch
try:
feat = processor(crop)
except ValueError as e:
if 'Unsupported image shape' in str(e):
feat = processor(np.asarray(Image.fromarray(crop).convert('RGB')))
else:
raise Prevention
- Convert every crop to 'L' or 'RGB' PIL mode right after cropping.
- Composite RGBA onto white before feeding formula models.
- Log crop .shape in debug builds to catch pipeline format drift early.
When it happens
Trigger: Passing an RGBA crop (shape (H, W, 4)) straight from PIL's .convert('RGBA') or a PNG with alpha into the processor; passing a (H, W, 2) LA-mode array; passing a flattened or batched array with ndim != 2/3.
Common situations: Cropping formula regions from PDF page renders that keep an alpha channel, mixing BGR/RGBA pipelines from OpenCV-based upstream stages, or feeding batched tensors (N, H, W) instead of a single image.
Related errors
- images_mfd_res and images must have the same length.
- max_size = {max_size} must be strictly greater than the requ
- images_mfd_res and images must have the same length.
- Input image ({w}, {h}) smaller than the target size ({cw}, {
- The channel({channel}) of the img is not in [1, 2, 3, 4]
AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14).
Data as JSON: /api/errors/bcf577f56a1f994e.
Report an issue: GitHub.