使用 torch 或 torchvision,我如何调整和裁剪图像批次,并获得调整大小的比例和新图像?

With torch or torchvision, how can I resize and crop an image batch, and get both the resizing scales and the new images?

我想转换一批图像,使它们随机裁剪(固定比例)和调整大小(缩放)。但是,我不仅需要新图像,还需要应用于每个图像的比例因子的张量。例如,此 torchvision 转换将执行我想要的裁剪和调整大小:

scale_transform = torchvision.transforms.RandomResizedCrop(224, scale=(0.08, 1.0), ratio=(1.0, 1.0))
images_scaled = scale_transform(images_original)

但我也想知道比例因子。我如何获得这些比例因子,或者以不同的方式解决这个问题?

如果我没理解错的话,你想知道裁剪部分的调整比例。您可以通过计算裁剪部分的xy尺寸并将其除以您想要获得的尺寸来获得它。

class MyRandomResizedCrop(object):
    def __init__(self, size, scale, ratio):
        self.t = torchvision.transforms.RandomResizedCrop(size, scale=scale, ratio=ratio)
        self.size = size
        self.scale = scale
        self.ratio = ratio
        
    def __call__(self, sample):
        sample = F.to_pil_image(sample)
        crop_size = self.t.get_params(sample, self.scale, self.ratio)

        x_size = crop_size[2] - crop_size[0]
        y_size = crop_size[3] - crop_size[1]

        x_ratio = sample.size[0] / x_size
        y_ratio = sample.size[1] / y_size
        ratio = (x_ratio, y_ratio) 
        
        output = F.crop(sample, *crop_size)
        output = F.resize(output, self.size)
        
        return ratio, output
        
import torchvision
from PIL import Image
import torchvision.transforms.functional as F

size = 244
scale = (0.08, 1.0)
ratio = (1.0, 1.0)

t = MyRandomResizedCrop(size, scale, ratio)

img = torch.rand((3,1024,1024), dtype=torch.float32)

r, img = t(img)

阅读 RandomResizedCrop 源代码后,我意识到它是以相同的方式裁剪和调整批处理中所有图像的大小,如果没问题的话。我也处于这种情况(未在我的原始问题中指定),我知道我的原始图像是正方形的,因此 resized/scaled 图像也是正方形,因为我保持 height/width 比率。下面是我编写的函数来执行我需要的操作(但是对批次中的所有图像进行了样本缩放)。我还定义了 scale,如果它大于 1.0,图像将被裁剪,调整大小后结果看起来“更大”。这是 RandomResizedCrop.

scale 参数的倒数
import torchvision.transforms.functional as F
from torchvision.transforms.functional import InterpolationMode

def scale_batch(imgs, max_scale):
    # imgs shape is (batch, channel, height, width) and height must equal width
    assert imgs.shape[2]==imgs.shape[3]
    assert max_scale >= 1.0
    scale_approximate = torch.rand(1).item() * (max_scale-1.0) + 1.0
    hw_original = imgs.shape[2]
    hw_crop = int(round(hw_original / scale_approximate))
    scale_actual = hw_original / hw_crop
    top, left = torch.randint(0, hw_original-hw_crop+1, (2,))
    imgs_scaled = F.resized_crop(imgs, top, left, hw_crop, hw_crop, (hw_original, hw_original), InterpolationMode.BILINEAR)
    return imgs_scaled, scale_actual