You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch语义分割自定义RandomCrop报错:'Image'对象无dim属性

解决AttributeError: 'Image' object has no attribute 'dim'问题

这个错误的根源很明确:你正在使用torch.nn.functional.pad(也就是代码里的F.pad)处理PIL Image对象,但这个函数是专门为PyTorch张量(Tensor)设计的——PIL Image并没有dim属性,所以调用时就触发了这个报错。

下面给你两种针对性的解决方案,推荐第一种更贴合你现有代码逻辑的:

方案1:改用torchvision.transforms.Pad处理PIL Image

torchvision.transforms.Pad是专门为PIL Image设计的填充工具,完全可以替代F.pad完成你的需求。修改你的__call__方法中填充图像和mask的部分:

def __call__(self, data):
    img, mask = data["image"], data["mask"]
    # 处理宽度不足的情况
    if self.pad_if_needed and img.size[0] < self.size[1]:
        pad_left = (self.size[1] - img.size[0]) // 2
        pad_right = self.size[1] - img.size[0] - pad_left
        pad_transform = transforms.Pad((pad_left, 0, pad_right, 0), fill=self.fill, padding_mode=self.padding_mode)
        img = pad_transform(img)
        mask = pad_transform(mask)
    # 处理高度不足的情况
    if self.pad_if_needed and img.size[1] < self.size[0]:
        pad_top = (self.size[0] - img.size[1]) // 2
        pad_bottom = self.size[0] - img.size[1] - pad_top
        pad_transform = transforms.Pad((0, pad_top, 0, pad_bottom), fill=self.fill, padding_mode=self.padding_mode)
        img = pad_transform(img)
        mask = pad_transform(mask)
    
    i, j, h, w = self.get_params(img, self.size)
    crop_image = transforms.functional.crop(img, i, j, h, w)
    crop_mask = transforms.functional.crop(mask, i, j, h, w)
    return {"image": crop_image, "mask": crop_mask}

关键改动说明:

  • 用transforms.Pad替代F.pad,它直接支持PIL Image输入
  • 计算左右/上下的填充量(这里做了对称填充,如果你需要单边填充可以改回原逻辑)
  • 对图像和mask使用完全相同的填充变换,确保二者空间位置完全对齐

方案2:先将PIL Image转为张量再处理

如果你更习惯用F.pad的API,可以先把PIL Image转为张量,处理完后再转回PIL Image:

def __call__(self, data):
    img, mask = data["image"], data["mask"]
    # 转为张量
    img_tensor = transforms.ToTensor()(img)
    mask_tensor = transforms.ToTensor()(mask)
    
    # 处理宽度不足的情况
    if self.pad_if_needed and img.size[0] < self.size[1]:
        img_tensor = F.pad(img_tensor, (self.size[1] - img.size[0], 0), value=self.fill, mode=self.padding_mode)
        mask_tensor = F.pad(mask_tensor, (self.size[1] - mask.size[0], 0), value=self.fill, mode=self.padding_mode)
    # 处理高度不足的情况
    if self.pad_if_needed and img.size[1] < self.size[0]:
        img_tensor = F.pad(img_tensor, (0, self.size[0] - img.size[1]), value=self.fill, mode=self.padding_mode)
        mask_tensor = F.pad(mask_tensor, (0, self.size[0] - mask.size[1]), value=self.fill, mode=self.padding_mode)
    
    # 转回PIL Image
    img = transforms.ToPILImage()(img_tensor)
    mask = transforms.ToPILImage()(mask_tensor)
    
    i, j, h, w = self.get_params(img, self.size)
    crop_image = transforms.functional.crop(img, i, j, h, w)
    crop_mask = transforms.functional.crop(mask, i, j, h, w)
    return {"image": crop_image, "mask": crop_mask}

不过这个方案多了张量和PIL的转换步骤,效率略低,所以更推荐方案1。

另外,关于你提到的先按0.98-1.1比例缩放的需求,可以单独写一个自定义变换类,和这个RandomCrop一起用transforms.Compose组合起来,比如:

class RandomResize(object):
    def __call__(self, data):
        img, mask = data["image"], data["mask"]
        scale = random.uniform(0.98, 1.1)
        new_size = (int(img.size[0]*scale), int(img.size[1]*scale))
        img = img.resize(new_size, Image.BILINEAR)
        mask = mask.resize(new_size, Image.NEAREST)  # mask用最近邻插值避免标签失真
        return {"image": img, "mask": mask}

# 组合变换
transform = transforms.Compose([
    RandomResize(),
    RandomCrop(size=(256, 256))  # 替换成你的目标尺寸
])

这样就能保证图像和mask先按相同比例缩放,再做随机裁剪,完全满足你的需求。

内容的提问来源于stack exchange,提问作者Atahan Özer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:37:38