Как загрузить несколько изображений в градациях серого как один тензор в pytorch?

В настоящее время я пытаюсь использовать стек, набор изображений как единый объект для каждой метки, чтобы обучить CNN использованию перекрестной проверки. Дан набор данных из изображений в оттенках серого 224x224x1, отсортированных по:

Root/
    Class0/image0_view0.png
    Class0/image0_view1.png
    Class0/image0_view2.png
    ...
    Class1/image0_view0.png
    Class1/image0_view1.png
    Class1/image0_view2.png

Как я могу объединить 3 изображения (вид 0, 1 и 2) как один тензор с размерами 224x224x3 (3 изображения в градациях серого)? Другими словами, как мне создать набор данных из стеков изображений в pytorch, используя ImageFolder / DatasetFolder и DataLoader? Придется ли мне реорганизовать свои папки и классы, или мне будет проще создавать стеки, когда я делаю разбиения для перекрестной проверки?

Спасибо за ваше время и помощь! Дайте мне знать, если я могу предоставить дополнительную информацию.


person jinsom    schedule 19.11.2019    source источник
comment
почему ты хочешь сделать это? Вы хотите, чтобы каналы вашего изображения были другими изображениями? Если я знаю причину, я смогу направить тебя лучше. Похоже, что то, что вы хотите, может вообще не требовать pytorch. Вам просто нужно прочитать изображения и сложить их, а затем сохранить как новое изображение с 3 каналами.   -  person jchaykow    schedule 19.11.2019
comment
Это имеет смысл для меня. Я хочу сделать это, потому что каждая метка не всегда видна только на одном изображении, и когда я попытался смонтировать все 3 изображения в одно изображение, CNN тоже не работала так хорошо.   -  person jinsom    schedule 20.11.2019
comment
Хорошо, мне кажется, что у вас проблема с классификацией, когда класс можно увидеть только с одного из трех «представлений» одного и того же объекта. Вместо того, чтобы объединять изображения вместе и пытаться классифицировать, я мог бы предложить просто сгенерировать классификации для всех трех изображений по отдельности, а затем объединить прогнозы в одно. Таким образом, если для view0 был предсказан класс 1, а для view1 не было предсказания, а для view2 был предсказан класс 2, общее предсказание было бы классами 1 и 2.   -  person jchaykow    schedule 20.11.2019
comment
Эти метки были созданы для набора изображений, поэтому, хотя ваше предложение определенно возможно, это потребует больше времени и затрат с точки зрения вычислений. Что вас беспокоит при наложении изображений?   -  person jinsom    schedule 20.11.2019


Ответы (2)


У меня была очень похожая задача. Мне нужно было загрузить случайную последовательность из 3 изображений как элемент пакета для обучения сети не на отдельных изображениях, а на последовательности изображений. Для размера пакета 8 у меня есть 8 x 3 = 24 изображения. Это похоже на разные взгляды в вашем случае. Я использовал функцию imread_collection из skimage.io. Я добавил такой getitem в класс Dataset:

def __getitem__(self, idx):
    idx_q = int(torch.randint(0 + self.boundary, self.length - self.boundary, (1,))) 
    
    q = imread_collection([self.image_paths[idx_q-1], self.image_paths[idx_q], self.image_paths[idx_q+1]], conserve_memory=True)
            
    if self.transform:
        q = torch.stack([self.transform(img) for img in q])

    return q, p, n

Здесь я генерирую случайный индекс изображения, а затем загружаю три последовательных изображения, используя imread_collection и self.image_paths, который представляет собой список с путями ко всем изображениям. Затем я трансформирую каждое изображение и складываю их. В вашем случае вам следует подумать об использовании правильных индексов, возможно, применив скользящее окно по длине self.image_paths.

Дополнительную информацию можно найти на форум torch. Я также пытался спросить и найти более элегантное решение, но не смог и успешно обучил модель с таким подходом.

person dinarkino    schedule 23.06.2021

Как загрузить несколько изображений в градациях серого как один тензор в pytorch?

В общем, количество каналов не важно.

Вам нужна операция, известная как «загрузка пакета данных». Для этого в PyTorch есть класс DataLoader. DataLoader классу дополнительно нужен Dataset класс.

Если в DataLoader размер пакета равен 64 (bs = 64), вы загрузите 64 изображения из одного раза в качестве тензора.

Если вы используете ImageFolder, это не вернет минибатч для ты. ImageFolder - это производный от Dataset класс.

Проблема с ImageFolder (если вы просто используете это) в том, что вы получите одно изображение для каждого индекса. Затем вы объедините несколько изображений в мини-серию.

Вот один пример использования ImageFolder с данными CIFAR10.

from torchvision import transforms
imagef = torchvision.datasets.ImageFolder(r'C:\Users\dj\data\cifar10\test', transform=transforms.ToTensor())

print(imagef)
print(imagef.classes)
img, label = imagef[0]
display(img)
print(img.size())
print(label)

Из:

Dataset ImageFolder
    Number of datapoints: 10000
    Root location: C:\Users\dj\data\cifar10\test
    StandardTransform
Transform: ToTensor()
['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']

tensor([[[0.6078, 0.6549, 0.6902,  ..., 0.7882, 0.7922, 0.7529],
         [0.6000, 0.6392, 0.6706,  ..., 0.7922, 0.7961, 0.7412],
         [0.6078, 0.6275, 0.6588,  ..., 0.8078, 0.8000, 0.7412],
         ...,
         [0.3490, 0.2235, 0.2392,  ..., 0.3490, 0.2314, 0.2627],
         [0.3490, 0.2353, 0.2471,  ..., 0.2235, 0.2392, 0.2941],
         [0.3608, 0.2353, 0.2392,  ..., 0.2353, 0.2510, 0.2863]], ...


torch.Size([3, 32, 32])
0

Следующий пример основан на DataLoader:

import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
import PIL.Image as Image

def pil_loader(path):    
    with open(path, 'rb') as f:
        img = Image.open(f)
        return img.convert('RGB')

ds = torchvision.datasets.DatasetFolder(r'C:\Users\dj\data\cifar10\test', 
                                        loader=pil_loader, 
                                        extensions=('.png'), 
                                        transform=transforms.ToTensor())
dl = DataLoader(ds, batch_size=2)
len(dl)
for imgs,lbls in dl:    
    print(imgs.size()) # torch.Size([2, 3, 32, 32])
    break 

Это DataLoader - то, что вам может понадобиться. Тот, который я представляю, имеет настраиваемую функцию загрузки: pil_loader.

Вы также можете использовать ImageFolder вместо DatasetFolder в предыдущем примере.

Это будет примерно так:

ds =  torchvision.datasets.ImageFolder(r'C:\Users\dj\data\cifar10\test', transform=transforms.ToTensor())
dl = DataLoader(ds, batch_size=3)
print(len(dl))

for imgs,lbls in dl:    
    print(imgs.size())
    break    
person prosti    schedule 20.11.2019
comment
Не думаю, что использование пакетов решит проблему. Кажется, OP захочет передать все 3 изображения как один вход, который входит в сеть и генерирует одну метку. В случае пакетов это приведет к количеству прогнозов, равных размеру пакета. - person Abhinav; 25.03.2021