赞
踩
目录
transforms的底层并没有太过于复杂的代码和逻辑。他是由transforms.py里写的几个工具类来实现的功能和算法。图片通过transforms的工具处理,然后得出我们想得到的结果。
对于tensor我们首先得有一个最简单的认识,那就是他是一种图片打开的类型,关于这种类型我们常用的有三种,一种是PIL他是由Image.open()打开的,第二章就是tensor他是用ToTensor()打开的图片类型,最后一种就是narrays是cv.imread()打开的,这里我们先讲Tensor的用法和数据结构
- tensor_trans=transforms.ToTensor()
- tensor_img=tensor_trans(img)
- print(tensor_img)
我们来看上面这三行代码,之前我们说过,transforms这个包是个工具类,所以他下面有许许多多的工具类,而ToTensor这个类的就是为了将图片转换成Tensor形式。所以我们先创建一个ToTensor类的对象,但第二行代码就有些让人摸不清头脑了,这个时候我们来看源码:
- class ToTensor:
- """Convert a PIL Image or ndarray to tensor and scale the values accordingly.
- This transform does not support torchscript.
- Converts a PIL Image or numpy.ndarray (H x W x C) in the range
- [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0]
- if the PIL Image belongs to one of the modes (L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1)
- or if the numpy.ndarray has dtype = np.uint8
- In the other cases, tensors are returned without scaling.
- .. note::
- Because the input image is scaled to [0.0, 1.0], this transformation should not be used when
- transforming target image masks. See the `references`_ for implementing the transforms for image masks.
- .. _references: https://github.com/pytorch/vision/tree/main/references/segmentation
- """
-
- def __init__(self) -> None:
- _log_api_usage_once(self)
-
- def __call__(self, pic):
- """
- Args:
- pic (PIL Image or numpy.ndarray): Image to be converted to tensor.
- Returns:
- Tensor: Converted image.
- """
- return F.to_tensor(pic)
-
- def __repr__(self) -> str:
- return f"{self.__class__.__name__}()"
我们发现在这个类里只有三个函数,第一个是初始化函数,第三个是相当于java里面的toString方法,就是为了返回一个字符串,但造成上面的结果的第二个函数。就是__call__()
讲到这个函数,我们就得讲到一个概念,就是就是可调用对象。我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,如果你想确定某个对象是否是课调用对象可以用到callable。很明显,我们平时的类对象是不可调用对象,因为我们平时除了初始化的时候可以类名(参数)这样写,但对于类对象我们基本是不会怎么写的,所以在这里__call__函数就是将实例对象转换成了可调用对象,这里我举了一个例子:
- class Person:
- def __call__(self, name):
- print("__call__"+"hello"+name)
- def hello(self, name):
- print("hello"+name)
-
- person = Person()
- person(name="zhangsan")
- person.hello("list")
就像上面这样,我们定义了一个Person类,在person类里面写了两个函数,然后对其调用,结果如下:
我们发现如果你直接调用实例对象并往里面传参,代码就会调用__call__()函数并调用他的函数块,而Tensor类这里也是一样,
tensor_img=tensor_trans(img)
如果你直接往实例对象里面传参他就会,调用__call__()函数,但其实他和tensor_trans.__call__(img)这个函数是一样的,但把实例对象转化成可调用对象是这个函数的特性。然后就会调用对应的函数块,如下:
- def __call__(self, pic):
- """
- Args:
- pic (PIL Image or numpy.ndarray): Image to be converted to tensor.
- Returns:
- Tensor: Converted image.
- """
- return F.to_tensor(pic)
对于F.to_tensor(pic)这个语句,pic这个参数可以是PIL或是numpy数据类型,但F这个似乎没有见过对应的库,因为在transforms库里面,用了这样一个语句:
from . import functional as F
这段代码语句 from . import functional as F
在Python中是一种导入模块的方式。
from .
: 这表示从当前目录中导入模块。import functional as F
: 这表示导入名为functional
的模块,并将其重命名为F
,以便在代码中更方便地引用。 所以,这行代码的意思是从当前目录中导入名为functional
的模块,并将其重命名为F
,以后可以使用F
来访问这个模块中的函数和变量。而to_tensor()这个函数就是把img转换成Tensor数据类型:
- def to_tensor(pic) -> Tensor:
- """Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor.
- This function does not support torchscript.
- See :class:`~torchvision.transforms.ToTensor` for more details.
- Args:
- pic (PIL Image or numpy.ndarray): Image to be converted to tensor.
- Returns:
- Tensor: Converted image.
- """
- if not torch.jit.is_scripting() and not torch.jit.is_tracing():
- _log_api_usage_once(to_tensor)
- if not (F_pil._is_pil_image(pic) or _is_numpy(pic)):
- raise TypeError(f"pic should be PIL Image or ndarray. Got {type(pic)}")
-
- if _is_numpy(pic) and not _is_numpy_image(pic):
- raise ValueError(f"pic should be 2/3 dimensional. Got {pic.ndim} dimensions.")
-
- default_float_dtype = torch.get_default_dtype()
-
- if isinstance(pic, np.ndarray):
- # handle numpy array
- if pic.ndim == 2:
- pic = pic[:, :, None]
-
- img = torch.from_numpy(pic.transpose((2, 0, 1))).contiguous()
- # backward compatibility
- if isinstance(img, torch.ByteTensor):
- return img.to(dtype=default_float_dtype).div(255)
- else:
- return img
-
- if accimage is not None and isinstance(pic, accimage.Image):
- nppic = np.zeros([pic.channels, pic.height, pic.width], dtype=np.float32)
- pic.copyto(nppic)
- return torch.from_numpy(nppic).to(dtype=default_float_dtype)
-
- # handle PIL Image
- mode_to_nptype = {"I": np.int32, "I;16" if sys.byteorder == "little" else "I;16B": np.int16, "F": np.float32}
- img = torch.from_numpy(np.array(pic, mode_to_nptype.get(pic.mode, np.uint8), copy=True))
-
- if pic.mode == "1":
- img = 255 * img
- img = img.view(pic.size[1], pic.size[0], F_pil.get_image_num_channels(pic))
- # put it from HWC to CHW format
- img = img.permute((2, 0, 1)).contiguous()
- if isinstance(img, torch.ByteTensor):
- return img.to(dtype=default_float_dtype).div(255)
- else:
- return img
从注释我们可以看出来,往这里面传的参数pic可以是PIL Image 或 numpy.ndarray,然后返回一个Tensor()类型,所以对于ToTensor()类的使用我们完整的代码应该是:
- img_path="D:\\pythonData\\ten\\face_image1.jpg"
- img=Image.open(img_path)
- tensor_trans=transforms.ToTensor()
- print(tensor_trans)
- tensor_img=tensor_trans(img)
- print(tensor_img)
然后我们用前面讲过的SummaryWriter类的writer.add_image()方法把图片数据放入tensorboard如下:
在上述代码里面我们用了print(tensor.img)我们打印出了tensor的数据,结果如下:
我们单从打印结果来看,tensor似乎是一个三维数组,在深度学习的知识里面,tensor也叫张量。张量一般和向量和矩阵放在一起来理解。他们是不同维度的数据。例如,向量是一阶张量,矩阵是二阶张量,也就是说张量是多维数组,目的是把向量和矩阵推向更高的维度。因为张量其实是更高维度的向量,所以向量的一些数学性质他也是有的。在我们开始处理图象的时候,张量就更加重要,因为图像一般以n维数组的形式出现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。