裁剪
要进行图像增广,通常会随机裁剪图像。换句话说,我们在随机区域上裁剪了一部分随机大小的图像。
可以从尺寸的比例(高度,宽度)中选择裁剪图像的尺寸。如果未指定裁剪的比例最大大小,则默认情况下,我们将认为它是图像的大小。
class Crop(object): def __init__(self, min_size_ratio, max_size_ratio=(1, 1)): self.min_size_ratio = np.array(list(min_size_ratio)) self.max_size_ratio = np.array(list(max_size_ratio)) def __call__(self, X, Y): size = np.array(X.shape[:2]) mini = self.min_size_ratio * size maxi = self.max_size_ratio * size # random size h = np.random.randint(mini[0], maxi[0]) w = np.random.randint(mini[1], maxi[1]) # random place shift_h = np.random.randint(0, size[0] - h) shift_w = np.random.randint(0, size[1] - w) X = X[shift_h:shift_h+h, shift_w:shift_w+w] Y = Y[shift_h:shift_h+h, shift_w:shift_w+w] return X, Y
过滤器
一般情况
我们将开始一些有趣的事情。过滤器是很棒的方法,但我认为能够轻松创建我们自己的卷积过滤器非常重要。
所以我想做一个通用的函数,以便能够使用我们自己的过滤器。
class CustomFilter(object): def __init__(self, kernel): self.kernel = kernel def __call__(self, X, Y): X = cv2.filter2D(X, -1, self.kernel) return X, Y
锐化
就过滤器而言,可以通过选择上游过滤器并以随机权重应用过滤器来进行进一步处理。例如,我向您介绍用于锐化图像的过滤器。
中心值从0到65。
class Sharpen(object): def __init__(self, max_center=4): self.identity = np.array([[0, 0, 0], [0, 1, 0], [0, 0, 0]]) self.sharpen = np.array([[ 0, -1, 0], [-1, 4, -1], [ 0, -1, 0]]) / 4 def __call__(self, X, Y): sharp = self.sharpen * np.random.random() * self.max_center kernel = self.identity + sharp X = cv2.filter2D(X, -1, kernel) return X, Y
模糊
可以用最流行的滤镜来随机模糊我们的图像。有很多方法可以模糊我们的图像。最著名的是平均值,中值,高斯或双边滤波器。
平均模糊
内核大小从1到35
关于平均滤波器。顾名思义,它使我们可以对给定中心的值取平均值。这是由内核完成的。可以指定其大小以增加或减少模糊。要使用平均滤波器增广图像,我们只需要使用随机大小的内核对输入图像进行滤波。
class GaussianBlur(object): def __init__(self, max_kernel=(7, 7)): self.max_kernel = ((max_kernel + 1) // 2) def __call__(self, X, Y): kernel_size = ( np.random.randint(1, self.max_kernel[0]) * 2 + 1, np.random.randint(1, self.max_kernel[1]) * 2 + 1, ) X = cv2.GaussianBlur(X, kernel_size, 0) return X, Y
高斯模糊
内核大小从1到35
高斯模糊不使用平均滤波器,而是使用高斯滤波器,因此这些值对应于从中心开始的高斯曲线。请注意,内核维数只能包含奇数。
class GaussianBlur(object): def __init__(self, max_kernel=(7, 7)): self.max_kernel = max_kernel def __call__(self, X, Y): kernel_size = ( np.random.randint(1, self.max_kernel[0] + 1), np.random.randint(1, self.max_kernel[1] + 1), ) X = cv2.GaussianBlur(X, kernel_size, 0) return X, Y
透视变换
迄今为止,最广泛使用的图像增广技术是透视变换。有旋转,平移,剪切和缩放。这些转换可以在3D维度中执行。通常,它们仅在2D中使用。让我们利用我们拥有的一切。
翻转
平移
剪切
缩放
结合
我不会在2D图像的3D转换上花费更多的时间,因为我写了有关这方面的整篇文章。因此,我选择了本文结尾处提供的函数。
应该注意的是,该函数允许我们根据所提出的4个矩阵随机执行变换。顺序很重要。这里我们有剪切,然后是旋转,然后是比例缩放,最后是平移。注意,平移是通过图像尺寸的比例完成的。
结合随机旋转平移剪切和比例缩放
class Perspective(object): def __init__(self, max_ratio_translation=(0.2, 0.2, 0), max_rotation=(10, 10, 360), max_scale=(0.1, 0.1, 0.2), max_shearing=(15, 15, 5)): self.max_ratio_translation = np.array(max_ratio_translation) self.max_rotation = np.array(max_rotation) self.max_scale = np.array(max_scale) self.max_shearing = np.array(max_shearing) def __call__(self, X, Y): # get the height and the width of the image h, w = X.shape[:2] max_translation = self.max_ratio_translation * np.array([w, h, 1]) # get the values on each axis t_x, t_y, t_z = np.random.uniform(-1, 1, 3) * max_translation r_x, r_y, r_z = np.random.uniform(-1, 1, 3) * self.max_rotation sc_x, sc_y, sc_z = np.random.uniform(-1, 1, 3) * self.max_scale + 1 sh_x, sh_y, sh_z = np.random.uniform(-1, 1, 3) * self.max_shearing # convert degree angles to rad theta_rx = np.deg2rad(r_x) theta_ry = np.deg2rad(r_y) theta_rz = np.deg2rad(r_z) theta_shx = np.deg2rad(sh_x) theta_shy = np.deg2rad(sh_y) theta_shz = np.deg2rad(sh_z) # compute its diagonal diag = (h ** 2 + w ** 2) ** 0.5 # compute the focal length f = diag if np.sin(theta_rz) != 0: f /= 2 * np.sin(theta_rz) # set the image from cartesian to projective dimension H_M = np.array([[1, 0, -w / 2], [0, 1, -h / 2], [0, 0, 1], [0, 0, 1]]) # set the image projective to carrtesian dimension Hp_M = np.array([[f, 0, w / 2, 0], [0, f, h / 2, 0], [0, 0, 1, 0]]) # adjust the translation on z t_z = (f - t_z) / sc_z ** 2 # translation matrix to translate the image T_M = np.array([[1, 0, 0, t_x], [0, 1, 0, t_y], [0, 0, 1, t_z], [0, 0, 0, 1]]) # calculate cos and sin of angles sin_rx, cos_rx = np.sin(theta_rx), np.cos(theta_rx) sin_ry, cos_ry = np.sin(theta_ry), np.cos(theta_ry) sin_rz, cos_rz = np.sin(theta_rz), np.cos(theta_rz) # get the rotation matrix on x axis R_Mx = np.array([[1, 0, 0, 0], [0, cos_rx, -sin_rx, 0], [0, sin_rx, cos_rx, 0], [0, 0, 0, 1]]) # get the rotation matrix on y axis R_My = np.array([[cos_ry, 0, -sin_ry, 0], [ 0, 1, 0, 0], [sin_ry, 0, cos_ry, 0], [ 0, 0, 0, 1]]) # get the rotation matrix on z axis R_Mz = np.array([[cos_rz, -sin_rz, 0, 0], [sin_rz, cos_rz, 0, 0], [ 0, 0, 1, 0], [ 0, 0, 0, 1]]) # compute the full rotation matrix R_M = np.dot(np.dot(R_Mx, R_My), R_Mz) # get the scaling matrix Sc_M = np.array([[sc_x, 0, 0, 0], [ 0, sc_y, 0, 0], [ 0, 0, sc_z, 0], [ 0, 0, 0, 1]]) # get the tan of angles tan_shx = np.tan(theta_shx) tan_shy = np.tan(theta_shy) tan_shz = np.tan(theta_shz) # get the shearing matrix on x axis Sh_Mx = np.array([[ 1, 0, 0, 0], [tan_shy, 1, 0, 0], [tan_shz, 0, 1, 0], [ 0, 0, 0, 1]]) # get the shearing matrix on y axis Sh_My = np.array([[1, tan_shx, 0, 0], [0, 1, 0, 0], [0, tan_shz, 1, 0], [0, 0, 0, 1]]) # get the shearing matrix on z axis Sh_Mz = np.array([[1, 0, tan_shx, 0], [0, 1, tan_shy, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) # compute the full shearing matrix Sh_M = np.dot(np.dot(Sh_Mx, Sh_My), Sh_Mz) Identity = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) # compute the full transform matrix M = Identity M = np.dot(Sh_M, M) M = np.dot(R_M, M) M = np.dot(Sc_M, M) M = np.dot(T_M, M) M = np.dot(Hp_M, np.dot(M, H_M)) # apply the transformation X = cv2.warpPerspective(X, M, (w, h)) Y = cv2.warpPerspective(Y, M, (w, h)) return X, Y