零基础⼊⻔CV-Task2 数据读取与数据扩增

3.1 学习目标

  1. 学习使用 Python 和 PyTorch 中读取图像
  2. 学会扩增方法和 PyTorch 读取赛题数据

3.2 图像读取

赛体重的数据是图像,赛题任务是识别图像中的字符。因此,我们首先要做的就是对数据进行读取操作,在 Python 中有很多库可以完成数据读取的操作,比较常见的有 Pillow 和 OpenCV。

3.2.1 Pillow

Pillow 是 Python 图像处理函式库(PIL)的一个分支。Pillow 提供了常见的图像读取和处理操作,而且可以与 IPython notebook 无缝集成,是应用比较广泛的库。

代码示例:

图片读取

from PIL import Image #导入 Pillow 库
IM= Image.open('cat.jpg') #图片读取

应用滤镜并保存滤镜之后的图像

from PIL import Image, ImageFilter
IM = Image.open('test.png')
im= Image.open('test.png')
im2 = im.filter(ImageFilter.BLUR) #应用滤镜
im2.save('blur.jpg', 'jpeg')
from PIL import Image
im = Image.open('test.png')
im.thumbnail((w//2, h//2))
im.save('thumbnail.png', 'png')

这只是最基础的操作,Pillow 还有很多图像操作,是图像处理的必备库。

Pillow 的官方文档ːhttps://pillow.readthedocs.io/en/stable/

3.2.2 OpenCV

OpenCV 是一个跨平台的计算机视觉库,最早由 Intel 开源得来。OpenCV 发展的非常早,拥有众多计算机视觉、数字图像处理和机器视觉等功能。OpenCV在功能上比 Pillow 更加强大很多,学习成本也高很多。

使用示例:

import cv2 # load opencv
img = cv2.imread('test.png') # opencv 默认颜色通道是 BGR,转化成 RGB
img = cv2.CvtColor(img, cv2.COLOR_BGR2RGB)

灰度化

import cv2
img_1 = cv2.read('test.png', 0) #零表示灰度处理
img_2 = cv2.read('test.png', cv2.COLOR_BGR2GRAY) #转换为灰度图

# 边缘检测
import cv2
img = cv2.read('test.png') 
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img, 20, 70)
cv2.imwrite('canny.jpg', edges) # 边缘检测

opencv 中包含了众多的图像处理的功能,opencv 包含了你能想得到的只要与图像相关的操作。此外 opencv 还内置了很多图像特征处理算法,如关键点检测、边缘检测和直线检测等。

opencv 官网:https://opencv.org

opencv Github: https://github.com/opencv/opencv

opencv 扩展算法库:https://github.com/opencv/opencv-contrib

3.3 数据扩增方法

在上一小节中初步介绍了 Pillow 和 opencv 的使用,现在回到赛题接到字符识别任务重。在赛体重我们需要对图像进行字符识别,因此我们需要完成数据的读取操作,同时也需要完成数据扩增操作。

3.3.1 数据扩增介绍

在深度学习中数据扩增方法非常重要,数据扩增可以增加训练集的样本,同时也可以有效缓解模型过拟合的情况,也可以给模型带来更强的泛化能力。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2K1KsIiO-1590278482051)(https://i.loli.net/2020/05/24/RUVnsvAJQhatdDe.png)]

数据扩增为什么有用?

在深度学习中模型的训练过程中,数据扩增是必不可少的环节。现有深度学习的参数非常多,一般的模型可训练的参数量基本上都是万到百万级别,而训练集样本的数量很难有这么多。

其次数据扩增可以扩展样本空间,假设我们现在的分类模型需要对汽车进行分类,左边是汽车A,右边是汽车B。如果不适用任何数据扩增方法,深度学习模型会从汽车车头的角度来进行判别,而不是汽车而具体的区别。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KKnRMlQ-1590278482057)(https://i.loli.net/2020/05/24/1oUdxuOSGP7634j.png)]

有哪些数据扩增方法?

数据扩增方法有很多:从颜色空间、尺度空间到样本空间,同时根据不同任务数据扩增都有相应的区别。

对于图像分类,数据扩增一般不会改变标签;对于物体检测,数据扩增会改变物体坐标位置;对于图像分割,数据扩增会改变像素标签。

3.3.2 常见的数据扩增方法

在常见的数据扩增方法中,一般会从图像颜色、尺寸、形态、空间和像素等角度进行变换。当然不同的数据扩增方法可以自由进行组合,得到更加丰富的数据扩增方法。以 torchvision 为例,常见的数据扩增方法包括:

  • teansforms.CenterCrop 对图片中心进行裁剪
  • tranfforms.ColorJitter 对图像颜色的对比度、饱和度和零度进行变换
  • transforms.FiveCrop 对图像四个角和中心进行裁剪得到五分图像
  • transforms.Grayscale 对图像进行灰度变换
  • transforms.Pad 使用固定值进行像素填充
  • transforms.RandomAffine 随机仿射变换
  • transforms.RandomCrop 随机区域裁剪
  • transforms.RandomHorizontalFlip 随机水平翻转
  • transforms.RandomRotation 随机旋转
  • transforms.RandomVerticalFlip 随机垂直翻转

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKKIzeSY-1590278482059)(https://i.loli.net/2020/05/24/3XYe9BG4CkA5bDl.png)]

在本次赛题中,赛题任务是需要对图像中的字符进行识别,因此对于字符图片并不能进行翻转操作。比如字符6经过水平翻转就变成了字符 9,会改变字符原本的含义。

3.3.3 常用的数据扩增库

torchvision

https://github.com/pytorch/vision

PyTorch 官方提供的数据扩增库,提供了基本的数据扩增方法,可以无缝与 torch 进行集成;但数据扩增方法种类少,且速度中等

imgaug

https://github.com/aleju/imgaug

imgaug 是常用的第三数据扩增库,提供了多样的数据扩增方法,且组合起来非常方便,速度较快

albumentations

https://albumentations.readthedocs.io

是常用的第三数据扩增库,提供了多样的数据扩增方法,对图像分类、语义分割,物体检测和关键点检测都支持,速度较快。

3.4 Pytorch 读取数据

由于本次赛题我们使用 PyTorch 框架讲解具体的解决方案,接下来将是解决赛题的第一步,使用 PyTorch 读取赛题数据。

在 PyTorch 中数据是通过 Dataset 进行封装,并通过 Dataloder 进行并行读取。所以我们只需要重载一下数据读取的逻辑就可以完成数据的读取。

import os, sys, glob, shutil, json
import cv2

from PIL import Image
import numpy as np

import torch
from torch.utils.data.dataset import Dataset
import torchvision.transforms as transforms

class SVHNDataset(Dataset):
	def __init__(self, img_path, img_label, transform=None):
 		self.img_path = img_path
 		self.img_label = img_label
 		if transform is not None:
 			self.transform = transform
 		else:
 			self.transform = None
 	def __getitem__(self, index):
 		img = Image.open(self.img_path[index]).convert('RGB')
 		if self.transform is not None:
 			img = self.transform(img)
 
 # 原始SVHN中类别10为数字0
 		lbl = np.array(self.img_label[index], dtype=np.int)
 		lbl = list(lbl) + (5 - len(lbl)) * [10]
 
 		return img, torch.from_numpy(np.array(lbl[:5]))
 	def __len__(self):
 		return len(self.img_path)
train_path = glob.glob('../input/train/*.png')
train_path.sort()
train_json = json.load(open('../input/train.json'))
train_label = [train_json[x]['label'] for x in train_json]
data = SVHNDataset(train_path, train_label,
 	transforms.Compose([
 	# 缩放到固定尺⼨
 	transforms.Resize((64, 128)),
 # 随机颜⾊变换
 	transforms.ColorJitter(0.2, 0.2, 0.2),
 # 加⼊随机旋转
 	transforms.RandomRotation(5),
 # 将图⽚转换为pytorch 的tesntor
 	# transforms.ToTensor(),
 # 对图像像素进⾏归⼀化
 	# transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])
 ]))

通过上述代码,可以将赛题的图像数据和对应标签进行读取,在读取过程中进行数据扩增,效果如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVP2ee5Y-1590278482066)(https://i.loli.net/2020/05/24/tb5IvkpOfAEVcxF.png)]

接下来我们将定义好的 Dataset 基础上构建 Dataloder,你可能会问有了 Dataset 为什么还要有 Dataloder?其实这两个是不同的概念,是为了实现不同的功能。

  • Dataset:对数据及的封装,提供索引方式对数据样本进行读取

  • dataloder:对 Dataset 进行封装,提供批量读取的迭代读取

    ​ 加入 Dataloder 后,数据读取代码改为如下:

    import os, sys, glob, shutil, json
    import cv2
    
    from PIL import Image
    import numpy as np
    import torch
    from torch.utils.data.dataset import Dataset
    import torchvision.transforms as transforms
    
    class SVHNDataset(Dataset):
    	def __init__(self, img_path, img_label, transform=None):
    	self.img_path = img_path
     	self.img_label = img_label
     	if transform is not None:
     		self.transform = transform
     	else:
     		self.transform = None
     		
    def __getitem__(self, index):
     	img = Image.open(self.img_path[index]).convert('RGB')
     	if self.transform is not None:
     		img = self.transform(img)
     
     # 原始SVHN中类别10为数字0
     	lbl = np.array(self.img_label[index], dtype=np.int)
     	lbl = list(lbl) + (5 - len(lbl)) * [10]
     
     	return img, torch.from_numpy(np.array(lbl[:5]))
     	def __len__(self):
     		return len(self.img_path)
     		
    train_path = glob.glob('../input/train/*.png')
    train_path.sort()
    train_json = json.load(open('../input/train.json'))
    train_label = [train_json[x]['label'] for x in train_json]
    
    train_loader = torch.utils.data.DataLoader(
     	SVHNDataset(train_path, train_label,
     	transforms.Compose([
     	transforms.Resize((64, 128)),
     	transforms.ColorJitter(0.3, 0.3, 0.2),
     	transforms.RandomRotation(5),
     	transforms.ToTensor(),
     	transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
     ])),
     	batch_size=10, # 每批样本个数
     	shuffle=False, # 是否打乱顺序
     	num_workers=10, # 读取的线程个数
    )
    for data in train_loader:
     break
    

    在加入 Dataloder后,数据按照批次获取,每批次调用 Dataset 读取单个样本进行拼接。此时 data 的格式为:

    torch.Size([10, 3, 64, 128]), torch.Size([10, 6])

    前者为图像文件,为 batchsize * chanel * width 次序;后者为字符标签。

    3.5 本章小结

    本章对数据读取进行了详细的讲解,并介绍了常见的数据扩增方法和使用,最后使用 PyTorch 框架对本次赛题的数据进行读取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值