花园宝宝战队 ----- 一阶段代码注释成果 #10
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2019-2022 Huawei Technologies Co., Ltd
|
||||
# Copyright 2019 Huawei Technologies Co., Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,625 +13,178 @@
|
|||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
"""
|
||||
The module vision.py_transforms is mainly implemented based on Python PIL, which
|
||||
provides many kinds of image augmentation methods and conversion methods between
|
||||
PIL.Image.Image and numpy.ndarray. For users who prefer using Python PIL in computer vision
|
||||
tasks, this module is a good choice to process images. Users can also self-define
|
||||
their own augmentation methods with Python PIL.
|
||||
The module transforms.py_transform is implemented based on Python. It provides common
|
||||
operations including OneHotOp.
|
||||
"""
|
||||
import numbers
|
||||
import random
|
||||
|
||||
import json
|
||||
import sys
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
import mindspore.dataset.transforms.py_transforms as py_transforms
|
||||
from .validators import check_one_hot_op, check_compose_list, check_random_apply, check_transforms_list, \
|
||||
check_compose_call
|
||||
from . import py_transforms_util as util
|
||||
from .c_transforms import parse_padding
|
||||
from .py_transforms_util import is_pil
|
||||
from .utils import Border, Inter
|
||||
from .validators import check_adjust_gamma, check_alpha, check_auto_contrast, check_center_crop, check_cutout, \
|
||||
check_five_crop, check_hsv_to_rgb, check_linear_transform, check_mix_up, check_normalize_py, \
|
||||
check_normalizepad_py, check_num_channels, check_pad, check_positive_degrees, check_prob, check_random_affine, \
|
||||
check_random_color_adjust, check_random_crop, check_random_erasing, check_random_perspective, \
|
||||
check_random_resize_crop, check_random_rotation, check_resize_interpolation, check_rgb_to_bgr, check_rgb_to_hsv, \
|
||||
check_ten_crop, check_uniform_augment_py
|
||||
from .c_transforms import TensorOperation
|
||||
|
||||
DE_PY_BORDER_TYPE = {Border.CONSTANT: 'constant',
|
||||
Border.EDGE: 'edge',
|
||||
Border.REFLECT: 'reflect',
|
||||
Border.SYMMETRIC: 'symmetric'}
|
||||
|
||||
DE_PY_INTER_MODE = {Inter.NEAREST: Image.NEAREST,
|
||||
Inter.ANTIALIAS: Image.ANTIALIAS,
|
||||
Inter.LINEAR: Image.LINEAR,
|
||||
Inter.CUBIC: Image.CUBIC}
|
||||
|
||||
|
||||
class AdjustGamma(py_transforms.PyTensorOperation):
|
||||
# 定义AdjustGamma类,用于调整图像的gamma值
|
||||
@check_adjust_gamma
|
||||
def __init__(self, gamma, gain=1.0):
|
||||
# 初始化AdjustGamma类,参数为gamma值和gain值
|
||||
self.gamma = gamma
|
||||
self.gain = gain
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用adjust_gamma函数,输入图像和gamma值和gain值
|
||||
return util.adjust_gamma(img, self.gamma, self.gain)
|
||||
|
||||
|
||||
class AutoContrast(py_transforms.PyTensorOperation):
|
||||
# 定义AutoContrast类,实现__init__方法,参数cutoff为阈值,ignore为忽略的像素
|
||||
@check_auto_contrast
|
||||
def __init__(self, cutoff=0.0, ignore=None):
|
||||
self.cutoff = cutoff
|
||||
self.ignore = ignore
|
||||
self.random = False
|
||||
|
||||
# 定义__call__方法,参数img为图像
|
||||
def __call__(self, img):
|
||||
# 调用util.auto_contrast函数,参数img,cutoff,ignore
|
||||
return util.auto_contrast(img, self.cutoff, self.ignore)
|
||||
|
||||
|
||||
class CenterCrop(py_transforms.PyTensorOperation):
|
||||
# 初始化函数,设置裁剪的大小
|
||||
@check_center_crop
|
||||
def __init__(self, size):
|
||||
self.size = size
|
||||
self.random = False
|
||||
|
||||
# 调用util.center_crop函数,参数img, size
|
||||
def __call__(self, img):
|
||||
return util.center_crop(img, self.size)
|
||||
|
||||
# 从输入图像数组中随机裁剪出给定数量的正方形区域。
|
||||
class Cutout(py_transforms.PyTensorOperation):
|
||||
# 初始化Cutout类,参数为length, num_patches
|
||||
@check_cutout
|
||||
def __init__(self, length, num_patches=1):
|
||||
self.length = length
|
||||
self.num_patches = num_patches
|
||||
self.random = False
|
||||
|
||||
# 定义__call__方法,用于调用Cutout类
|
||||
def __call__(self, np_img):
|
||||
# 如果np_img不是NumPy数组,抛出类型错误异常
|
||||
if not isinstance(np_img, np.ndarray):
|
||||
raise TypeError(
|
||||
"img should be NumPy array. Got {}.".format(type(np_img)))
|
||||
# 如果np_img的维度不是3,抛出类型错误异常
|
||||
if np_img.ndim != 3:
|
||||
raise TypeError(
|
||||
'img dimension should be 3. Got {}.'.format(np_img.ndim))
|
||||
|
||||
# 获取np_img的高度和宽度
|
||||
_, image_h, image_w = np_img.shape
|
||||
# 计算图片裁剪规模
|
||||
scale = (self.length * self.length) / (image_h * image_w)
|
||||
# 将bounded赋值为False
|
||||
bounded = False
|
||||
|
||||
# 遍历num_patches次
|
||||
for _ in range(self.num_patches):
|
||||
# 获取i,j,erase_h(擦除区域高度),erase_w(擦除区域宽度),erase_value(擦除区域的像素填充值)
|
||||
i, j, erase_h, erase_w, erase_value = util.get_erase_params(np_img, (scale, scale), (1, 1), 0, bounded,
|
||||
1)
|
||||
# 使用util.erase函数,将np_img中的像素值替换为erase_value
|
||||
np_img = util.erase(np_img, i, j, erase_h, erase_w, erase_value)
|
||||
# 返回np_img
|
||||
return np_img
|
||||
|
||||
# 将输入的压缩图像解码为RGB格式
|
||||
class Decode(py_transforms.PyTensorOperation):
|
||||
# 定义Decode类
|
||||
def __init__(self):
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用util.decode函数,输入img
|
||||
return util.decode(img)
|
||||
|
||||
# 对输入图像进行直方图均衡化。
|
||||
class Equalize(py_transforms.PyTensorOperation):
|
||||
# 定义Decode类
|
||||
def __init__(self):
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用util.equalize函数,输入img,返回比较图像
|
||||
return util.equalize(img)
|
||||
|
||||
# 定义一个类FiveCrop,用来对图像进行五分类
|
||||
class FiveCrop(py_transforms.PyTensorOperation):
|
||||
@check_five_crop
|
||||
def __init__(self, size):
|
||||
# 初始化类FiveCrop,参数为size
|
||||
self.size = size
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回五分类图像
|
||||
return util.five_crop(img, self.size)
|
||||
|
||||
# 将输入PIL图像转换为灰度图
|
||||
class Grayscale(py_transforms.PyTensorOperation):
|
||||
# 定义Grayscale类
|
||||
@check_num_channels
|
||||
def __init__(self, num_output_channels=1):
|
||||
# 初始化类,参数num_output_channels表示输出通道数
|
||||
self.num_output_channels = num_output_channels
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回一个黑白图像
|
||||
return util.grayscale(img, num_output_channels=self.num_output_channels)
|
||||
|
||||
# 将输入的HSV格式numpy.ndarray图像转换为RGB格式。
|
||||
class HsvToRgb(py_transforms.PyTensorOperation):
|
||||
# 定义HsvToRgb类,参数为is_hwc,默认为False
|
||||
@check_hsv_to_rgb
|
||||
def __init__(self, is_hwc=False):
|
||||
# 初始化HsvToRgb类,参数为is_hwc
|
||||
self.is_hwc = is_hwc
|
||||
# 设置随机数为False
|
||||
self.random = False
|
||||
|
||||
def __call__(self, hsv_imgs):
|
||||
# 调用util.hsv_to_rgbs函数,传入hsv_imgs,is_hwc参数
|
||||
return util.hsv_to_rgbs(hsv_imgs, self.is_hwc)
|
||||
|
||||
# 将输入图像的shape从 <H, W, C> 转换为 <C, H, W>
|
||||
class HWC2CHW(py_transforms.PyTensorOperation):
|
||||
|
||||
def __init__(self):
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
return util.hwc_to_chw(img)
|
||||
|
||||
# 在 RGB 模式下对输入图像应用像素反转。
|
||||
class Invert(py_transforms.PyTensorOperation):
|
||||
# 定义Invert类,初始化random变量
|
||||
def __init__(self):
|
||||
self.random = False
|
||||
|
||||
# 返回util.invert_color函数的调用结果
|
||||
def __call__(self, img):
|
||||
return util.invert_color(img)
|
||||
|
||||
# 使用指定的变换方阵和均值向量对输入numpy.ndarray图像进行线性变换。
|
||||
class LinearTransformation(py_transforms.PyTensorOperation):
|
||||
# 定义LinearTransformation类,参数transformation_matrix, mean_vector
|
||||
@check_linear_transform
|
||||
def __init__(self, transformation_matrix, mean_vector):
|
||||
self.transformation_matrix = transformation_matrix
|
||||
self.mean_vector = mean_vector
|
||||
self.random = False
|
||||
|
||||
def __call__(self, np_img):
|
||||
# 返回线性变换后的图像
|
||||
return util.linear_transform(np_img, self.transformation_matrix, self.mean_vector)
|
||||
|
||||
# 随机混合一批输入的numpy.ndarray图像及其标签。
|
||||
class MixUp(py_transforms.PyTensorOperation):
|
||||
# 定义MixUp类,参数image, label, batch_size, alpha, is_single
|
||||
@check_mix_up
|
||||
def __init__(self, batch_size, alpha, is_single=True):
|
||||
# 初始化image和label
|
||||
self.image = 0
|
||||
self.label = 0
|
||||
self.is_first = True
|
||||
self.batch_size = batch_size
|
||||
self.alpha = alpha
|
||||
self.is_single = is_single
|
||||
self.random = False
|
||||
|
||||
# 返回mix_up_single函数
|
||||
def __call__(self, image, label):
|
||||
# 如果is_single为True,则返回mix_up_single函数
|
||||
if self.is_single:
|
||||
return util.mix_up_single(self.batch_size, image, label, self.alpha)
|
||||
# 否则返回mix_up_muti函数
|
||||
return util.mix_up_muti(self, self.batch_size, image, label, self.alpha)
|
||||
|
||||
# 根据均值和标准差对输入图像进行归一化
|
||||
class Normalize(py_transforms.PyTensorOperation):
|
||||
@check_normalize_py
|
||||
def __init__(self, mean, std):
|
||||
'''
|
||||
初始化函数,用于初始化模型参数
|
||||
:param mean: 均值
|
||||
:param std: 标准差
|
||||
'''
|
||||
#设置均值
|
||||
self.mean = mean
|
||||
#设置标准差
|
||||
self.std = std
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
#返回一个normalize对象
|
||||
return util.normalize(img, self.mean, self.std)
|
||||
|
||||
# 根据均值和标准差对输入图像进行归一化,然后填充一个全零的额外通道
|
||||
class NormalizePad(py_transforms.PyTensorOperation):
|
||||
# 初始化NormalizePad类,参数mean, std, dtype
|
||||
@check_normalizepad_py
|
||||
def __init__(self, mean, std, dtype="float32"):
|
||||
self.mean = mean
|
||||
self.std = std
|
||||
self.dtype = dtype
|
||||
self.random = False
|
||||
|
||||
# 定义__call__函数,用于调用normalize函数
|
||||
def __call__(self, img):
|
||||
# 调用util.normalize函数,将img参数转换为输入的格式,并且设置pad_channel为True,dtype为self.dtype
|
||||
return util.normalize(img, self.mean, self.std, pad_channel=True, dtype=self.dtype)
|
||||
|
||||
# 填充图像
|
||||
class Pad(py_transforms.PyTensorOperation):
|
||||
@check_pad
|
||||
def __init__(self, padding, fill_value=0, padding_mode=Border.CONSTANT):
|
||||
# 初始化NormalizePad类,参数padding, fill_value, padding_mode
|
||||
# 解析padding
|
||||
parse_padding(padding)
|
||||
|
||||
self.padding = padding
|
||||
self.fill_value = fill_value
|
||||
self.padding_mode = DE_PY_BORDER_TYPE[padding_mode]
|
||||
self.random = False
|
||||
|
||||
# 定义__call__方法,用于处理图像
|
||||
def __call__(self, img):
|
||||
# 调用util.pad函数,处理图像
|
||||
return util.pad(img, self.padding, self.fill_value, self.padding_mode)
|
||||
|
||||
# 对输入图像应用随机仿射变换
|
||||
class RandomAffine(py_transforms.PyTensorOperation):
|
||||
# 根据参数degrees,translate,scale,shear,resample,fill_value初始化RandomAffine类
|
||||
@check_random_affine
|
||||
def __init__(self, degrees, translate=None, scale=None, shear=None, resample=Inter.NEAREST, fill_value=0):
|
||||
# 如果shear不为空,则将shear转换为数组
|
||||
if shear is not None:
|
||||
if isinstance(shear, numbers.Number):
|
||||
shear = (-1 * shear, shear)
|
||||
else:
|
||||
if len(shear) == 2:
|
||||
shear = [shear[0], shear[1], 0., 0.]
|
||||
elif len(shear) == 4:
|
||||
shear = [s for s in shear]
|
||||
|
||||
# 如果degrees不为空,则将degrees转换为数组
|
||||
if isinstance(degrees, numbers.Number):
|
||||
degrees = (-degrees, degrees)
|
||||
|
||||
self.degrees = degrees
|
||||
self.translate = translate
|
||||
self.scale_ranges = scale
|
||||
self.shear = shear
|
||||
self.resample = DE_PY_INTER_MODE[resample]
|
||||
self.fill_value = fill_value
|
||||
|
||||
# 返回一个随机变换后的图像
|
||||
def __call__(self, img):
|
||||
# 调用util.random_affine函数,参数img,self.degrees,self.translate,self.scale_ranges,self.shear,self.resample,self.fill_value
|
||||
return util.random_affine(img,
|
||||
self.degrees,
|
||||
self.translate,
|
||||
self.scale_ranges,
|
||||
self.shear,
|
||||
self.resample,
|
||||
self.fill_value)
|
||||
|
||||
# 随机调整输入图像的颜色
|
||||
class RandomColor(py_transforms.PyTensorOperation):
|
||||
# 定义一个RandomColor类,参数为degrees,用于控制随机颜色的范围
|
||||
@check_positive_degrees
|
||||
def __init__(self, degrees=(0.1, 1.9)):
|
||||
self.degrees = degrees
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用py_transforms.PyTensorOperation的__call__方法,传入img参数
|
||||
return util.random_color(img, self.degrees)
|
||||
|
||||
|
||||
class RandomColorAdjust(py_transforms.PyTensorOperation):
|
||||
# 定义一个RandomColorAdjust类,接收三个参数:brightness、contrast、saturation和hue
|
||||
@check_random_color_adjust
|
||||
def __init__(self, brightness=(1, 1), contrast=(1, 1), saturation=(1, 1), hue=(0, 0)):
|
||||
self.brightness = brightness
|
||||
self.contrast = contrast
|
||||
self.saturation = saturation
|
||||
self.hue = hue
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用PyTensorOperation类的__call__方法,传入img参数,返回一个改变图像的图像
|
||||
return util.random_color_adjust(img, self.brightness, self.contrast, self.saturation, self.hue)
|
||||
|
||||
# 对输入图像进行随机区域的裁剪
|
||||
class RandomCrop(py_transforms.PyTensorOperation):
|
||||
# 初始化RandomCrop类,参数size为裁剪大小,padding为边界,pad_if_needed为是否需要裁剪,fill_value为填充值,padding_mode为填充模式
|
||||
@check_random_crop
|
||||
def __init__(self, size, padding=None, pad_if_needed=False, fill_value=0, padding_mode=Border.CONSTANT):
|
||||
# 如果padding为空,则padding为(0, 0, 0, 0)
|
||||
if padding is None:
|
||||
padding = (0, 0, 0, 0)
|
||||
else:
|
||||
# 将padding转换为元组
|
||||
padding = parse_padding(padding)
|
||||
self.size = size
|
||||
self.padding = padding
|
||||
self.pad_if_needed = pad_if_neededm
|
||||
self.fill_value = fill_value
|
||||
self.padding_mode = DE_PY_BORDER_TYPE[padding_mode]
|
||||
|
||||
# 定义__call__方法,用于调用RandomCrop类的构造函数
|
||||
def __call__(self, img):
|
||||
# 调用util.random_crop函数,输入img,self.size,self.padding,self.pad_if_needed,self.fill_value,self.padding_mode
|
||||
return util.random_crop(img, self.size, self.padding, self.pad_if_needed,
|
||||
self.fill_value, self.padding_mode)
|
||||
|
||||
# 按照指定的概率擦除输入numpy.ndarray图像上随机矩形区域内的像素
|
||||
class RandomErasing(py_transforms.PyTensorOperation):
|
||||
# 定义一个RandomErasing类,参数prob, scale, ratio, value, inplace, max_attempts
|
||||
@check_random_erasing
|
||||
def __init__(self, prob=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0, inplace=False, max_attempts=10):
|
||||
self.prob = prob
|
||||
self.scale = scale
|
||||
self.ratio = ratio
|
||||
self.value = value
|
||||
self.inplace = inplace
|
||||
self.max_attempts = max_attempts
|
||||
|
||||
def __call__(self, np_img):
|
||||
# 调用父类的__call__函数
|
||||
bounded = True
|
||||
# 如果概率大于随机的,则进行擦除
|
||||
if self.prob > random.random():
|
||||
# 获取擦除参数
|
||||
i, j, erase_h, erase_w, erase_value = util.get_erase_params(np_img, self.scale, self.ratio,
|
||||
self.value, bounded, self.max_attempts)
|
||||
# 进行擦除
|
||||
return util.erase(np_img, i, j, erase_h, erase_w, erase_value, self.inplace)
|
||||
return np_img
|
||||
|
||||
# 按照指定的概率将输入PIL图像转换为灰度图
|
||||
class RandomGrayscale(py_transforms.PyTensorOperation):
|
||||
# 定义RandomGrayscale类参数prob
|
||||
@check_prob
|
||||
def __init__(self, prob=0.1):
|
||||
self.prob = prob
|
||||
|
||||
# 定义操作
|
||||
def __call__(self, img):
|
||||
# 如果图像类型为L,则输出通道数为1
|
||||
if img.mode == 'L':
|
||||
num_output_channels = 1
|
||||
else:
|
||||
# 否则输出通道数为3
|
||||
num_output_channels = 3
|
||||
|
||||
# 如果概率大于随机数,则进行灰度变换
|
||||
if self.prob > random.random():
|
||||
return util.grayscale(img, num_output_channels=num_output_channels)
|
||||
# 否则返回原图
|
||||
return img
|
||||
|
||||
# 对输入图像按给定的概率进行水平随机翻转
|
||||
class RandomHorizontalFlip(py_transforms.PyTensorOperation):
|
||||
# 初始化函数,接收一个prob参数,默认为0.5
|
||||
@check_prob
|
||||
def __init__(self, prob=0.5):
|
||||
self.prob = prob
|
||||
|
||||
# 定义函数,返回一个随机水平翻转的图像
|
||||
def __call__(self, img):
|
||||
|
||||
# 返回一个随机水平翻转的图像,并将prob参数赋值给img
|
||||
return util.random_horizontal_flip(img, self.prob)
|
||||
|
||||
# 将AlexNet PCA的噪声添加到图像中
|
||||
class RandomLighting(py_transforms.PyTensorOperation):
|
||||
# 定义一个RandomLighting类
|
||||
@check_alpha
|
||||
def __init__(self, alpha=0.05):
|
||||
self.alpha = alpha
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用随机亮度函数
|
||||
return util.random_lighting(img, self.alpha)
|
||||
|
||||
# 按照指定的概率对输入PIL图像进行透视变换
|
||||
class RandomPerspective(py_transforms.PyTensorOperation):
|
||||
# 定义RandomPerspective类,接收一个参数distortion_scale,用于控制随机投影的概率,prob,用于控制随机投影的插值方式
|
||||
@check_random_perspective
|
||||
def __init__(self, distortion_scale=0.5, prob=0.5, interpolation=Inter.BICUBIC):
|
||||
self.distortion_scale = distortion_scale
|
||||
self.prob = prob
|
||||
# 将interpolation转换为插值方式
|
||||
self.interpolation = DE_PY_INTER_MODE[interpolation]
|
||||
|
||||
def __call__(self, img):
|
||||
# 定义__call__方法,接收一个参数img,用于处理图像
|
||||
if not is_pil(img):
|
||||
raise ValueError("Input image should be a Pillow image.")
|
||||
# 如果prob大于随机生成的值,则获取随机投影的起点和终点
|
||||
if self.prob > random.random():
|
||||
start_points, end_points = util.get_perspective_params(
|
||||
img, self.distortion_scale)
|
||||
# 返回投影后的图像
|
||||
return util.perspective(img, start_points, end_points, self.interpolation)
|
||||
# 如果prob小于随机生成的值,则返回原图
|
||||
return img
|
||||
|
||||
# 对输入图像进行随机裁剪,并使用指定的 mindspore.dataset.vision.Inter 插值方式去调整为指定的尺寸大小
|
||||
class RandomResizedCrop(py_transforms.PyTensorOperation):
|
||||
# 定义RandomResizedCrop类,用来对图像进行随机裁剪
|
||||
@check_random_resize_crop
|
||||
def __init__(self, size, scale=(0.08, 1.0), ratio=(3. / 4., 4. / 3.),
|
||||
interpolation=Inter.BILINEAR, max_attempts=10):
|
||||
# 初始化RandomResizedCrop类,设置裁剪尺寸,裁剪比例,裁剪方式,最大尝试次数
|
||||
self.size = size
|
||||
self.scale = scale
|
||||
self.ratio = ratio
|
||||
self.interpolation = DE_PY_INTER_MODE[interpolation]
|
||||
self.max_attempts = max_attempts
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回随机裁剪后的图像
|
||||
return util.random_resize_crop(img, self.size, self.scale, self.ratio,
|
||||
self.interpolation, self.max_attempts)
|
||||
|
||||
# 在指定的角度范围内,随机旋转输入图像
|
||||
class RandomRotation(py_transforms.PyTensorOperation):
|
||||
@check_random_rotation
|
||||
# 定义RandomRotation类,参数degrees, resample, expand, center, fill_value
|
||||
def __init__(self, degrees, resample=Inter.NEAREST, expand=False, center=None, fill_value=0):
|
||||
self.degrees = degrees
|
||||
self.resample = DE_PY_INTER_MODE[resample]
|
||||
self.expand = expand
|
||||
self.center = center
|
||||
self.fill_value = fill_value
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回随机旋转图像
|
||||
return util.random_rotation(img, self.degrees, self.resample, self.expand, self.center, self.fill_value)
|
||||
|
||||
# 在固定或随机的范围调整输入图像的锐度
|
||||
class RandomSharpness(py_transforms.PyTensorOperation):
|
||||
# 定义RandomSharpness类,参数为degrees,表示角度
|
||||
@check_positive_degrees
|
||||
def __init__(self, degrees=(0.1, 1.9)):
|
||||
self.degrees = degrees
|
||||
|
||||
# 定义__call__函数
|
||||
def __call__(self, img):
|
||||
# 调用util.random_sharpness函数,参数为img和self.degrees
|
||||
return util.random_sharpness(img, self.degrees)
|
||||
|
||||
|
||||
class RandomVerticalFlip(py_transforms.PyTensorOperation):
|
||||
# 定义RandomVerticalFlip类,参数为prob
|
||||
@check_prob
|
||||
def __init__(self, prob=0.5):
|
||||
self.prob = prob
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回随机翻转图像
|
||||
return util.random_vertical_flip(img, self.prob)
|
||||
|
||||
# 对输入图像使用给定的 mindspore.dataset.vision.Inter 插值方式去调整为给定的尺寸大小
|
||||
class Resize(py_transforms.PyTensorOperation):
|
||||
# 定义Resize类,接收size和interpolation参数
|
||||
@check_resize_interpolation
|
||||
def __init__(self, size, interpolation=Inter.BILINEAR):
|
||||
self.size = size
|
||||
self.interpolation = DE_PY_INTER_MODE[interpolation]
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回resize函数,传入图像和size和interpolation参数
|
||||
return util.resize(img, self.size, self.interpolation)
|
||||
|
||||
# 将输入的RGB格式numpy.ndarray图像转换为BGR格式
|
||||
class RgbToBgr(py_transforms.PyTensorOperation):
|
||||
@check_rgb_to_bgr
|
||||
def __init__(self, is_hwc=False):
|
||||
self.is_hwc = is_hwc
|
||||
self.random = False
|
||||
|
||||
def __call__(self, rgb_imgs):
|
||||
return util.rgb_to_bgrs(rgb_imgs, self.is_hwc)
|
||||
|
||||
# 将输入的RGB格式numpy.ndarray图像转换为HSV格式
|
||||
class RgbToHsv(py_transforms.PyTensorOperation):
|
||||
@check_rgb_to_hsv
|
||||
def __init__(self, is_hwc=False):
|
||||
self.is_hwc = is_hwc
|
||||
self.random = False
|
||||
|
||||
def __call__(self, rgb_imgs):
|
||||
return util.rgb_to_hsvs(rgb_imgs, self.is_hwc)
|
||||
|
||||
# 在输入PIL图像的中心与四个角处分别裁剪指定尺寸大小的子图,并将其翻转图一并返回
|
||||
class TenCrop(py_transforms.PyTensorOperation):
|
||||
# 定义TenCrop类,接收一个size参数,use_vertical_flip参数
|
||||
@check_ten_crop
|
||||
def __init__(self, size, use_vertical_flip=False):
|
||||
# 如果size参数是int类型,则将size转换为元组,否则直接赋值
|
||||
if isinstance(size, int):
|
||||
size = (size, size)
|
||||
self.size = size
|
||||
self.use_vertical_flip = use_vertical_flip
|
||||
# 将random设置为False
|
||||
self.random = False
|
||||
|
||||
# 定义__call__方法,接收一个img参数
|
||||
def __call__(self, img):
|
||||
# 调用util.ten_crop函数,传入img和self.size,self.use_vertical_flip
|
||||
return util.ten_crop(img, self.size, self.use_vertical_flip)
|
||||
|
||||
# 将已解码的numpy.ndarray图像转换为PIL图像
|
||||
class ToPIL(py_transforms.PyTensorOperation):
|
||||
def __init__(self):
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
return util.to_pil(img)
|
||||
|
||||
# 将输入PIL图像或numpy.ndarray图像转换为指定类型的numpy.ndarray图像,
|
||||
# 图像的像素值范围将从[0, 255]放缩为[0.0, 1.0],shape将从<H, W, C>调整为<C, H, W>
|
||||
class ToTensor(py_transforms.PyTensorOperation):
|
||||
# 初始化ToTensor类,输入参数output_type为np.float32
|
||||
def __init__(self, output_type=np.float32):
|
||||
self.output_type = output_type
|
||||
self.random = False
|
||||
|
||||
# 定义__call__方法,输入参数img,返回util.to_tensor函数的输出
|
||||
def __call__(self, img):
|
||||
return util.to_tensor(img, self.output_type)
|
||||
|
||||
# 将输入转换为指定的MindSpore数据类型或NumPy数据类型
|
||||
class ToType(py_transforms.PyTensorOperation):
|
||||
# 定义ToType类,设置output_type参数
|
||||
def __init__(self, output_type):
|
||||
self.output_type = output_type
|
||||
# 定义random变量,默认为False
|
||||
self.random = False
|
||||
|
||||
# 定义__call__方法,将img参数转换为output_type类型
|
||||
def __call__(self, img):
|
||||
return util.to_type(img, self.output_type)
|
||||
|
||||
# 从指定序列中均匀采样一批数据处理操作,并按顺序随机执行,即采样出的操作也可能不被执行
|
||||
class UniformAugment(py_transforms.PyTensorOperation):
|
||||
'''
|
||||
使用随机操作增强图像
|
||||
'''
|
||||
@check_uniform_augment_py
|
||||
def __init__(self, transforms, num_ops=2):
|
||||
'''
|
||||
:param transforms: 增强函数列表
|
||||
:param num_ops: 增强次数
|
||||
'''
|
||||
self.transforms = transforms
|
||||
self.num_ops = num_ops
|
||||
self.random = False
|
||||
|
||||
def __call__(self, img):
|
||||
'''
|
||||
:param img: 图像
|
||||
:return: 增强后的图像
|
||||
'''
|
||||
return util.uniform_augment(img, self.transforms.copy(), self.num_ops)
|
||||
|
||||
def not_random(func):
|
||||
def not_random(function):
|
||||
"""
|
||||
Specify the function as "not random", i.e., it produces deterministic result.
|
||||
A Python function can only be cached after it is specified as "not random".
|
||||
"""
|
||||
func.random = False
|
||||
return func
|
||||
function.random = False
|
||||
return function
|
||||
|
||||
|
||||
class PyTensorOperation:
|
||||
"""
|
||||
Base Python Tensor Operations class
|
||||
"""
|
||||
|
||||
def to_json(self):
|
||||
"""
|
||||
Base to_json for Python tensor operations class
|
||||
"""
|
||||
json_obj = {}
|
||||
json_trans = {}
|
||||
if "transforms" in self.__dict__.keys():
|
||||
# operations which have transforms as input, need to call _to_json() for each transform to serialize
|
||||
json_list = []
|
||||
for transform in self.transforms:
|
||||
json_list.append(json.loads(transform.to_json()))
|
||||
json_trans["transforms"] = json_list
|
||||
self.__dict__.pop("transforms")
|
||||
if "output_type" in self.__dict__.keys():
|
||||
json_trans["output_type"] = np.dtype(
|
||||
self.__dict__["output_type"]).name
|
||||
self.__dict__.pop("output_type")
|
||||
json_obj["tensor_op_params"] = self.__dict__
|
||||
# append transforms to the tensor_op_params of the operation
|
||||
json_obj["tensor_op_params"].update(json_trans)
|
||||
json_obj["tensor_op_name"] = self.__class__.__name__
|
||||
json_obj["python_module"] = self.__class__.__module__
|
||||
return json.dumps(json_obj)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_string):
|
||||
"""
|
||||
Base from_json for Python tensor operations class
|
||||
"""
|
||||
json_obj = json.loads(json_string)
|
||||
new_op = cls.__new__(cls)
|
||||
new_op.__dict__ = json_obj
|
||||
if "transforms" in json_obj.keys():
|
||||
# operations which have transforms as input, need to call _from_json() for each transform to deseriallize
|
||||
transforms = []
|
||||
for json_op in json_obj["transforms"]:
|
||||
transforms.append(getattr(
|
||||
sys.modules[json_op["python_module"]], json_op["tensor_op_name"]).from_json(
|
||||
json.dumps(json_op["tensor_op_params"])))
|
||||
new_op.transforms = transforms
|
||||
if "output_type" in json_obj.keys():
|
||||
output_type = np.dtype(json_obj["output_type"])
|
||||
new_op.output_type = output_type
|
||||
return new_op
|
||||
|
||||
|
||||
class OneHotOp(PyTensorOperation):
|
||||
# 定义OneHotOp类,参数num_classes, smoothing_rate
|
||||
@check_one_hot_op
|
||||
def __init__(self, num_classes, smoothing_rate=0.0):
|
||||
# 初始化num_classes和smoothing_rate
|
||||
self.num_classes = num_classes
|
||||
self.smoothing_rate = smoothing_rate
|
||||
self.random = False
|
||||
|
||||
def __call__(self, label):
|
||||
# 返回one_hot_encoding函数的结果
|
||||
return util.one_hot_encoding(label, self.num_classes, self.smoothing_rate)
|
||||
|
||||
# 将多个数据增强操作组合使用
|
||||
class Compose(PyTensorOperation):
|
||||
@check_compose_list
|
||||
def __init__(self, transforms):
|
||||
'''
|
||||
参数:
|
||||
transforms:PyTensorOperation对象列表
|
||||
'''
|
||||
self.transforms = transforms
|
||||
if all(hasattr(transform, "random") and not transform.random for transform in self.transforms):
|
||||
self.random = False
|
||||
|
||||
@check_compose_call
|
||||
def __call__(self, *args):
|
||||
# 返回:组合后的PyTensorOperation对象
|
||||
return util.compose(self.transforms, *args)
|
||||
|
||||
@staticmethod
|
||||
def reduce(operations):
|
||||
# import nn and ops locally for type check
|
||||
from mindspore import nn, ops
|
||||
# 检查输入的运算是否包含像mindspore.nn或mindspore.ops的运算
|
||||
for item in operations:
|
||||
if isinstance(item, (nn.Cell, ops.Primitive)):
|
||||
raise ValueError("Input operations should not contain network computing operator like in "
|
||||
"mindspore.nn or mindspore.ops, got operation:", str(item))
|
||||
# 检查输入的运算是否为空
|
||||
if len(operations) == 1:
|
||||
# 检查输入的运算是否为张量运算,如果是返回运算
|
||||
if str(operations).find("c_transform") >= 0 or isinstance(operations[0], TensorOperation):
|
||||
return operations
|
||||
# 如果不是,返回util.FuncWrapper的运算结果
|
||||
return [util.FuncWrapper(operations[0])]
|
||||
|
||||
# 重新设置数值
|
||||
new_ops, start_ind, end_ind = [], 0, 0
|
||||
# 循环遍历运算
|
||||
for i, op in enumerate(operations):
|
||||
# 检查当前运算为 Compose
|
||||
if str(op).find("c_transform") >= 0:
|
||||
# 为new_ops添加新的数值
|
||||
if start_ind!= end_ind:
|
||||
new_ops.append(Compose(operations[start_ind:end_ind]))
|
||||
# 添加当前运算符
|
||||
new_ops.append(op)
|
||||
start_ind, end_ind = i + 1, i + 1
|
||||
# 检查当前运算为 Compose
|
||||
else:
|
||||
# 让end_ind 加一
|
||||
end_ind += 1
|
||||
# 额外检查以防最后一个运算为Python运算
|
||||
if start_ind!= end_ind:
|
||||
new_ops.append(Compose(operations[start_ind:end_ind]))
|
||||
return new_ops
|
||||
|
||||
# 指定一组数据增强处理及其被应用的概率,在运算时按概率随机应用其中的增强处理
|
||||
class RandomApply(PyTensorOperation):
|
||||
# 定义RandomApply类,参数transforms和prob:概率
|
||||
@check_random_apply
|
||||
def __init__(self, transforms, prob=0.5):
|
||||
self.prob = prob
|
||||
self.transforms = transforms
|
||||
|
||||
def __call__(self, img):
|
||||
# 返回随机应用于img的结果
|
||||
return util.random_apply(img, self.transforms, self.prob)
|
||||
|
||||
# 在一组数据增强中随机选择部分增强处理进行应用
|
||||
class RandomChoice(PyTensorOperation):
|
||||
# 定义RandomChoice类,继承PyTensorOperation类
|
||||
@check_transforms_list
|
||||
def __init__(self, transforms):
|
||||
# 初始化transforms参数
|
||||
self.transforms = transforms
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用PyTensorOperation类的__call__方法,传入img参数
|
||||
return util.random_choice(img, self.transforms)
|
||||
|
||||
# 给一个数据增强的列表,随机打乱数据增强处理的顺序
|
||||
class RandomOrder(PyTensorOperation):
|
||||
# 定义一个RandomOrder类,用于接收一个可调用的transforms列表
|
||||
@check_transforms_list
|
||||
def __init__(self, transforms):
|
||||
self.transforms = transforms
|
||||
|
||||
def __call__(self, img):
|
||||
# 调用PyTensorOperation的__call__方法,传入img参数,并将返回值赋值给img
|
||||
return util.random_order(img, self.transforms)
|
||||
|
|
|
|||
Loading…
Reference in New Issue