Faster-rcnn中的数据预处理

该代码中讲的是faster-rcnn中在进行训练过程中,对图片进行预处理操作。

对图像进行预处理

在faster-rcnn训练过程中,需要对传入网络中的图片进行预处理,其中包括减均值,除方差,对图像进行缩放等。使用如下函数进行调用。

注意其中images,targets代表的是在pytorch框进中打包好的一个batch_size的图片和其对应的标签

from transform import GeneralizedRCNNTransform

images, targets = self.transform(images, targets)  

如下是transfor.py的文件

首先遍历batch内每一张图片,对每张图片减均值,除方差处理

      images = [img for img in images]
        for i in range(len(images)):
            image = images[i]
            target_index = targets[i] if targets is not None else None

            if image.dim() != 3:
                raise ValueError("images is expected to be a list of 3d tensors "
                                 "of shape [C, H, W], got {}".format(image.shape))
            image = self.normalize(image)                # 对图像进行标准化处理
            image, target_index = self.resize(image, target_index)   # 对图像和对应的bboxes缩放到指定范围
            images[i] = image
            if targets is not None and target_index is not None:
                targets[i] = target_index

        # 记录resize后的图像尺寸
        image_sizes = [img.shape[-2:] for img in images]
        images = self.batch_images(images)  # 将images打包成一个batch
        image_sizes_list = torch.jit.annotate(List[Tuple[int, int]], [])

        for image_size in image_sizes:
            assert len(image_size) == 2
            image_sizes_list.append((image_size[0], image_size[1]))

        image_list = ImageList(images, image_sizes_list)
        return image_list, targets
            

具体代码如下:

一,对图片进行normalize处理

1.查看图片的类型和图片的设备类型
2.传入图片的均值和方差,将其转成和图片类型和相应的设备类型上
3.执行减均值,除方差操作

    def normalize(self, image):
        """标准化处理"""
        dtype, device = image.dtype, image.device
        mean = torch.as_tensor(self.image_mean, dtype=dtype, device=device)
        std = torch.as_tensor(self.image_std, dtype=dtype, device=device)
        # [:, None, None]: shape [3] -> [3, 1, 1]
        return (image - mean[:, None, None]) / std[:, None, None]

二、对图片进行resize操作,resize到指定范围的最大宽高上,防止图片尺寸过大造成显卡爆炸

    def resize(self, image, target):
        # type: (Tensor, Optional[Dict[str, Tensor]]) -> Tuple[Tensor, Optional[Dict[str, Tensor]]]
        """
        将图片缩放到指定的大小范围内,并对应缩放bboxes信息
        Args:
            image: 输入的图片
            target: 输入图片的相关信息(包括bboxes信息)

        Returns:
            image: 缩放后的图片
            target: 缩放bboxes后的图片相关信息
        """
        # image shape is [channel, height, width]
        h, w = image.shape[-2:]

        if self.training:
            size = float(self.torch_choice(self.min_size))  # 指定输入图片的最小边长,注意是self.min_size不是min_size
        else:
            # FIXME assume for now that testing uses the largest scale
            size = float(self.min_size[-1])    # 指定输入图片的最小边长,注意是self.min_size不是min_size

    
        image = _resize_image(image, size, float(self.max_size))

        if target is None:
            return image, target

        bbox = target["boxes"]
        # 根据图像的缩放比例来缩放bbox
        bbox = resize_boxes(bbox, [h, w], image.shape[-2:])
        target["boxes"] = bbox

        return image, target

具体的resize方法

def _resize_image(image, self_min_size, self_max_size):
    # type: (Tensor, float, float) -> Tensor
    im_shape = torch.tensor(image.shape[-2:])
    min_size = float(torch.min(im_shape))    # 获取高宽中的最小值
    max_size = float(torch.max(im_shape))    # 获取高宽中的最大值
    scale_factor = self_min_size / min_size  # 根据指定最小边长和图片最小边长计算缩放比例

    # 如果使用该缩放比例计算的图片最大边长大于指定的最大边长
    if max_size * scale_factor > self_max_size:
        scale_factor = self_max_size / max_size  # 将缩放比例设为指定最大边长和图片最大边长之比

    # interpolate利用插值的方法缩放图片
    # image[None]操作是在最前面添加batch维度[C, H, W] -> [1, C, H, W]
    # bilinear只支持4D Tensor
    image = torch.nn.functional.interpolate(
        image[None], scale_factor=scale_factor, mode="bilinear", recompute_scale_factor=True,
        align_corners=False)[0]

    return image

同时对图片的坐标也进行缩放;

def resize_boxes(boxes, original_size, new_size):
    # type: (Tensor, List[int], List[int]) -> Tensor
    """
    将boxes参数根据图像的缩放情况进行相应缩放

    Arguments:
        original_size: 图像缩放前的尺寸
        new_size: 图像缩放后的尺寸
    """
    ratios = [
        torch.tensor(s, dtype=torch.float32, device=boxes.device) /
        torch.tensor(s_orig, dtype=torch.float32, device=boxes.device)
        for s, s_orig in zip(new_size, original_size)
    ]
    ratios_height, ratios_width = ratios
    # Removes a tensor dimension, boxes [minibatch, 4]
    # Returns a tuple of all slices along a given dimension, already without it.
    xmin, ymin, xmax, ymax = boxes.unbind(1)
    xmin = xmin * ratios_width
    xmax = xmax * ratios_width
    ymin = ymin * ratios_height
    ymax = ymax * ratios_height
    return torch.stack((xmin, ymin, xmax, ymax), dim=1)

三、对图片resize完以后,图片的宽高被限制到最大宽高上面,此时每张图片的宽高各不一样,如果需要进行并行处理,仍然需要对该batch内的图片进行打包,处理成统一的宽高。具体步骤如下:

1.在该batch内找到最大图片的宽和高,以及最大的通道数目,假设为[c,h,w]
2.将计算得到的最大宽高调整到具体strdide的最近整数倍
3.创建shape为batch_shape且值全部为0的tensor
4. 将输入images中的每张图片复制到新的batched_imgs的每张图片中,对齐左上角,保证bboxes的坐标不变, 这样保证输入到网络中一个batch的每张图片的shape相同
打包的原理如下:
在创建为0的tensor中对每张图片以左上角为原点进行加入
在这里插入图片描述

 def batch_images(self, images, size_divisible=32):
        # type: (List[Tensor], int) -> Tensor
        """
        将一批图像打包成一个batch返回(注意batch中每个tensor的shape是相同的)
        Args:
            images: 输入的一批图片
            size_divisible: 将图像高和宽调整到该数的整数倍

        Returns:
            batched_imgs: 打包成一个batch后的tensor数据
        """

        # 分别计算一个batch中所有图片中的最大channel, height, width
        max_size = self.max_by_axis([list(img.shape) for img in images])

        stride = float(size_divisible)
        # max_size = list(max_size)
        # 将height向上调整到stride的整数倍
        max_size[1] = int(math.ceil(float(max_size[1]) / stride) * stride)
        # 将width向上调整到stride的整数倍
        max_size[2] = int(math.ceil(float(max_size[2]) / stride) * stride)

        # [batch, channel, height, width]
        batch_shape = [len(images)] + max_size

        # 创建shape为batch_shape且值全部为0的tensor
        batched_imgs = images[0].new_full(batch_shape, 0)
        for img, pad_img in zip(images, batched_imgs):
            # 将输入images中的每张图片复制到新的batched_imgs的每张图片中,对齐左上角,保证bboxes的坐标不变
            # 这样保证输入到网络中一个batch的每张图片的shape相同
            # copy_: Copies the elements from src into self tensor and returns self
            pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img)

        return batched_imgs

分别计算一个batch中所有图片中的最大channel, height, width

    def max_by_axis(self, the_list):
        # type: (List[List[int]]) -> List[int]
        maxes = the_list[0]
        for sublist in the_list[1:]:
            for index, item in enumerate(sublist):
                maxes[index] = max(maxes[index], item)
        return maxes

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Keras实现Faster R-CNN旋转目标检测算法可以按以下步骤进行: 1. 数据预处理:将训练数据转换为网络需要的格式,包括图片大小的调整、数据增强等等。 2. 构建模型:搭建Faster R-CNN网络模型,包括特征提取层、RPN层、ROI Pooling层、分类和回归层等。 3. 编译模型:设置模型的优化器、损失函数等参数。 4. 训练模型:对构建好的模型进行训练,并保存训练好的权重。 5. 模型评估:使用测试数据对训练好的模型进行评估,计算模型的精度、召回率等指标。 以下是一个基于Keras实现Faster R-CNN旋转目标检测算法的示例代码: ``` # 数据预处理 # TODO: 数据预处理代码 # 构建模型 input_shape = (None, None, 3) img_input = Input(shape=input_shape) shared_layers = nn.nn_base(img_input, trainable=True) # RPN网络 num_anchors = len(config.RPN_ANCHOR_RATIOS) * len(config.ANGLE_BINS) rpn = nn.rpn(shared_layers, num_anchors) # ROI Pooling层 roi_input = Input(shape=(config.TRAIN_ROIS_PER_IMAGE, 5)) roi_pooling = PyramidROIAlign([config.POOL_SIZE, config.POOL_SIZE], name="roi_align")([shared_layers, roi_input]) # 分类和回归层 x = TimeDistributed(Flatten(name='flatten'))(roi_pooling) x = TimeDistributed(Dense(4096, activation='relu', name='fc1'))(x) x = TimeDistributed(Dropout(0.5))(x) x = TimeDistributed(Dense(4096, activation='relu', name='fc2'))(x) x = TimeDistributed(Dropout(0.5))(x) # 分类和回归输出 cls_output = TimeDistributed(Dense(config.NUM_CLASSES, activation='softmax', kernel_initializer='zero'), name='dense_class_{}'.format(config.NUM_CLASSES))(x) angle_output = TimeDistributed(Dense(num_anchors * config.NUM_ANGLES, activation='linear', kernel_initializer='zero'), name='dense_angle_{}'.format(num_anchors * config.NUM_ANGLES))(x) bbox_output = TimeDistributed(Dense(num_anchors * 4, activation='linear', kernel_initializer='zero'), name='dense_regress_{}'.format(4))(x) # 编译模型 model = Model([img_input, roi_input], [cls_output, angle_output, bbox_output]) model.compile(optimizer=Adam(lr=config.LEARNING_RATE), loss=[losses.class_loss(), losses.angle_loss(), losses.rpn_regress_loss(config.NUM_ANCHORS)]) # 训练模型 # TODO: 训练模型代码 # 模型评估 # TODO: 模型评估代码 ``` 需要注意的是,在实现旋转目标检测时,需要对RoI Pooling和NMS等部分进行修改,以支持旋转矩形的处理。具体实现可以参考上述项目的代码和论文《R2CNN: Rotational Region CNN for Orientation Robust Scene Text Detection》。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值