Tensorflow2.0---SSD网络原理及代码解析(二)-锚点框的生成

40 篇文章 2 订阅
7 篇文章 2 订阅

Tensorflow2.0—SSD网络原理及代码解析(二)-锚点框的生成

分析完SSD网络的原理之后,一起来看看代码吧~

代码转载于:https://github.com/bubbliiiing/ssd-tf2

在train.py中有一行代码:

priors = get_anchors((input_shape[0], input_shape[1]), anchors_size)

这行代码是用于生成锚点框的,原理对应于第一篇博客中2.1知识点。我们进get_anchors函数,发现它是在anchors.py文件中,该文件有一个类和一个函数。

net = {}
priorbox = PriorBox(img_size, anchors_size[0],max_size = anchors_size[1], aspect_ratios=[2],
                        variances=[0.1, 0.1, 0.2, 0.2],
                        name='conv4_3_norm_mbox_priorbox')
net['conv4_3_norm_mbox_priorbox'] = priorbox.call([features_map_length[0],features_map_length[0]])

在锚点框生成函数中,都是按照这种格式进行创建的,先实例化一个PriorBox类,然后调用其中的call方法。

    def call(self, input_shape, mask=None):
        # --------------------------------- #
        #   获取输入进来的特征层的宽和高
        #   比如38x38
        # --------------------------------- #
        layer_width = input_shape[self.waxis]
        layer_height = input_shape[self.haxis]

        # --------------------------------- #
        #   获取输入进来的图片的宽和高
        #   比如300x300
        # --------------------------------- #
        img_width = self.img_size[1]
        img_height = self.img_size[0]
        box_widths = []  #存放anchor box的宽
        box_heights = []  #存放anchor box的高
        # --------------------------------- #
        #   self.aspect_ratios一般有两个值
        #   [1, 1, 2, 1/2]
        #   [1, 1, 2, 1/2, 3, 1/3]
        # --------------------------------- #
        for ar in self.aspect_ratios:
            # 首先添加一个较小的正方形
            if ar == 1 and len(box_widths) == 0:
                box_widths.append(self.min_size)
                box_heights.append(self.min_size)
            # 然后添加一个较大的正方形
            elif ar == 1 and len(box_widths) > 0:
                box_widths.append(np.sqrt(self.min_size * self.max_size))
                box_heights.append(np.sqrt(self.min_size * self.max_size))
            # 然后添加长方形
            elif ar != 1:
                box_widths.append(self.min_size * np.sqrt(ar))
                box_heights.append(self.min_size / np.sqrt(ar))

        # --------------------------------- #
        #   获得所有先验框的宽高1/2
        # --------------------------------- #
        box_widths = 0.5 * np.array(box_widths)
        box_heights = 0.5 * np.array(box_heights)

        # --------------------------------- #
        #   每一个特征层对应的步长
        # --------------------------------- #
        step_x = img_width / layer_width
        step_y = img_height / layer_height

        # --------------------------------- #
        #   生成网格中心
        # --------------------------------- #
        linx = np.linspace(0.5 * step_x, img_width - 0.5 * step_x,
                           layer_width)
        liny = np.linspace(0.5 * step_y, img_height - 0.5 * step_y,
                           layer_height)

        plt.scatter(linx, liny)
        # plt.show()


        centers_x, centers_y = np.meshgrid(linx, liny)
        centers_x = centers_x.reshape(-1, 1)
        centers_y = centers_y.reshape(-1, 1)

        plt.scatter(centers_x, centers_y)
        # plt.show()


        # 每一个先验框需要两个(centers_x, centers_y),前一个用来计算左上角,后一个计算右下角
        num_priors_ = len(self.aspect_ratios)
        prior_boxes = np.concatenate((centers_x, centers_y), axis=1)
        print(prior_boxes.shape)

        prior_boxes = np.tile(prior_boxes, (1, 2 * num_priors_))
        print(prior_boxes.shape)

        # 获得先验框的左上角和右下角(由xy坐标转为左右角坐标形式)
        prior_boxes[:, ::4] -= box_widths
        prior_boxes[:, 1::4] -= box_heights
        prior_boxes[:, 2::4] += box_widths
        prior_boxes[:, 3::4] += box_heights


        # --------------------------------- #
        #   将先验框变成小数的形式
        #   归一化
        # --------------------------------- #
        prior_boxes[:, ::2] /= img_width
        prior_boxes[:, 1::2] /= img_height
        prior_boxes = prior_boxes.reshape(-1, 4)
        prior_boxes = np.minimum(np.maximum(prior_boxes, 0.0), 1.0)


        num_boxes = len(prior_boxes)

        if len(self.variances) == 1:
            variances = np.ones((num_boxes, 4)) * self.variances[0]
        elif len(self.variances) == 4:
            variances = np.tile(self.variances, (num_boxes, 1))
        else:
            raise Exception('Must provide one or four variances.')

        prior_boxes = np.concatenate((prior_boxes, variances), axis=1)
        return prior_boxes

步骤总结:
**1.**先创建存放anchor box的长宽的字典box_widths 和 box_heights 。然后根据aspect_ratios来进行生成anchor box的长宽。
在这里插入图片描述
**2.**然后生成网格中心,这里的做法是先生成对角线,然后基于np.meshgrid来生成最终的网格中心。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里,只选取三个有效特征层生成的anchor网格中心点。可以根据上述图片可以看得出来,随着网络层级越深,在原图中生成的锚点数量就越少,说明越深层级的feature map主要是检测大物体的,浅层级的feature map主要是检测小物体的。
**3.**基于网格中心点坐标和每个层级生成的anchor box的长宽一半,可以计算出每个层级生成的锚点框左上角和右下角坐标。
在这里插入图片描述
此时,prior_boxes的shape为(1444,16),1444表示的是该层级,生成锚点的数量,同理,在其他层级中,prior_boxes的shape分别为(361, 24),(100, 24),(25, 24),(9, 16),(1, 16),后面数字不相同的原因是不同层级每个锚点生成的box的数目是不一样的。
**4.**将prior_boxes进行归一化,将坐标全部归一化成(0,1),并进行reshape到(-1,4),再进行负值坐标剔除操作。最后与variances 进行横向拼接。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进我的收藏吃灰吧~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值