faster rcnn pytorch 复现系列(二):generate_anchors源码解析

本文深入探讨了目标检测中锚点生成算法的核心原理,详细解释了如何通过枚举长宽比和尺度来生成一系列基准锚点,适用于不同场景的目标检测任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 总函数 generate_anchors

2. 函数分功能写,首先是ratios的实现,其次是scale的实现

3. anchor2WHXY函数+WsHsXsYs2anchors函数[s表示复数]

4.  _ratio_enum(anchor,ratios) 

5 ._scale_enum(anchor,scales)

6. 最终获得的anchors的坐标:


学习到的变成知识点:

函数按照功能分开写,每一个函数只实现一个功能,如果需要叠加,交给循环或者np.vstack

其中ratios函数的功能:一次只实现3种ratios的变化 _ratio_enum

scale的功能:一次只实现3种scale的变化,_scale_enum

要得到3*3anchors,交给stack处理

 

首先,添加print,然后直接运行py文件,生成anchor结果

大意理解:

由一个anchor得到9个anchors

[0 0 15 15]


[[ -84.  -40.   99.   55.]
 [-176.  -88.  191.  103.]
 [-360. -184.  375.  199.]
 [ -56.  -56.   71.   71.]
 [-120. -120.  135.  135.]
 [-248. -248.  263.  263.]
 [ -36.  -80.   51.   95.]
 [ -80. -168.   95.  183.]
 [-168. -344.  183.  359.]]


 

1. 总函数 generate_anchors

  输入包括:特征图对应于原图的大小,ratios长宽比,scales放大倍数

def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
                     scales=2**np.arange(3, 6)):
    """
    Generate anchor (reference) windows by enumerating aspect ratios X
    scales wrt a reference (0, 0, 15, 15) window.
    """
    base_anchor = np.array([1, 1, base_size, base_size]) - 1
    print ("base anchors",base_anchor)

    ratio_anchors = _ratio_enum(base_anchor, ratios)
    print ("anchors after ratio",ratio_anchors)
    """
    对ratios后处理得到的每一行,分别进行3次scale变化,循环三次
    """
    anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales)
                         for i in xrange(ratio_anchors.shape[0])])
    print ("achors after ration and scale",anchors)
    return anchors

2. 函数分功能写,首先是ratios的实现,其次是scale的实现

  其中ratios函数的功能:一次实现3种ratios的变化

  scale的功能:一次实现3中scale的变化,其余交给循环处理x

3. anchor2WHXY函数+WsHsXsYs2anchors函数[s表示复数]

  无论是ratio还是scale的实现,本身的中心点没有变,只是长宽比发生了变化 ,所以需要相互转换。

  下面两个scales和ratios的函数的实现,都是先将anchor2whxy然后WsHsXsYs2anchors 。

def _whctrs(anchor):
    """
    Return width, height, x center, and y center for an anchor (window).
    本身负责的只是一个行向量的转变,x0 y0 x1 y1 to  xc yc w h
    input:anchor [x0,y0,x1,y1]
    """
    w = anchor[2] - anchor[0] + 1
    h = anchor[3] - anchor[1] + 1
    x_ctr = anchor[0] + 0.5 * (w - 1)
    y_ctr = anchor[1] + 0.5 * (h - 1)
    return w, h, x_ctr, y_ctr

def _mkanchors(ws, hs, x_ctr, y_ctr):
    """
    input:xc yc w_after h_after
    out:anchors 注意这里是anchors复数
    method:首先需要将w改成列向量,然后水平拼接
    
             x0  y0 x1 y1
    state1
    state2
    state3
    ...
    """
    #(x_ctr, y_ctr) 7.5  7.5  
    ws = ws[:, np.newaxis]#[[23],[16],[11]]  col 
    hs = hs[:, np.newaxis]#[[12],[16],[22]]
    anchors = np.hstack((x_ctr - 0.5 * (ws - 1),
                         y_ctr - 0.5 * (hs - 1),
                         x_ctr + 0.5 * (ws - 1),
                         y_ctr + 0.5 * (hs - 1)))
    return anchors

4.  _ratio_enum(anchor,ratios) 

  输入:一个anchor,return都是三个anchor。

def _ratio_enum(anchor, ratios):
    """
    input: 
          anchor[np.array]  [0,0,15,15] 
          ratios[list]   [0.5,1,2]
    output:
          anchors
    method:
          1.x0 y0 x1 y1 to xc yc w h 
          2.compute w_after and h_after
          3.xc yc w h to x0 y0 x1 y1
    """
    
    w, h, x_ctr, y_ctr = _whctrs(anchor)#
    size = w * h   #size:16*16=256
    size_ratios = size / ratios  #256/ratios[0.5,1,2]=[512,256,128]
    #round()方法返回x的四舍五入的数字,sqrt()方法返回数字x的平方根
    ws = np.round(np.sqrt(size_ratios)) #ws:[23 16 11]
    hs = np.round(ws * ratios)    #hs:[12 16 22],ws和hs一一对应。as:23&12
    #给定一组宽高向量,输出各个预测窗口,也就是将(宽,高,中心点横坐标,中心点纵坐标)的形式,转成
    #四个坐标值的形式
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)  
    return anchors

高比变换之后anchors的坐标

ratio_anchors = _ratio_enum(base_anchor, ratios)
       x0     y0      x1     y1
'''[[ -3.5,   2. ,  18.5,  13. ],
    [  0. ,   0. ,  15. ,  15. ],
    [  2.5,  -3. ,  12.5,  18. ]]'''

5 ._scale_enum(anchor,scales)

 对上一步得到的ratio_anchors中的三种宽高比的anchor,再分别进行三种scale的变换

 输入:一个anchor,return都是三个anchor。

def _scale_enum(anchor, scales):
    """
    输入一个anchr行向量,一次得到3种变化
    """

    w, h, x_ctr, y_ctr = _whctrs(anchor)
    ws = w * scales
    hs = h * scales
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

6. 最终获得的anchors的坐标:

anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales)
                         for i in xrange(ratio_anchors.shape[0])])
'''
[[ -84.  -40.   99.   55.]
 [-176.  -88.  191.  103.]
 [-360. -184.  375.  199.]
 [ -56.  -56.   71.   71.]
 [-120. -120.  135.  135.]
 [-248. -248.  263.  263.]
 [ -36.  -80.   51.   95.]
 [ -80. -168.   95.  183.]
 [-168. -344.  183.  359.]]

 

以下是使用 PyTorch 实现 Faster R-CNN 算法的代码示例: ```python import torch import torch.nn as nn import torch.nn.functional as F from torchvision.models import vgg16 class VGG16(nn.Module): def __init__(self): super(VGG16, self).__init__() self.features = vgg16(pretrained=True).features self.rpn = RPN(self.features.out_channels) self.roi_pool = nn.AdaptiveMaxPool2d((7,7)) self.fc1 = nn.Linear(512*7*7, 4096) self.fc2 = nn.Linear(4096, 4096) self.cls_score = nn.Linear(4096, 21) self.bbox_pred = nn.Linear(4096, 84) def forward(self, x): x = self.features(x) rpn_cls, rpn_reg = self.rpn(x) rois = self._generate_rois(rpn_cls, rpn_reg) roi_feat = self.roi_pool(rois) x = roi_feat.view(roi_feat.size(0), -1) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) cls_score = self.cls_score(x) bbox_pred = self.bbox_pred(x) return cls_score, bbox_pred def _generate_rois(self, rpn_cls, rpn_reg): anchors = self._generate_anchors(rpn_cls.size(2), rpn_cls.size(3)) rois = [] for i in range(rpn_cls.size(0)): inds = torch.nonzero(rpn_cls[i] > 0.7)[:, 0] if inds.numel() == 0: inds = torch.nonzero(rpn_cls[i] > 0.3)[:, 0] if inds.numel() == 0: inds = torch.arange(0, rpn_cls.size(2)).long() reg = rpn_reg[i][inds] anchor = anchors[inds] roi = self._bbox_transform(anchor, reg) rois.append(roi) rois = torch.cat(rois, 0) rois[:, 0::2].clamp_(min=0, max=x.size(3) - 1) rois[:, 1::2].clamp_(min=0, max=x.size(2) - 1) return rois def _generate_anchors(self, h, w): anchors = [] for s in [8, 16, 32]: for i in range(0, h, s): for j in range(0, w, s): anchors.append([j, i, j+s-1, i+s-1]) return torch.Tensor(anchors).to(device) def _bbox_transform(self, boxes, deltas): widths = boxes[:, 2] - boxes[:, 0] + 1.0 heights = boxes[:, 3] - boxes[:, 1] + 1.0 ctr_x = boxes[:, 0] + 0.5 * (widths - 1.0) ctr_y = boxes[:, 1] + 0.5 * (heights - 1.0) dx = deltas[:, 0::4] dy = deltas[:, 1::4] dw = deltas[:, 2::4] dh = deltas[:, 3::4] pred_ctr_x = dx * widths[:, None] + ctr_x[:, None] pred_ctr_y = dy * heights[:, None] + ctr_y[:, None] pred_w = torch.exp(dw) * widths[:, None] pred_h = torch.exp(dh) * heights[:, None] pred_boxes = torch.zeros(deltas.shape).to(device) pred_boxes[:, 0::4] = pred_ctr_x - 0.5 * (pred_w - 1.0) pred_boxes[:, 1::4] = pred_ctr_y - 0.5 * (pred_h - 1.0) pred_boxes[:, 2::4] = pred_ctr_x + 0.5 * (pred_w - 1.0) pred_boxes[:, 3::4] = pred_ctr_y + 0.5 * (pred_h - 1.0) return pred_boxes class RPN(nn.Module): def __init__(self, in_channels): super(RPN, self).__init__() self.conv1 = nn.Conv2d(in_channels, 512, kernel_size=3, padding=1) self.cls_score = nn.Conv2d(512, 18, kernel_size=1, stride=1) self.bbox_pred = nn.Conv2d(512, 36, kernel_size=1, stride=1) def forward(self, x): x = F.relu(self.conv1(x)) rpn_cls = self.cls_score(x) rpn_reg = self.bbox_pred(x) return rpn_cls, rpn_reg ``` 这里实现的是在 VGG16 特征提取器的基础上加入 RPN(Region Proposal Network),用于生成候选框,然后再对这些候选框进行池化和全连接层的计算,得到最终的分类和回归结果。需要注意的是,这里只是一个简化版的 Faster R-CNN 实现,具体细节还需要根据实际需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值