非常详细的Kaggle实战(二)图片预处理

2020-03-20  本文已影响0人  海盗船长_coco

图片预处理

对图片进行以下操作:
1、转化为黑白图像
2、进行一系列仿射变换

一、转化为黑白图像

在早期实验中,作者发现当比较两个彩色图像或两个黑白图像时,模型能够达到了差不多相同的精度。 但是,将彩色图像与黑白图像进行比较会导致精度大大降低。 最简单的解决方案是将所有图像转换为黑白图像,这样即使在比较原始彩色图像时也不会降低准确性。

二、仿射变换

观察下图可以发现给我们的图像中存在大量的背景像素,先使用bounding box将鲸鱼的矩形区域框出来,再利用仿射变换将图像的矩形区域映射到分辨率为384x384x1(黑白仅一个通道)的方形图像。矩形区域的宽高比为2.15,接近于所有图片的平均高宽比。矩形的边界框比bounding box模型预测的边界框略大。
在训练期间,通过添加一系列缩放,平移,旋转和剪切的随机变换来进行数据增强。而测试时会跳过这些随机变换。
最后,将图像标准化为零均值和单位方差。
ps:bounding box文件也在上篇博客的百度云资源中,该数据主要是通过网络模型预测得到,具体可参考https://www.kaggle.com/martinpiotte/bounding-box-model

bounding box的裁剪图片
同时在之前的DataSource资源文件夹下添加bounding box的读取
class DataSource():

    def __init__(self, TRAIN_DF, SUB_DF, HASH_PATH, SIZE_PATH, BBOX_PATH):
        super(DataSource, self).__init__()
        # Read the dataset description
        self.picture_2_bbox = self.get_bbox(BBOX_PATH)  # 每张图片中的bounding box

    def get_bbox(self, bbox_path):
        # Read the bounding box data from the bounding box
        bbox = {p: (x0, y0, x1, y1) for _, p, x0, y0, x1, y1 in pd.read_csv(bbox_path).to_records()}
        return bbox
[('72c3ce75c.jpg', (0, 0, 1045, 389)), ('a7ad640ee.jpg', (35, 71, 523, 291)), 
('df2b6c364.jpg', (12, 15, 1033, 308)), ('26013fcb5.jpg', (3, 1, 1024, 292)), 
('09eff7b37.jpg', (11, 8, 926, 334))]

在util.py在添加包括旋转、裁切、缩放、平移等随机变换的方法

# 图像增强:随机变换
def build_transform(rotation, shear, height_zoom, width_zoom, height_shift, width_shift):
    rotation = np.deg2rad(rotation)  # 旋转角度转化为弧度
    shear = np.deg2rad(shear)
    rotation_matrix = np.array(
        [[np.cos(rotation), np.sin(rotation), 0], [-np.sin(rotation), np.cos(rotation), 0], [0, 0, 1]])  # 旋转
    shear_matrix = np.array([[1, np.sin(shear), 0], [0, np.cos(shear), 0], [0, 0, 1]])  # 裁剪
    zoom_matrix = np.array([[1.0 / height_zoom, 0, 0], [0, 1.0 / width_zoom, 0], [0, 0, 1]])  # 放大
    shift_matrix = np.array([[1, 0, -height_shift], [0, 1, -width_shift], [0, 0, 1]])  # 位移
    return np.dot(np.dot(rotation_matrix, shear_matrix), np.dot(zoom_matrix, shift_matrix))

在DataSouce类下添加读取图片的方法,训练集读取时便进行随机变换进行数据增强,而测试集读取时不必进行变换。

    # 读取裁切的图片
    def read_cropped_image(self, picture, augment, crop_margin=0.05, anisotropy=2.15, img_shape=(384, 384, 1)):
        """
        @param p : the name of the picture to read
        @param augment: True/False if data augmentation should be performed
        @:param crop_margin:The margin added around the bounding box to compensate for bounding box inaccuracy
        @:param anisotropy:高宽比
        @return a numpy array with the transformed image
        """
        # If an image id was given, convert to filename
        if picture in self.hash_2_picture:
            picture = self.hash_2_picture[picture]
        size_x, size_y = self.picture_2_size[picture]

        # Determine the region of the original image we want to capture based on the bounding box.
        x0, y0, x1, y1 = self.picture_2_bbox[picture]
        # if picture in rotate:     #无需旋转的图片
        #     x0, y0, x1, y1 = size_x - x1, size_y - y1, size_x - x0, size_y - y0
        dx = x1 - x0
        dy = y1 - y0
        x0 -= dx * crop_margin
        x1 += dx * crop_margin + 1
        y0 -= dy * crop_margin
        y1 += dy * crop_margin + 1
        # 防止越界
        x0 = 0 if x0 < 0 else x0
        x1 = size_x if x1 > size_x else x1
        y0 = 0 if y0 < 0 else y0
        y1 = size_y if y1 > size_y else y1
        # 宽高比
        dx = x1 - x0
        dy = y1 - y0
        if dx > dy * anisotropy:
            dy = 0.5 * (dx / anisotropy - dy)
            y0 -= dy
            y1 += dy
        else:
            dx = 0.5 * (dy * anisotropy - dx)
            x0 -= dx
            x1 += dx
        # Generate the transformation matrix
        trans = np.array([[1, 0, -0.5 * img_shape[0]], [0, 1, -0.5 * img_shape[1]], [0, 0, 1]])
        trans = np.dot(np.array([[(y1 - y0) / img_shape[0], 0, 0], [0, (x1 - x0) / img_shape[1], 0], [0, 0, 1]]),
                       trans)  # 缩放
        if augment:  # 数据增强
            trans = np.dot(build_transform(
                random.uniform(-5, 5),
                random.uniform(-5, 5),
                random.uniform(0.8, 1.0),
                random.uniform(0.8, 1.0),
                random.uniform(-0.05 * (y1 - y0), 0.05 * (y1 - y0)),
                random.uniform(-0.05 * (x1 - x0), 0.05 * (x1 - x0))
            ), trans)
        trans = np.dot(np.array([[1, 0, 0.5 * (y1 + y0)], [0, 1, 0.5 * (x1 + x0)], [0, 0, 1]]), trans)

        # Read the image, transform to black and white and comvert to numpy array
        img = np.array(Image.open(expand_path(picture)).convert('L'))

        # Apply affine transformation
        matrix = trans[:2, :2]
        offset = trans[:2, 2]
        # img = img.reshape(img.shape[:-1])
        img = affine_transform(img, matrix, offset, output_shape=img_shape[:-1], order=1, mode='constant',
                               cval=np.average(img))
        img = img.reshape(img_shape).astype(float)

        # Normalize to zero mean and unit variance
        img -= np.mean(img, keepdims=True)
        img /= np.std(img, keepdims=True)
        return img

    # Read an image for validation, i.e. without data augmentation.
    def read_for_validation(self, img_path, img_size=(384, 384, 1), anisotropy=2.15):
        return self.read_cropped_image(img_path, augment=False, img_shape=img_size, anisotropy=anisotropy)

    # Read an image for training, i.e. including a random affine transformation
    def read_for_training(self, img_path, img_size=(384, 384, 1), anisotropy=2.15):
        return self.read_cropped_image(img_path, augment=True, img_shape=img_size, anisotropy=anisotropy)

第一张为原图,第二张为训练时进行随即变换的图片,第三张为测试时不进行随机变换的图片。


原图、训练集图片、测试集图片

总结

以上就是对图片进行预处理的内容,主要是通过bounding box模型将鲸鱼的边界框进行预测,然后将预测出的矩形区域缩小到指定大小,在训练时通过随机变换进行数据增强,而测试时不进行数据增强。
当然边界框的预测也是一项重要内容,它直接关系到鲸鱼边界框的准确性,继而影响训练图像的质量,关于预测边界框的网络模型会另开一篇博客进行讲解。

上一篇下一篇

猜你喜欢

热点阅读