使用python查看图像数据
在学习图像分割前,发现对如何查看图像数据完全不熟悉,在查看了Fast.ai框架的源码后,本文记录了在图像数据为Tensor类型的情况下,显示图像数据的过程。
参考资料:fast.ai源码
1. 查看文件路径
本篇使用了CAMVID数据集,下载后文件目录结构如下所示:
以images为例,打开该文件夹后,有701张图片
有了图片路径,可以将所有图片的绝对路径存为一个list,如下所示:
def getImageFiles(path:str):"递归地查找图片文件"result = []for rootDir, Dir, files in os.walk(path):for file in files:if '.png' in file or '.jpg' in file:result.append(Path(path)/file)breakreturn result
img_path = 'C:/Users/ASUS/.fastai/data/camvid/images' #文件上级目录
imageFilesPath = getImageFiles(img_path)
此处rootDir代表文件夹路径,Dir代表下一级文件夹路径(如果在rootDir里之前创建过某个文件夹A,此处会保存A的路径字符串),这两个变量目前没啥用,files保存了rootDir下的所有文件的路径列表。
第二个loop用来做一个简单粗暴的过滤,过滤掉不是.PNG
,.JPG
格式的文件,并把.PNG
,.JPG
文件路径全部放入一个result列表里并return。
可以输出imageFilesPath[0]查看结果,如下所示:
WindowsPath('C:/Users/ASUS/.fastai/data/camvid/images/0001TP_006690.png')
标签图片文件在labels文件夹中,发现图片名有规律可循,如labels 中图片名字比images文件名字多一个‘_P’, 所以可以继续用上面的方式得到labels文件路径,也可以通过fast.ai教程里lambda来将图片文件名转换为标签图片名。
getLblPath = lambda x : path_lbl/f'{x:stem}'_P'{x.suffix}'
#测试用例
lbl_name = getLblPath(imageFilesPath[0])
imageFilesPath[0], lbl_name
运行结果为:
WindowsPath('C:/Users/ASUS/.fastai/data/camvid/images/0001TP_006690.png'),
(WindowsPath('C:/Users/ASUS/.fastai/data/camvid/labels/0001TP_006690_P.png'))
2. 显示图片
2.1 读取图片
数据集,标签路径已知后,就可以显示图片了,这里参考fastai源码,在显示图片的同时,return torch的tensor类型数据,将第3维度转为第1维度,如下所示:
def openImage(path:Path, figsize:tuple = (3, 3)):img = PIL.Image.open(path).convert('RGB')img = Tensor(np.array(img))img = pil2tensor(img, np.float32)img = img/255return img
这里使用PIL库来加载一个图片数据,并转为Tensor数据,最后返回这个数据。
2.2 读取标签图片
首先读取标签图片,但标签图片是2维的,为了和数据图片匹配,要扩展一个维度,并将第三个维度转到第一个维度上,再返回成Tensor,如下所示
def openMask(path:Path):img = PIL.Image.open(path).convert('L')#灰度图像模式img = pil2tensor(img, np.float32)return img
def pil2tensor(image:np.ndarray,dtype:np.dtype):"Convert PIL style `image` array to torch style image tensor."a = np.asarray(image)print(a.shape)if a.ndim==2 : a = np.expand_dims(a,2)a = np.transpose(a, (1, 0, 2))a = np.transpose(a, (2, 1, 0))return torch.from_numpy(a.astype(dtype, copy=False) )
#测试用例
mask = openMask(get_y_fn(imageFilesPath[10]))
image = openImage(imageFilesPath[10])#openImage会返回浮点 torch.Size([720, 960, 3])
mask.shape, image.shape
运行结果如下所示:
torch.Size([1, 720, 960])
torch.Size([3, 720, 960])
2.3 显示图片
如果是普通的三通道图片(RGB等)可以用imshow方法输入numpy数据来显示图片,将一维度和三维度转换(如[3, 720, 960]->[720, 960, 3]),但是标签数据只有一个通道,所以额外转换成二维的numpy输入([1, 720, 960]->[720, 960, 1]->[720, 960]),再显示图片。代码如下所示(参考fast.ai 源码):
def ifnone(a:Any,b:Any)->Any:return b if a is None else a
def image2np(image:Tensor)->np.ndarray:"Convert from torch style `image` to numpy/matplotlib style."res = image.cpu().permute(1,2,0).numpy()#此处作用是调换原有维度位置return res[...,0] if res.shape[2]==1 else res #抽取最后一个维度的第0个数据def show(img:Tensor, figsize:tuple=(3, 3), title:Optional[str]=None, hide_axis:bool=True,cmap:str=None, alpha:float=None):cmap = ifnone(cmap, 'viridis')fig, ax = plt.subplots(figsize=figsize)xtr = dict(cmap=cmap, alpha=alpha)ax.imshow(image2np(img.data), **xtr)if hide_axis: ax.axis('off')return axif title is not None: ax.set_title(title)
将mask 和 image 都作为show方法的输入,可以显示如下结果:
以上就是显示图片的方法。