街景字符编码识别-Task2:数据读取与数据扩增

街景字符编码识别-Task2:数据读取与数据扩增

2.1 学习目标

  • 学习Python和Pytorch中图像读取
  • 学会扩增方法和Pytorch读取赛题数据

2.2 图像读取

2.2.1 Pillow

from PIL import Image
import numpy as np
#1.图片读取
im = Image.open("./imgs/000000.png")
#2.转换为数组
a = np.asarray(im)
# print(a)
#3.将数组转变为图像
im = Image.fromarray(a)
#4.旋转
im.rotate(45).show()
#5.复制图片
im_copy = im.copy()
#6.截取矩形框内图片,(左、上、右、下)-元组
(left, upper, right, lower) = (246, 77, 246+81, 77+219)
im_crop = im.crop((left, upper, right, lower))
#7.模糊滤镜
from PIL import ImageFilter
im_blurred = im_copy.filter(filter=ImageFilter.BLUR)
im_blurred.show()
#8.Returns ('R', 'G', 'B') 判读图像颜色通道
print(im_copy.getbands())
#9.计算图像非空白区域,即判断图像大小,图像完全为空则返回None
print(im_copy.getbbox())
#10.变换大小
(width, height) = (im.width // 2, im.height // 2)
im_resized = im_copy.resize((width, height))
im_resized.show()
#11.保存
im_resized.save('./1.jpg')
#12.获得图片中单个通道图片
r_img = im_copy.getchannel('R')
r_img.show()
#13.图像变换Image.FLIP_LEFT_RIGHT左右变换(镜像)、Image.FLIP_TOP_BOTTOM上下变换(倒置)、
#Image.ROTATE_90, Image.ROTATE_180, Image.ROTATE_270旋转90,180,270
# PIL.Image.TRANSPOSE镜像后旋转90
# or PIL.Image.TRANSVERSE镜像后逆时针旋转90
im_flipped = im_copy.transpose(method=Image.TRANSPOSE)
im_flipped.show()
#14.添加字体
from PIL import Image, ImageDraw, ImageFont
# get an image 添加亮度通道
base = Image.open('./imgs/000000.png').convert('RGBA')
#创建相同大小的图片用于书写文字
txt = Image.new('RGBA', base.size, (255,255,255,0))
# get a font,字体,字号
fnt = ImageFont.truetype(r'‪C:\Windows\Fonts\simsun.ttc', 40)
# 定义书写内容
d = ImageDraw.Draw(txt)
# 其实坐标,内容,颜色
d.text((10, 10), "Hello", font=fnt, fill=(255,255,255,128))
# draw text, full opacity
d.text((10, 60), "World", font=fnt, fill=(255,255,255,255))
#文字图与原图融合
out = Image.alpha_composite(base, txt)
out.show()

2.2.2 OpenCV

import cv2
img=cv2.imread('./1.jpg')
#img=cv2.imread('./1.jpg',0)  0为转变为灰度图,无参数或1为彩色图像读入,-1为加载图像,包括alpha通道

#图片显示
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()

#关键字用法
img = cv.imread('D:/desktop/18.jpg',0)
cv.imshow('image',img)
k = cv.waitKey(0)
if k == 27 : #等待ESC退出
    cv.destroyAllWindows()
elif k == ord('s'): #等待关键字,保存和退出
    cv.imwrite('zhang.png',img)
    cv.destroyAllWindows()

#读取视频
#保存视频
cap = cv.VideoCapture(0)
#定义编码器并创建VideoWriter对象
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi',fourcc,20.0,(640,480))
while cap.isOpened():
    ret,frame = cap.read()
    if not ret:
        print('canot')
        break
    # frame = cv.flip(frame,0) 控制视频的翻转
    #写翻转的框架
    out.write(frame)
    cv.imshow('frame',frame)
    if cv.waitKey(5)==ord('q'):
        break
#完成工作后释放所有内容
cap.release()
out.release()
cv.destroyAllWindows()
#图像绘制
# #颜色BGR
# #创建黑色的图像
# img = np.zeros((512,512,3), np.uint8)
# #绘制一条厚度为5的蓝色对角线
# cv.line(img, (0, 0), (511,511), (255, 0, 0), 5)
#
# #绘制矩形 指定左上角和右下角
# cv.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
# #绘制圆圈  指定中心坐标和半径
# cv.circle(img, (447, 63), 63, (0, 0, 255))
# #绘制椭圆 中心位置,长轴长,短轴长,旋转角度等
# cv.ellipse(img, (256, 256), (100, 50), 0, 0, 180, 255, -1)
#
# #绘制多边形
# pts = np.array([[10, 5], [20, 30], [70, 20], [50, 10]], np.int32)
# pts = pts.reshape((-1, 1, 2))
# cv.polylines(img, [pts], True, (0, 255, 255))
#
# #添加文本  位置指定左下角坐标  字体 字体大小 颜色 粗细 线条类型
# font = cv.FONT_HERSHEY_SIMPLEX
# cv.putText(img, 'opencv', (10, 500), font, 4, (255, 255, 255), 2, cv.LINE_AA)
#
# cv.imshow('img', img)
# cv.waitKey(0)
# cv.destroyAllWindows()

#图像绘制
img =cv.imread('zhang.png')
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img, 'zhang', (30, 350), font, 4, (255, 255, 255), 2, cv.LINE_AA)
cv.imshow('img', img)
cv.imwrite('ying.png', img)
cv.waitKey(0)
cv.destroyAllWindows()
#几何变换
#缩放
# img = cv.imread('18.jpg')
# print(img.shape)
# #倍数变化
# # res = cv.resize(img, None, fx=2, fy=2, interpolation=cv.INTER_CUBIC)
# #指定大小
# res = cv.resize(img, (500, 500), interpolation=cv.INTER_CUBIC)
# cv.imshow('res', res)
# print(res.shape)
# cv.waitKey(0)
# cv.destroyAllWindows()

# #平移
# img = cv.imread('18.jpg')
# rows, cols, channels = img.shape
# #平移100,50
# m = np.float32([[1, 0, 100], [0, 1, 50]])
# res = cv.warpAffine(img, m, (cols, rows))#第三参数为输出图像的大小,先列后行
# cv.imshow('res', res)
# cv.waitKey(0)
# cv.destroyAllWindows()

# 旋转
# img = cv.imread('18.jpg')
# rows, cols, channels = img.shape
# #中心坐标, 角度, 图像的显示比例
# m = cv.getRotationMatrix2D(((cols-1)/2, (rows-1)/2), 90, 1)
# res = cv.warpAffine(img, m, (cols, rows))
# cv.imshow('res', res)
# cv.waitKey(0)
# cv.destroyAllWindows()

2.3 数据扩增方法

  • 2.3.1 数据扩增介绍
    在深度学习中数据扩增方法非常重要,数据扩增可以增加训练集的样本,同时也可以有效缓解模型过拟合的情况,也可以给模型带来的更强的泛化能力。
  • 2.3.2 常见的数据扩增方法
    在常见的数据扩增方法中,一般会从图像颜色、尺寸、形态、空间和像素等角度进行变换。当然不同的数据扩增方法可以自由进行组合,得到更加丰富的数据扩增方法。
  • 2.3.3 常用的数据扩增库
  • torchvision
    https://github.com/pytorch/vision
    pytorch官方提供的数据扩增库,提供了基本的数据数据扩增方法,可以无缝与torch进行集成;但数据扩增方法种类较少,且速度中等;
# (1)torchvision.transforms.Resize():用于对载入的图片数据按我们需求的大小进行缩放。传递给这个类的参数可以使一个整形数据,也可以是一个类似于(h,w)的序列,其中,h代表高度,w代表宽度,但是如果使用的是一个整形数据,那么代表缩放的宽度和高度都是这个整形数据的值。
#
# (2)torchvision.transforms.Scale:用于对载入的图片数据按我们需求进行缩放,和torchvision.transforms.Resize()用法类似。
#
# (3)torchvision.transforms.CenterCrop:用于对载入图片以图片中心为参考点,按照需求进行裁剪。
#
# (4)torchvision.transforms.RamdomCrop:用于对载入的图片按需求进行随机裁剪。
#
# (5)torchvision.transforms.RandomHorizontalFlip:对载入图片按随机概率进行水平翻转,默认概率值为0.5.。
#
# (6)torchvision.teansforms.RandomVerticalFlip:对载入图片按随机概率进行垂直翻转,默认概率值为0.5。
#
# (7)torchvision.transoforms.ToTensor:对载入图片进行类型转换,将PIL图片数据转换为Tensor数据类型数据。
#
# ex:transform=transforms.Compose([transform.ToTensor(),transforms.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])])
#也就是说(0,1)-0.5/0.5=(1-,1),即将数据归一化为[-1,1]的张量
result_img = transform(img)
# (8)torchvison.transforms.ToPILImage:将Tensor变量数据转换为PIL图片数据,方便显示。
  • imgaug
    https://github.com/aleju/imgaug
    imgaug是常用的第三方数据扩增库,提供了多样的数据扩增方法,且组合起来非常方便,速度较快;
from imgaug import augmenters as iaa
import numpy as np
import imgaug as ia
import cv2
#使用该库,输入要求4D张量(N, height, width, channels) 或者3D张量RGB类型(height, width, channels)
#gray类型(height, width, 1)
#也可模拟网络输入的batch大小 shape(32,64,64,3)
img = cv2.imread('./img.jpg')
images = np.expand_dims(img, axis=0)#增加一个维度
#定义变换
seq = iaa.Sequential([
    iaa.Fliplr(p=0.5),  # 水平0.5的概率翻转
    iaa.Flipud(p=1),  ##垂直0.5的概率翻转
    iaa.Crop(percent=(0, 0.3), keep_size=True),  # 0-0.1的数值,分别乘以图片的宽和高为剪裁的像素个数,保持原尺寸
    iaa.Sometimes(p=1,
                  then_list=[iaa.GaussianBlur(sigma=(0, 0.5))], else_list=[iaa.Flipud(p=0.5), iaa.Flipud(p=0.5)]
                  ),  #以p的概率执行then_list的增强方法,以1-p的概率执行else_list的增强方法,其中then_list,else_list默认为None
    iaa.ContrastNormalization((0.75, 1.5), per_channel=True),  #0.75-1.5随机数值为alpha,对图像进行对比度增强,该alpha应用于每个通道
    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.3 * 255), per_channel=0.5),
    #loc 噪声均值,scale噪声方差,50%的概率,对图片进行添加白噪声并应用于每个通道
    iaa.Multiply((0.8, 1.2), per_channel=0.2),  #20%的图片像素值乘以0.8-1.2中间的数值,用以增加图片明亮度或改变颜色
    iaa.Affine(
        scale={"x": (0.8, 1.2), "y": (0.8, 1.2)},
        translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)},
        rotate=(-25, 25),
        shear=(-8, 8))
    #对图片进行仿射变化,缩放x,y取值范围均为0.8-1.2之间随机值,左右上下移动的值为-0.2-0.2乘以宽高后的随机值
    #旋转角度为-25到25的随机值,shear剪切取值范围0-360,-8到8随机值进行图片剪切
], random_order=True)  # 打乱定义图像增强的顺序
#调用变换
images_aug = seq.augment_images(images)
#将维度复原
images_aug = np.squeeze(images_aug, axis=0)
cv2.imwrite('result.jpg', images_aug)

  • ImageDataGenerator
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
# # 指定参数
# # rotation_range 随机旋转最大角度
# # width_shift_range 最大左右平移
# # height_shift_range 最大上下平移
# # zoom_range 随机放大或缩小
# #horizontal_flip=True 随机水平翻转
# #vertical_flip=True 随机上下翻转
#fill_mode 填充方式   fill_mode='constant',指定颜色填充,此时需要参数 cval=

data_gen_args_image = dict(
    rotation_range=360,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.1,
    zoom_range=0.1,
    horizontal_flip=True,
    fill_mode='nearest',
)
image_datagen = ImageDataGenerator(**data_gen_args_image)
#读取原图
img = load_img(r'C:\Users\Administrator\Desktop\datajpg\017.JPG')  # this is a PIL image, please replace to your own file path
x = img_to_array(img)  # this is a Numpy array with shape (3, 150, 150)
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 3, 150, 150) 增加维度
#数据增强
i = 0
seed = 1
for batch_x in image_datagen.flow(x, batch_size=1, save_to_dir=r'C:\Users\Administrator\Desktop\extend', save_prefix='jueyuanzi', save_format='jpeg', seed = seed):
    i += 1
    #定义增强次数
    if i > 9:
        break  # otherwise the generator would loop indefinitely

2.4 Pytorch读取数据

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])
            ]))

接下来我们将在定义好的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)  + (6 - len(lbl)) * [10]
        
        return img, torch.from_numpy(np.array(lbl[:6]))

    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 * height * width次序;后者为字符标签。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值