1、数据的读取
1.1 对于图片的读取,一般计算机视觉领域常用的是opencv和pillow。
对于pillow库我用的比较少,所以我这里就介绍一下opencv库。opencv是Intel开源的计算机视觉库,它是由一系列c函数和少量的c++类构成,实现了图像处理和计算机视觉方面的很多通用算法。opencv拥有包括300多个c函数的跨平台的中、高层API。它不依赖于其它的外部库-尽管可以使用某些外部库。最重要的是opencv对于商业和非商业都是free的。它同时支持linux,windows,android平台,提供有python,c,c++,java的接口函数。
关于opencv的python接口函数的读取处理数据的简单用法,见下图:

1.2 pytorch对于图片数据的读取操作代码示例:
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])
]))
2、数据的增广
数据增广是深度学习中常用的技巧之一,主要用于增加训练集,让数据尽可能的多样化,使得训练的模型具有更强的泛化能力。现有的各大深度学习框架都已经自带了数据增广,它只是提供了接口函数。现在我们从:水平/垂直翻转,旋转,缩放,裁剪,剪切,平移,对比度,色彩抖动,噪声等几个方面讲解和实现数据增广。
所有的数据增广在操作的时候默认是以图像中心点进行的。从数学角度来看,任何操作都可以分成以下几个步骤:1、首先将旋转点移动到原点处;2、执行如下图所描述的绕原点旋转;3、再将旋转点移回到原来的位置;为了更好的理解见下图:

假设图像的原始坐标为(x1,y1),平移后的坐标为(x,y),则平移前和平移后的坐标关系为:
2.1、图像平移
平移是指所有的像素在x和y方向各平移一定距离,平移变换对应的数学矩阵为:
如图平移的具体实例(这里平移采用的是到映射填充)

2.2、图像翻转(图像镜像)
图像翻转包括水平翻转和垂直翻转。水平翻转的变换矩阵为:
垂直翻转的变换矩阵为:
翻转后的具体实例(这里是采用倒映射填充):

2.3、图像旋转
图像旋转是指以某个点(默认为图像中心点)为中心进行任意角度旋转,其变换矩阵为:
图像旋转图片(这里平移后采用的是到映射填充):

2.4、图像缩放:
图像缩放是指对当前图像进行任意尺度的缩放,其变换矩阵为:
缩放后的图片如下(这里平移后采用的是到映射填充):

2.5、图像错切:
其变换矩阵为:
错切的图像如下(这里平移后采用的到映射填充):

2.6、图像裁剪:
深度学习的图像裁剪的常用做法是将图片缩放到原图的1.1倍,然后在缩放后的图像上进行裁剪操作,具体的裁剪实例如下:

2.7、组合变换:
在深度学习中的数据增广一般会采用多种增广的方式的组合,根据其运算的规则,可以知道不同的组合顺序结果是不一样的。
为了更好地解释,假设给定平移变换矩阵Hshift ,旋转矩阵Hrotate,缩放矩阵Hscale ,为了说明这里我给出两个不同的组合变换.对于组合变换一,其组合后的矩阵如下:M = Hshift x Hrotate x Hscale;对于组合变换二,其组合后的矩阵如下:M = Hscale x Hrotate x Hshift,对于两种不同的组合其结果如下:

下边是数据增广的源码实现示例:
import numpy as np
import os
import cv2
import copy
class DataAugment:
def __init__(self,debug=False):
self.debug=debug
print("Data augment...")
def basic_matrix(self,translation):
"""基础变换矩阵"""
return np.array([[1,0,translation[0]],[0,1,translation[1]],[0,0,1]])
def adjust_transform_for_image(self,img,trans_matrix):
"""根据图像调整当前变换矩阵"""
transform_matrix=copy.deepcopy(trans_matrix)
height, width, channels = img.shape
transform_matrix[0:2, 2] *= [width, height]
center = np.array((0.5 * width, 0.5 * height))
transform_matrix = np.linalg.multi_dot([self.basic_matrix(center), transform_matrix, self.basic_matrix(-center)])
return transform_matrix
def apply_transform(self,img,transform):
"""仿射变换"""
output = cv2.warpAffine(img, transform[:2, :], dsize=(img.shape[1], img.shape[0]),flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT, borderValue=0,) #cv2.BORDER_REPLICATE,cv2.BORDER_TRANSPARENT
return output
def apply(self,img,trans_matrix):
"""应用变换"""
tmp_matrix=self.adjust_transform_for_image(img, trans_matrix)
out_img=self.apply_transform(img, tmp_matrix)
if self.debug:
self.show(out_img)
return out_img
def random_vector(self,min,max):
"""生成范围矩阵"""
min=np.array(min)
max=np.array(max)
print(min.shape,max.shape)
assert min.shape==max.shape
assert len(min.shape) == 1
return np.random.uniform(min, max)
def show(self,img):
"""可视化"""
cv2.imshow("outimg",img)
cv2.waitKey()
def random_transform(self,img,min_translation,max_translation):
"""平移变换"""
factor=self.random_vector(min_translation,max_translation)
trans_matrix=np.array([[1, 0, factor[0]],[0, 1, factor[1]],[0, 0, 1]])
out_img=self.apply(img,trans_matrix)
return trans_matrix, out_img
def random_flip(self,img,factor):
"""水平或垂直翻转"""
flip_matrix = np.array([[factor[0], 0, 0],[0, factor[1], 0],[0, 0, 1]])
out_img=self.apply(img,flip_matrix)
return flip_matrix, out_img
def random_rotate(self,img,factor):
"""随机旋转"""
angle=np.random.uniform(factor[0],factor[1])
print("angle:{}".format(angle))
rotate_matrix=np.array([[np.cos(angle), -np.sin(angle), 0],[np.sin(angle),np.cos(angle), 0],[0, 0, 1]])
out_img=self.apply(img,rotate_matrix)
return rotate_matrix, out_img
def random_scale(self,img,min_translation,max_translation):
"""随机缩放"""
factor=self.random_vector(min_translation, max_translation)
scale_matrix = np.array([[factor[0], 0, 0],[0, factor[1], 0],[0, 0, 1]])
out_img=self.apply(img,scale_matrix)
return scale_matrix, out_img
def random_shear(self,img,factor):
"""随机剪切,包括横向和众向剪切"""
angle = np.random.uniform(factor[0], factor[1])
print("fc:{}".format(angle))
crop_matrix = np.array([[1, factor[0], 0], [factor[1], 1, 0], [0, 0, 1]])
out_img=self.apply(img,crop_matrix)
return crop_matrix, out_img
if __name__=="__main__":
demo=DataAugment(debug=True)
img=cv2.imread("/pathto/dataArgu/wr.jpg")
# 平移测试
_,outimg=demo.random_transform(img,(0.1,0.1),(0.2,0.2)) #(-0.3,-0.3),(0.3,0.3)
# 垂直变换测试
_, outimg =demo.random_flip(img,(1.0,-1.0))
# 水平变换测试
_, outimg =demo.random_flip(img, (-1.0, 1.0))
# 旋转变换测试
_, outimg =demo.random_rotate(img,(0.5,0.8))
# # 缩放变换测试
_, outimg =demo.random_scale(img,(1.2, 1.2),(1.3,1.3))
# 随机裁剪测试
_, outimg =demo.random_shear(img,(0.2,0.3))
# 组合变换
t1,_=demo.random_transform(img,(-0.3,-0.3),(0.3,0.3))
t2,_=demo.random_rotate(img,(0.5,0.8))
t3,_=demo.random_scale(img,(1.5,1.5),(1.7,1.7))
tmp=np.linalg.multi_dot([t1,t2,t3])
print("tmp:{}".format(tmp))
out=demo.apply(img,tmp)
3、总结
图片数据读取和数据增广是计算机视觉,特别是搞深度学习的最最基础的部分了,可能对于没有cv基础的同学理解起来会有点困难。
网友评论