街景字符识别2-图像读取及图像增广

1 目的

  1. PIL读取数据
  2. PIL+Torch生成小批量图像数据样本
  3. 理解Baseline中torchvision.transforms进行图像增广的基本使用方法。

2 图像读取

Python中完成数据读取操作,比较常用的是Pillow和OpenCV、。注意:Image.open()读取的通道顺序是RGB,cv2.imread()读取的通道顺序为BGR。

单一图像读取:

2.1 Pillow

  1. Pillow的官方文档
  2. 读取及图像增强操作示例
  3. 图像格式转换.
    注:模式“RGB”转换为模式“L”以后,像素值为[0,255]之间的某个数值。而从模式“L”转换成“RGB”时,“RGB”的三个通道都是模式“L”的像素值的拷贝。
    这里有个问题
  • 原始数据是L模式,CHANEL为1?PIL数据已经转成RGB,这时候数据是CHANEL为3吗?
from PIL import Image 

# 读取图片
im =Image.open('lena.jpg’)    
# 应用模糊滤镜:
im2 = im.filter(ImageFilter.BLUR)
#缩放原图
im.thumbnail((w//2, h//2))
im.save('thumbnail.jpg', 'jpeg')
  1. 增强过滤器
 from PIL.ImageFilter import BLUR,GaussianBlur #模糊滤波

这里提到模糊滤波是为后期的模型优化做准备,阿水的第一期分享中提到模糊优化,大概是因为OCR识别等图像识别中在图像特征提取之前经常通过smooth/blur来使图像噪声降低、在二值化之前通过smooth/blur把不必要的噪声去掉,以免影响对准确的对象的提取。

2.2 OpenCV

OpenCV在功能上比Pillow更加强大。

  1. Python - Opencv 之 基础操作与变化操作
  • 图像读入[cv2.imread()]、显示[cv2.imshow()]与保存[cv2.imwrite()]
  • 变换操作:翻转图片[cv2.flip()]、颜色空间转换[cv2.cvtColor()]
  1. Python - Opencv 之 Canny 边缘检测理论及具体实现
   import cv2
    import numpy as np
    from matplotlib import pyplot as plt

    img = cv2.imread('lena.jpg',0)
    edges = cv2.Canny(img, 100, 200)

    plt.subplot(121),plt.imshow(img,cmap = 'gray')
    plt.title('Original Image'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(edges,cmap = 'gray')
    plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
  1. Python - Opencv 之平滑与模糊滤波

batch图像读取:

这个说法并不准确,batch样本是为了训练模型,实际还是基于单体图像读取(这里使用PIL),封装成一个torch.utils.data.dataset的子类,然后将其传入torch.utils.data.DataLoader来创建一个读取小批量数据样本的DataLoader实例,完成batch样本提取。

import torch,glob
from PIL import Image 

'''第一步 生成数据集'''
class SVHNDataset(torch.utils.data.dataset.Dataset):
	def __init__(self,img_path,img_label,transform=None):
	'''
	Args:
	img_path 单个图像路径
	img_label 单个图像标签
	transform 为图像增广做准备
	'''
        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):
		'''
		Args:
		index 图像序号
		
		output:
		img 单一图像特征序列
		torch.from_numpy(np.array(lbl[:5])) 单一图像的定长字符标签

		'''
		# 读取图片并转换为RGB格式
        img = Image.open(self.img_path[index]).convert('RGB')

        if self.transform is not None:
            img = self.transform(img)
        
        # 将不定长的变迁转换成设置长度为5的定长字符串
        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')  #提取所有训练集png文件路径
train_path.sort() #路径排序
train_json = json.load(open('../input/train.json')) #读取训练集标签及边界框信息
train_label = [train_json[x]['label'] for x in train_json]  #生成训练集标签
print(len(train_path), len(train_label))
dataset = SVHNDataset(train_path, train_label,transform=None) #定义训练数据集。
'''!!!这里transform=None应该会出错【待确认】,至少需要指定参数 transform = transforms.ToTensor() 使所有数据转换为 Tensor ,如果不进行转换则返回的是PIL图片。 transforms.ToTensor() 将尺寸为 (H x W x C) 且数据位于[0, 255]的PIL 图片或者数据类型为 np.uint8 的 NumPy 数组转换为尺寸为 (C x H x W) 且数据类型为 torch.float32 且位于[0.0, 1.0]的 Tensor 。'''

'''第二步 读取小批量'''
batch_size=40 #小批量样本量
shuffle=True #样本的读取顺序是随机的
train_loader = torch.utils.data.DataLoader(
    dataset, 
    batch_size=batch_size, 
    shuffle=shuffle, 
    num_workers=0)
for i, (inputs, targets) in enumerate(train_loader):
	print(inputs,targets) #inputs是随机读取的长度为batch_size的Tensor,其中每一个分别为各个图像的尺寸为 (C x H x W) 且数据类型为 torch.float32 且位于[0.0, 1.0]的 Tensor。
	#targetss是对应的40个标签。
	break

3 图像增广

3.1 基础知识

数据扩增(Data Augmentation)操作的目的是为了增加训练集的数量缓解过拟合

大规模数据集是成功应用深度神经网络的前提。图像增 广(image augmentation)技术通过对训练图像做一系列随机改变,来产生相似但又不同的训练样本,从而扩大训练数据集的规模。图像增广的另一种解释是,随机改变训练样本可以降低模型对某些属性的依赖,从而提高模型的泛化能力。例如,我们可以对图像进行不同方式的裁剪,使感兴趣的物体出现在不同位置,从而减轻模型对物体出现位置的依赖性。我们也可以调整亮度、色彩等因素来降低模型对色彩的敏感度。可以说,在当年AlexNet的成功中,图像增⼴技术功不可没。
——《动手学深度学习》李沐

  1. 阿水——Kaggle知识点:数据扩增方法
  2. PyTorch源码解读之torchvision.transforms

目前Baseline里用到transfrom的顺序依次是Resize、RandomCrop、ColorJitter、RandomRotation、ToTensor、Normalize。

  • Resize(size=(h, w)):resize输出尺寸为(h, w).
  • RandomCrop(size=(h, w)):crop时的中心点坐标是随机的,每次crop生成的图像都是有差异的,输出尺寸为(h, w)。
  • ColorJitter(brightness,contrast,saturation):修改输入图像的3大参数值:brightness, contrast and saturation,也就是亮度,对比度,饱和度。
  • RandomRotation(degrees):随机旋转输入图像。
  • ToTensor():Convert a PIL Image((H x W x C),[0, 255]) or numpy.ndarray to tensor 的过程, 输出尺寸为 (C x H x W) 且数据类型为 torch.float32 且位于 [0.0, 1.0] 的 Tensor 。在PyTorch中常用PIL库来读取图像数据,因此这个方法相当于搭建了PIL Image和Tensor的桥梁。 另外要强调的是在做数据归一化之前必须要把PIL Image转成Tensor,而其他resize或crop操作则不需要。
  • Normalize(mean,std):数据标准化【(X-mean)/std】,主要是取消梯度量级的差异,使得剃度始终朝着最小值的方向前进,加速收敛。在调用Normalize的时候,输入得是Tensor。

3.2 torchvision.transforms进行图像增广

这里存在一些问题,比如

  • Resize的Size(64,128)有没有什么依据?PIL转成RGB后数据CHANEL影响这个数字吗?验证集(60,120)是搞混了吧?是否需要训练集、验证集、测试集数据都一样?
  • RandomCrop不应该对测试集进行处理吧?改成对训练集处理?
  • RandomRotation里旋转5度会不会影响6和9的分类?
transform类型 训练集 验证集 测试集
Resize(size=(h, w)) (64, 128) (60, 120) (64, 128)
RandomCrop(size=(h, w)) × × (60, 120)
ColorJitter(brightness,contrast,saturation) (0.3, 0.3, 0.2) × ×
RandomRotation(degrees) 5 × ×
ToTensor()
Normalize(mean,std) [0.485, 0.456, 0.406], [0.229, 0.224, 0.225] [0.485, 0.456, 0.406], [0.229, 0.224, 0.225] [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
import torchvision.transforms as transforms
train_trans = 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])]) 
val_trans = transforms.Compose([
                    transforms.Resize((60, 120)),
                    # 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])])
test_trans = transforms.Compose([
                    transforms.Resize((64, 128)),
                    transforms.RandomCrop((60, 120)),
                    # 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])])

4 小结

学到知识心里高兴。

5 参考

动手学深度学习 PYTORCH 版(DEMO)
链接已各处贴上。

Have fun~
2020.5.23

你可能感兴趣的:(零基础入门CV赛事-,街景字符编码识别)