【问题标题】:How to apply mask to image tensors in PyTorch?如何在 PyTorch 中对图像张量应用遮罩?
【发布时间】:2021-10-25 23:58:31
【问题描述】:

使用 NumPy 或 OpenCV 应用掩码是一个相对简单的过程。但是,如果我需要在优化算法的损失计算中使用蒙版图像,我需要专门使用 PyTorch,否则会干扰梯度计算。 假设我有一个图像张量[1, 512, 512, 3](批次、高度、宽度、通道)和一个掩码张量[1, 20, 512, 512](批次、通道、高度、宽度),其中每个通道对应于 20 个分割类之一,我想得到用黑色 (0, 0, 0) 填充每个像素的蒙版图像张量,但属于一个或多个指定分割类别的除外。

这里是如何使用 numpy 完成的:

import numpy as np
import torch

# Create dummy image and mask
image_tensor = torch.randn([1, 512, 512, 3])
mask_tensor = torch.randn([1, 20, 512, 512])

# Apply argmax to mask
mask_tensor =  torch.max(mask_tensor, 1)[1] # -> 1, 512, 512

# Define mask function
def selective_mask(image_src, mask, dims=[]):
    h, w = mask.shape
    background = np.zeros([h, w, 3], dtype=np.uint8)
    for j_, j in enumerate(mask[:, :]):
        for k_, k in enumerate(j):
            if k in dims:
                background[j_, k_] = image_src[j_, k_]
    output = background
    return output

# Convert tensors to numpy:
image = image_tensor.squeeze(0).cpu().numpy()
mask = mask_tensor.squeeze(0).cpu().nmpy()

# Apply mask function for several classes
image_masked = selective_mask(image, mask, dims=[5, 6, 8])

应如何更改我的代码以使其符合 PyTorch 要求?

【问题讨论】:

    标签: python image numpy machine-learning pytorch


    【解决方案1】:

    首先,函数selective_mask 的定义远非您所说的“直截了​​当”。使用numpy(和torch,它被设计为最兼容)的关键是利用操作的向量化并避免使用不可并行化的循环。

    如果你以这种方式重写上述函数:

    def selective_mask(image_src, mask, channels=[]):
        mask = mask[np.array(channels).astype(int)]
        return np.sign(np.sum(mask, axis=0), dtype=image_src.dtype) * image_src
    

    事实证明,你实际上可以对 pytorch 张量做同样的事情(这里不需要挤压批次(第一)维度):

    def selective_mask_t(image_src, mask, channels=[]):
        mask = mask[:, torch.tensor(channels).long()]
        mask = torch.sgn(torch.sum(mask, dim=1)).to(dtype=image_src.dtype).unsqueeze(-1)
        return mask * image_src
    

    另外,您可能希望以这种方式制作面具本身:
    (顺便说一句,在这里使用 max 和 sgn 的组合实际上应该比设置由 argmax 索引的元素更快)

    # Create dummy image and mask
    image_tensor = torch.randn([1, 512, 512, 3])
    mask_tensor = torch.randn([1, 20, 512, 512])
    
    # Discreticize the mask (set to one in the channel with the highest value) -> 1, 20, 512, 512
    mask_tensor = torch.sgn(mask_tensor - torch.max(mask_tensor, 1)[0].unsqueeze(1)) + 1.  
    

    那么它应该可以正常工作:

    print(selective_mask_t(image_tensor, mask_tensor, [5, 6, 8]))
    

    【讨论】:

    • 感谢您的评论,我已经尝试使用这种方法。但是,我首先得到了 AttributeError: 'Tensor' object has no attribute 'astype' ,在将 ,astype 替换为 .to(dtype=image_src.dtype) 之后,我完全遇到了另一个问题: RuntimeError: The size of tensor a (20) must在非单维 3 处匹配张量 b (3) 的大小。这假设输入的形状为 [1, 256, 256, 3] 用于图像,[1, 256, 256, 20] 用于掩码,假设您使用渠道。
    • 在使用 permute 将输入形状更改为 [1, 3, 512, 512] 和 [1, 20, 512, 512] (上面的 256 是我的错误)后,我设法在没有公开的情况下使用此功能例外。然而,它的输出看起来更像是一个奇怪的色彩空间中的负片,而不是蒙版。
    • 对不起'astype' 错误,看来我也混淆了这两个库。我认为您使用 argmax 创建蒙版的方式还有另一个错误,之前没有注意到。我更新了帖子以适应整个示例代码的变化。
    • 再次感谢,在浏览了我的一些原始代码后,它的工作方式与预期一样。
    猜你喜欢
    • 2011-07-04
    • 2018-05-29
    • 2016-01-07
    • 2021-07-20
    • 2022-10-23
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多