零基础⼊⻔CV(二)——数据读取与扩增

Task2 数据读取与数据扩增

本章主要内容为常见的数据读取、数据扩增方法和使用Pytorch框架读取数据。
赛题链接:https://tianchi.aliyun.com/competition/entrance/531795/information

1、图像读取

Python有很多库可以完成图像读取,比较常见的有Pillow和OpenCV。

1.1、Pillow

from PIL import Image
img =Image.open('./mchar_train/000100.png')  #读取图片
img.show()  #显示图片

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

1.2、OpenCV

OpenCV包含了众多图像处理算法,还内置了很多图像特征处理算法,如关键点检测、边缘检测等。

import cv2
#读取显示图片
img = cv2.imread('./mchar_train/000100.png') 
cv2.namedWindow('image', cv2.WINDOW_AUTOSIZE) #创建一个窗口
cv2.imshow('image', img) #在指定的窗口中显示一幅图像
cv2.waitKey(0)  
cv2.destroyAllWindows() #删除建立的全部窗口,释放资源

OpenCV官网:https://opencv.org/
OpenCV Github:https://github.com/opencv/opencv
OpenCV扩展算法库:https://github.com/opencv/opencv_contrib

2、数据扩增

在深度学习中数据扩增方法非常重要,数据扩增可以增加训练集的样本,同时也可以有效缓解模型过拟合的情况,也可以给模型带来的更强的泛化能力。
数据扩增方法有很多:从颜色空间、尺度空间到样本空间,同时根据不同任务数据扩增都有相应的区别。对于图像分类,数据扩增一般不会改变标签;对于物体检测,数据扩增会改变物体坐标位置;对于图像分割,数据扩增会改变像素标签。

2.1、Pillow

from PIL import Image,ImageFilter,ImageEnhance
img = Image.open('./mchar_train/000100.png')  #读取图片

#### 1 创建缩略图 ####
w, h = img.size  # 获得图片宽高
img.thumbnail((w//2, h//2)) # 缩略图

#### 2 剪贴、粘贴、合并图像 ####
box = (25,5,55,35)  #坐标位置:左、上、右、下
img_box = img.crop(box)  #图片裁剪 
img.paste(img_box,(0,0,30,30))  #原图粘贴子图,注意box的像素与子图的宽高必须吻合

#### 3 分离、合并通道 ####
r,g,b=img.split()
img=Image.merge("RGB",(b,g,r))  #交换图像rgb波段

#### 4 几何变换 ####
resized_img = img.resize((200,100))  #调整图片大小 (w, h)
img_rotate = img.rotate(45)  #旋转图片,逆时钟旋转45度
img_transpose = img.transpose(Image.FLIP_LEFT_RIGHT)  # 图片转换;左右转换 FLIP_LEFT_RIGHT,上下转换 FLIP_TOP_BOTTOM,逆时针90度 ROTATE_90

#### 5 颜色变换 ####
img.convert('L')  #转为灰度图

#### 6 图像增强 ####
img_blur = img.filter(ImageFilter.BLUR)  #模糊滤波
img_detail = img.filter(ImageFilter.DETAIL)  #细节增强
img.point(lambda i:i*1.2)  #每个像素点扩大1.2倍
source=img.split()  #R,G,B=0,1,2
source[0].point(lambda i : i *1.2) 
img=Image.merge(img.mode,source)
#对比度
contrast_img = ImageEnhance.Contrast(img)
contrast_img.enhance(1.8).show('180%enhance Contrast')	#对比度增强1.8倍
#亮度
lighten_img = ImageEnhance.Brightness(img)
lighten_img.enhance(1.2).show('120%enchance brightness')  #亮度增强1.2倍
'''
ImageEnhance.Contrast(img) 对比度
ImageEnhance.Color(img) 色彩饱和度
ImageEnhance.Brightness(img) 亮度
ImageEnhance.Sharpness(img) 清晰度
'''

2.2、OpenCV

import cv2
img = cv2.imread('./mchar_train/000100.png') 

################################## 1 图像缩放 #################################
'''
函数原型: cv2.resize(InputArray src, OutputArray dst, Size, fx, fy, interpolation)
InputArray src:输入图片
OutputArray dst:输出图片
Size:图片尺寸
fx,fy:沿x,y轴的缩放系数
interpolation:插入方式
'''
#方法一
result=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
#方法二
height, width = img.shape[:2] #获取图片大小(长,宽,通道数),注意imread()读入的是按照(h, w)
result = cv2.resize(img,(2*width, 2*height),interpolation = cv2.INTER_CUBIC) #resize()的第二个参数为目标尺寸,格式为(w, h)
#方法三 不用resize函数
import numpy as np

height, width = img.shape[:2]
dstHeight,dstWidth = int(height*2),int(width*2)  #设定缩放后的图片大小

dstImage = np.zeros([dstHeight, dstWidth, 3], np.uint8)
for i in range(dstHeight):
    for j in range(dstWidth):
        iNew = i * ( height * 1.0 / dstHeight )
        jNew = j * ( width * 1.0 / dstWidth )
        dstImage[i,j] = img[int(iNew),int(jNew)]

################################## 2 图像平移 ##################################
'''
向(x,y)平移,创建变换矩阵M=[[1 0 x],[0 1 y]],并将其传递给cv.warpAffine()函数
'''
#方法一
height, width = img.shape[:2]
M = np.float32([[1,0,40],[0,1,20]])  #向(40,20)平移
dst = cv2.warpAffine(img,M,(width,height))

#方法二 创建空矩阵赋值
height, width = img.shape[:2]
x,y=40,20  #向(40,20)平移

dst=np.zeros(img.shape,np.uint8)
for i in range(y,height):
    for j in range(x,width):
        dst[i,j]=img[i-y,j-x]

################################## 3 图像旋转 ##################################
rows,cols = img.shape[:2] 
M = cv2.getRotationMatrix2D((cols/2,rows/2),45,1) #参数:旋转中心,旋转角度,缩放比例 
res = cv2.warpAffine(img,M,(cols,rows)) #参数:图像,旋转矩阵,变换后的图像大小 

################################## 4 图像增强 ##################################
#亮度和对比度
#OpenCV中亮度和对比度公式:g(x) = αf(x) + β,其中:α(>0)、β常称为增益与偏置值,分别控制图片的对比度和亮度。
#numpy.clip(a, a_min, a_max, out=None, **kwargs)限定数据范围
alpha = 0.3
beta = 80
img = np.uint8(np.clip((alpha * img + beta), 0, 255))

2.3、torchvision

import torchvision
from PIL import Image

img = Image.open('./mchar_train/000100.png') 
  • 2.3.1、裁剪Crop
#中心裁剪
centercrop = torchvision.transforms.CenterCrop((20,20)) #生成一个CenterCrop类的对象,用来将图片从中心裁剪成20*20
image = centercrop(img) 

#上下左右中心裁剪,获得5张图片
fivecrop=torchvision.transforms.FiveCrop((20,20))  
image=fivecrop(img)

#随机裁剪
randomcrop=torchvision.transforms.RandomResizedCrop((20,20))
image=randomcrop(img)

#上下左右中心裁剪后翻转,获得10张图片
tencrop=torchvision.transforms.TenCrop((20,20), vertical_flip=False) #vertical_flip 是否垂直翻转,默认为水平翻转
image=tencrop(img)
  • 2.3.2、翻转和旋转Filp and Rotation
#依概率p水平翻转
randomHfilp=torchvision.transforms.RandomHorizontalFlip(p=0.5)
image=randomHfilp(img)

#依概率p垂直翻转
randomVfilp=torchvision.transforms.RandomVerticalFlip(p=0.5)
image=randomVfilp(img)

#随机旋转
randomrotate=torchvision.transforms.RandomRotation(30, center=None) #degress若为30,表示在(-30,30)之间随机旋转,若为(30,60),表示在30-60度之间随机旋转,center可选中心旋转还是左上角旋转
image=randomrotate(img)
  • 2.3.3、图像变换
####重置图像分辨率####
resize=torchvision.transforms.Resize((5*8), interpolation=2) #size设定为h*w,interpolation插值方法,默认为PIL.Image.BILINEAR
image=resize(img)

####归一化####
#方法一
normalize = torchvision.transforms.Compose([torchvision.transforms.ToTensor(),torchvision.transforms.Normalize(std=(0.5,0.5,0.5),mean=(0.5,0.5,0.5))])# 归一化到(0,1)之后,再(x-mean)/std,归一化到(-1,1)
image = normalize(img)
'''
transforms.Normalize标准化
transforms.ToTensor将PIL Image或者 ndarray 转换为tensor,并且归一化至(0,1)
'''
#方法二 手动归一化
import torch
import numpy as np
img_temp1 = torch.from_numpy(np.array(img).transpose((2,0,1))) #重置图像的shape,(H,W,C)转为(C,H,W)
img_temp2 = img_temp1.float().div(255)
imgnorm = img_temp2.sub_(0.5).div_(0.5)
image.equal(imgnorm) #True

####修改亮度、对比度和饱和度####
colorjitter=torchvision.transforms.ColorJitter(brightness=0, contrast=2, saturation=2) #参数分别为亮度、对比度和饱和度
image=colorjitter(img)

####转灰度图####
grayimg=torchvision.transforms.Grayscale(1)
image=grayimg(img)

####填充####
imgpad=torchvision.transforms.Pad((10,5), fill=255, padding_mode='constant') #第一个参数设置填充多少个pixel
image=imgpad(img)

####仿射变换####
imgaffie=torchvision.transforms.RandomAffine(30, fillcolor=255)
image=imgaffie(img)

常用的数据扩增库
torchvision :https://github.com/pytorch/vision
imgaug :https://github.com/aleju/imgaug
albumentations :https://albumentations.readthedocs.io

3、Pytorch数据读取

在Pytorch中数据是通过DataSet进行封装,并通过DataLoder进行读取。

import os, sys, glob, shutil, json
import cv2
from PIL import Image
import numpy as np
import torch
import torchvision.transforms as transforms
from torch.utils.data.dataset import Dataset

#构建dataset
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, item):
        img = Image.open(self.img_path[item]).convert('RGB')#PIL读取数据为‘RGBA’格式
        if self.transform is not None:
            img = self.transform(img)
            
        lbl = np.array(self.img_label[item], dtype=np.int)
        #训练集图片的最长字符数为6,所以设置长度为6的label,并将空值填充0.
        lbl = list(lbl) + (6 - len(lbl)) * [0]
        return img, torch.from_numpy(np.array(lbl[:6]))

    def __len__(self):
        return len(self.img_path)

train_path = glob.glob('F:/tianchi_CV_entrance/mchar_train/*.png')
train_path.sort()
train_json = json.load(open('F:/tianchi_CV_entrance/mchar_train.json'))
train_label = [train_json[x]['label'] for x in train_json]

#加载dataset
train_loader = torch.utils.data.DataLoader(
    SVHNDataset(train_path, train_label,
                #transforms.Compose()类用来组合多个torchvision.transforms操作
                transforms.Compose([
                    transforms.Resize((64, 128)),
                    transforms.ColorJitter(0.3, 0.3, 0.2),    
                    transforms.RandomRotation(10),
                    transforms.ToTensor(),
                    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])   
    ])),
    batch_size=10,  #每批样本个数
    shuffle=False,   #是否打乱顺序
    num_workers=0,  #线程数
)

#构造iter对象,通过next函数对数据进行检查
x = iter(train_loader)
data = next(x)
img, label = data[0], data[1]
print(img.size())  #torch.Size([10, 3, 64, 128])  [batchsize , chanel , height , width]
print(label.size())  #torch.Size([10, 6])  [batchsize, 字符数]

你可能感兴趣的:(opencv,python,计算机视觉,机器学习)