FCN的图片预处理

1.如何处理mat文件

SBD数据集时常用于语义分割的数据集,图片数据的lbl文件时mat文件,这个文件要怎么处理啊

import numpy as np
import PIL.Image
import scipy.io
import torch
from torch.utils import data


lbl_file = '/home/mlxuan/project/DeepLearning/data/benchmark/benchmark_RELEASE/dataset/cls/2010_005556.mat'
mat = scipy.io.loadmat(lbl_file)

lbl = mat['GTcls'][0]['Segmentation'][0].astype(np.int32)

mat的格式很复杂 看不懂

lbl的值:lbl中只有0和另外一个值,表示这个图像中的类

lbl对应的原图:

使用tensorboardX将lbl可视化

from tensorboardX import SummaryWriter
writer  = SummaryWriter()
lbl = torch.from_numpy(lbl).long()
writer.add_image('lbl2',lbl)
writer.close()

2.遍历trainloader时,

如果batch_size不是1,那么每次输入的batch_size个Tensor就需要有相同的size,否则就不能遍历

如果batch_size=2,trainset的getitem2次返回的Tensor大小不同时,报错

将返回的Tensor变为同一大小后,错误消失,根据data的格式可知,getitem返回的Tensor需要同一大小

读取一张图片为PIL Image,转变为Tensor并归一化,然后在反变换为PIL Image的代码

import torch as t

from PIL import Image
im = Image.open('/home/mlxuan/project/DeepLearning/data/benchmark/benchmark_RELEASE/dataset/img/2008_000002.jpg')

#变换为Tensor

from torchvision import transforms as T
trans = T.Compose([T.ToTensor(), T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
img = trans(im)

从Tensor反变换为PIL Image

trans = T.Compose([T.Normalize([-0.485/0.229,-0.456/0.224,-0.406/0.225],[1/0.229,1/0.224,1/0.225]) ])
img2 = trans(img)

img3=img2*255
img3

img4 = T.ToPILImage()(img2)
img4

3.几种图像大小变换的方式

深度学习,由于需要batchsize操作,许多时候需要把图片变为同一大小

常见的两种方式:

from PIL import Image
im = Image.open('/home/mlxuan/project/DeepLearning/data/benchmark/benchmark_RELEASE/dataset/img/2008_000002.jpg')

   方式1:利用torchvision.transforms来操作,这种方式保持了纵横比信息,但是会丢掉边缘信息

T.Resize(224)保持图像的纵横比,按照窄边缩放为224

T.CenterCrop(224)中心裁剪为224

方式2:利用PIL Image的函数操作(这种方式失去了图像的纵横比信息,但是保持图像的边缘)

4.

将自己的图片定义为dataset,用dataloader遍历,并使用TensorBoardX可视化

'''定义自己的数据集'''
# coding:utf8
import os
from PIL import Image
from torch.utils import data
import numpy as np
from torchvision import transforms as T
import scipy.io
import  torch
import utils


def picFulPath(txtPath,rootImg,rootLbl):
    '''
    给定只包含图片文件名的txt和图片所在路径
    参数:txtPath  包含图片文件名的txt的路径  
         rootImg:图片所在的根文件夹
         rootLbl:标记文件所在的根目录
    :return: 包含图片绝对路径和图片文件名、包含标签绝对和标签和的txt文档
    
    '''
    #读取txtpath中的每一行,然后加上rootImag和rootLbl后写入新的txt文档
    f = open('./ImagAndLal.txt','w')
    fh = open(txtPath, 'r')
    #读取txtPath中的每一行,每一行都是图片文件的文件名,在每一行中加上绝对路径
    for line in fh:
        line = line.rstrip()  # 去掉改行最后的回车符号
        line = rootImg+line+'.jpg'+' '+rootLbl+line+'.mat'+'\n'#此处最好改为文件名的相加,而不是单纯的字符串相加
        f.write(line)
    f.close()
    fh.close()


class SBDClassSeg(data.Dataset):
    def __init__(self, txt_path, transforms=None,train=True):#此处train val test(指定此次的数据时用来做什么的,不同用处的数据集图片预处理方法不同,可以传入不同的txt_path即可)的指定应该用union

        '''
        dataset是为了dataloader而定义,dataloader是为了按照batch遍历数据集,所以dataset要制定数据集、获得数据集元素的方法,数据集长度
        dataset生成self.imgs,这是一个list,包含了数据集的所有图片组成的list
        参数:txt_path包含了每张图片的路径和图片的标签(语义分割时就是标记好的图片的路径)
            transforms表示该读取图片后,图片要进行的预处理,如果为None,则使用默认的预处理
        '''

        #1.指定数据集,常用的方法是给定图片路径的txt文档,将他们读入一个列表
        imgs=[]
        self.train=train
        fh = open(txt_path, 'r')
             #遍历整个txt文档,每张图片的路径作为list的一个元素
        for line in fh:
            line = line.rstrip()#去掉改行最后的回车符号
            words = line.split()
            imgs.append((words[0], words[1]))#words[0]是原图片的路径,words[1]是标记好的图片的标签
        self.imgs = imgs
        # 2.指定读入图片后的预处理
        if transforms is None:

            def transforms(img,lbl):
                #T.Resize T.CenterCrop将图片保持纵横比缩放裁剪为同一大小,
                #T.Tensor,T.Normalize 将图片转为[0,1]的Tensor,并归一化
                trans = T.Compose([T.Resize(224),T.CenterCrop(224),
                                   T.ToTensor(),
                           T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
                img = trans(img)

                #lbl时mat格式,处理参考https://blog.csdn.net/qq_32425195/article/details/85202552
                lbl = torch.from_numpy(np.array(lbl)).int()
                lbl[lbl == 255] = 0
                #T.ToPILImage()将tensor转为PILImage,然后做Resize和CenterCrop处理
                trans = T.Compose([T.ToPILImage(),T.Resize(224),T.CenterCrop(224),
                                   T.ToTensor()])
                lbl = trans(lbl.unsqueeze(0))
                return img,lbl

            def untransforms(img,lbl):
                #该trans是对已经归一化的tensor处理,得到归一化之前的Tensor
                trans = T.Compose([T.Normalize([-0.485/0.229,-0.456/0.224,-0.406/0.225],[1/0.229,1/0.224,1/0.225])])
                imgUntrans = torch.Tensor(img.shape)
                for i  in range(img.shape[0]):
                    imgUntrans[i]= trans(img[i])


                return imgUntrans,lbl




             # 常规的数据操作:(裁剪为统一大小,可选T.scale),(数据增强,如随机裁剪等 语义分割时一般不做这个),ToTensor()后+T.Normalize
            if self.train:#如果此次是训练集(训练集和验证集可能读取数据方法一样,但是预处理的过程不一样)
                self.transforms = transforms
                self.untransforms = untransforms
        fh.close()

    def __getitem__(self, index):#该方法是给定索引或键值,返回对应的值,常用在enumerate遍历数据集时
        '''返回一张图片的验证集和测试集的数据'''
        #从list中获取图片的路径
        img_path = self.imgs[index][0]
        lbl_path = self.imgs[index][1]
        #读取图片,为numpy格式
        im = Image.open(img_path)
          #lbl是mat格式,mat格式的处理参考https://blog.csdn.net/qq_32425195/article/details/85202552

        mat = scipy.io.loadmat(lbl_path)
        lbl = mat['GTcls'][0]['Segmentation'][0].astype(np.int32)
        im,lbl = self.transforms(im,lbl)

        return im,lbl

    def __len__(self):
        '''
        返回为数据集中所有图片的个数
        :return:
        '''
        return len(self.imgs)

if __name__ == '__main__':
    picFulPath('/home/mlxuan/project/DeepLearning/data/benchmark/benchmark_RELEASE/dataset/train.txt','/home/mlxuan/project/DeepLearning/data/benchmark/benchmark_RELEASE/dataset/img/','/home/mlxuan/project/DeepLearning/data/benchmark/benchmark_RELEASE/dataset/cls/')
    train_dataset = SBDClassSeg('./ImagAndLal.txt')
    from torch.utils.data import DataLoader
    trainloader = DataLoader(train_dataset,batch_size=2,shuffle=False,drop_last=True)
    V = utils.Visualizer()
    #按batch_size遍历trainloader
    for i,(data,label) in enumerate(trainloader):# 如果batch_size不是1,那么每次输入的batch_size个Tensor就需要有相同的size,否则就不能遍历。还可以用for data,label in trainloader:遍历
        #data,label = trainloader.dataset.untransforms(data,label)
        #label.unsqueeze_(1)

        V.plot_many('imgs'+str(i),data)
        V.plot_img('imgs' + str(i), label)

    V.close()

'''调用TensorBoardX中的函数,可视化
使用方法:
在文件当前目录执行tensorboard --logdir runs

首先调用 V = Visualizer()初始化类对象,在当前目录新建了文件
然后调用V.plotxx来绘图,绘图会实时显示
绘制完所有的图像,关闭当前的对象V.close()

'''
import torch
import torchvision.utils as vutils
import numpy as np
import torchvision.models as models
from torchvision import datasets
from tensorboardX import SummaryWriter


class Visualizer(object):
    def __init__(self,):  # env表示路径
        self.writer = SummaryWriter()

    def plot_many(self, tag,tensor):
        """
        用于一次绘制多张图像,每张图像需要有相同的通道数和分辨率,输入为tensor(要显示的图片数,每张图片的通道,每张图片的宽,每张图片的高)
        """
        __= vutils.make_grid(tensor)
        #with self.writer:
        self.writer.add_image(tag, __)
        self.writer.file_writer.flush()

    def plot_img(self,tag,img_tensor):
        """绘制一张图片"""
        #with self.writer:
        self.writer.add_image(tag,img_tensor)
        self.writer.file_writer.flush()
    def close(self):
        self.writer.close()

if __name__ == '__main__':
    V = Visualizer()
    _ = torch.rand(32,3,64,64)
    V.plot_many('img',_)
    V.plot_img('tag',torch.rand(3,224,224))
    V.close()

大小控制位224*224后的图片

label图

做了Normalize后直接显示的图片

猜你喜欢

转载自blog.csdn.net/qq_32425195/article/details/85202552
FCN