目标检测算法-锚框公式推导及代码详解

  • 0 沐神对锚框的宽高计算并未推导以及讲解
  • 1 锚框宽高公式推导
    • 1.1 基础概念
    • 1.2 锚框宽高公式推导
    • 1.3 图片验证计算
    • 1.4 小结
  • 2 代码详解
    • 2.1 看一下数据
    • 2.2 生成多个锚框(重点)
    • 2.3 在图像上绘制多个锚框
    • 2.4 图片验证锚框宽高计算

0 沐神对锚框的宽高计算并未推导以及讲解

在沐神b站视频以及书籍中并未对锚框的宽高计算进行推导,只是给出结论:锚框的宽度和高度分别分别是 h s r hs\sqrt{r} hsr ​和 h s / r hs/\sqrt{r} hs/r ​ 。对应的代码也是一知半解,具体有歧义代码如下:

    w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),sizes[0] * torch.sqrt(ratio_tensor[1:])))\* in_height / in_width  # 处理矩形输入h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),sizes[0] / torch.sqrt(ratio_tensor[1:])))

基于此,我将对锚框宽高的公式进行推导,并且利用实际图片进行验证。
参考资料:

[1]: 动手学深度学习-锚框.
[2]: 锚框(anchor box)理解和代码实现.

1 锚框宽高公式推导

1.1 基础概念

假设输入图像的高度为H,宽度为W 。以图像的每个像素为中心生成不同形状的锚框,假设锚框的高度为h,宽度为w:

  • 真实边界框(ground-truth bounding box)
    在训练集中人工标定的已经包含标号物体的边框,其坐标 ( X m i n , Y m i n , X m a x , Y m a x ) (X_{min},Y_{min},X_{max},Y_{max}) (Xmin​,Ymin​,Xmax​,Ymax​)即为待检测目标的真实坐标。
  • 缩放比(scale)
    锚框的面积照输入图像按比例缩放的大小,其中 s ∈ ( 0 , 1 ] s∈(0,1] s∈(0,1]。用公式解释就是:
    w h W H = s 2 \frac{wh}{WH}=s^2 WHwh​=s2此处歧义点是h和H是不是有 h H = s \frac{h}{H}=s Hh​=s的关系,其实是没有的,不然锚框的宽高都是固定的了。锚框的宽和高与输入图片的宽高没有对应关系,只是锚框的面积与输入图片的面积成整体缩小的关系。
  • 宽高比(aspect ratio)
    生成锚框的宽和高的比率,其中 r > 0 r>0 r>0。用公式解释就是:
    w h = r \frac{w}{h}=r hw​=r
  • 锚框(aspect ratio)
    锚框是以每个像素为中心,生成多个缩放比和宽高比不同的框体。目标检测就是拿这若干个锚框与真实边界框进行比较,寻找更贴近真实边界框的过程。
  • 锚框的个数
    为了生成多个不同形状的锚框,让我们设置许多缩放比取值 s 1 , s 2 , . . . , s n s_1,s_2,...,s_n s1​,s2​,...,sn​ 。宽高比取值 r 1 , r 2 , . . . , r m r_1,r_2,...,r_m r1​,r2​,...,rm​。为了方便取值,我们只考虑包含 s 1 s_1 s1​或 r 1 r_1 r1​的组合: ( s 1 , r 1 ) , ( s 1 , r 2 ) , . . . , ( s 1 , r m ) , ( s 2 , r 1 ) , . . . , ( s n , r 1 ) , (s_1,r_1),(s_1,r_2),...,(s_1,r_m),(s_2,r_1),...,(s_n,r_1), (s1​,r1​),(s1​,r2​),...,(s1​,rm​),(s2​,r1​),...,(sn​,r1​),引用参考链接2的图片:

    也就是说,以同一像素为中心的锚框的数量是n+m-1
    代码举例则是:

    Y = multibox_prior(X,sizes = [0.75,0.5,0.25],ratios=[1,2,0.5])
    #len(sizes)=3,len(ratios)=3,一个像素共生成3+3-1=5个锚框
    

    对于整个输入图像,将共生成个 W ∗ H ∗ ( n + m − 1 ) W*H*(n+m-1) W∗H∗(n+m−1)锚框。

1.2 锚框宽高公式推导

  • 输入图片归一化
    将输入图片的大小归一化到(0,1)的尺度,这样只要知道图像的scale就能够很容易在当前尺度下使用矩形框定位。假设 W , H W,H W,H为输入图片的宽高,归一化方程如下:
    { W W = 1 H H = 1 \begin{cases}\frac{W}{W}=1\\[3ex]\frac{H}{H}=1 \\[3ex]\end{cases} ⎩ ⎨ ⎧​WW​=1HH​=1​
  • 锚框宽高推导
    设 w , h w,h w,h为锚框的实际宽和高,则有:
    { w h W H = s 2 w h = r \begin{cases}\frac{wh}{WH}=s^2\\[3ex]\frac{w}{h}=r \\[3ex]\end{cases} ⎩ ⎨ ⎧​WHwh​=s2hw​=r​ → \rightarrow → { w = s H W r h = s W H r \begin{cases} w=s\sqrt{HWr} \\[3ex] h=s\sqrt{\frac{WH}{r}} \\[3ex]\end{cases} ⎩ ⎨ ⎧​w=sHWr ​h=srWH​ ​​
    对 w , h w,h w,h归一化:
    w 0 = w W = s H r W w_0 = \frac{w}{W} = s\sqrt{\frac{Hr}{W}} w0​=Ww​=sWHr​ ​ h 0 = h H = s W H r h_0 = \frac{h}{H} = s\sqrt{\frac{W}{Hr}} h0​=Hh​=sHrW​ ​显然:当H = W时 w 0 = s r w_0 =s\sqrt{r} w0​=sr ​, h 0 = s r h_0 =\frac{s}{\sqrt{r}} h0​=r ​s​
  • 归一化后的锚框宽高比
    因为输入图片和锚框都进行了归一化计算,所以归一化后的锚框宽高比也对应发生变化,我们利用公式进行推导,并且利用图片进行验证其变化。
    r 0 = w 0 h 0 = H r W r_0 = \frac{w_0}{h_0}= \frac{Hr}{W} r0​=h0​w0​​=WHr​

1.3 图片验证计算

已知图片的像素为(889,500),为了形象的表示图片锚框的计算和归一化的过程。我将其放在ppt中进行绘制。如上图我巧妙的设置了一个锚框框住了喵喵。在ppt中三个框的宽度分别为4.81cm,4.63cm,4.81cm,于是锚框的坐标信息为 x m i n = W ∗ w 1 w 1 + w 2 + w 3 = 889 ∗ 4.81 4.81 + 4.63 + 4.81 = 300 x_{min} = \frac{W*w_1}{w_1+w_2+w_3} = \frac{889*4.81}{4.81+4.63+4.81} = 300 xmin​=w1​+w2​+w3​W∗w1​​=4.81+4.63+4.81889∗4.81​=300, x m a x = W ∗ ( w 1 + w 2 ) w 1 + w 2 + w 3 = 889 ∗ ( 4.81 + 4.63 ) 4.81 + 4.63 + 4.81 = 589 x_{max} = \frac{W*(w_1+w_2)}{w_1+w_2+w_3} = \frac{889*(4.81+4.63)}{4.81+4.63+4.81} = 589 xmax​=w1​+w2​+w3​W∗(w1​+w2​)​=4.81+4.63+4.81889∗(4.81+4.63)​=589,高度为图片的高度。
归一化后 x m i n N = x m i n W = 300 889 = 0.34 x_{minN} = \frac{x_{min} }{W} = \frac{300}{889} = 0.34 xminN​=Wxmin​​=889300​=0.34, x m a x = x m a x W = 589 889 = 0.66 x_{max} = \frac{x_{max} }{W} = \frac{589}{889} = 0.66 xmax​=Wxmax​​=889589​=0.66。
于是计算出锚框的宽高分别为 h = 300 , w = 289 h=300,w=289 h=300,w=289,根据缩放比和宽高比的定义,反算缩放比和宽高比,计算过程如下:
{ s 1 2 = w h W H r 1 = w h \begin{cases}s_1^2=\frac{wh}{WH}\\[3ex] r_1=\frac{w}{h} \\[3ex]\end{cases} ⎩ ⎨ ⎧​s12​=WHwh​r1​=hw​​ → \rightarrow → { s = w h W H = 289 ∗ 500 889 ∗ 500 = 0.57 r 1 = w h = 289 500 = 0.58 \begin{cases} s=\sqrt{\frac{wh}{WH}}=\sqrt{\frac{289*500}{889*500}}=0.57 \\[3ex] r_1=\frac{w}{h} =\frac{289}{500}=0.58 \\[3ex]\end{cases} ⎩ ⎨ ⎧​s=WHwh​ ​=889∗500289∗500​ ​=0.57r1​=hw​=500289​=0.58​
计算得出 s = 0.57 , r = 0.58 s=0.57,r=0.58 s=0.57,r=0.58。
此时我们用这组(r1,s1)来计算归一化的 r 0 r_0 r0​,看看是不是和实际情况相同。
r 0 = w 0 h 0 = H r W = 500 ∗ 0.58 889 = 0.32 r_0 = \frac{w_0}{h_0}= \frac{Hr}{W}= \frac{500*0.58}{889}=0.32 r0​=h0​w0​​=WHr​=889500∗0.58​=0.32
而右图中 r 0 = w 0 h 0 = 0.32 1 = 0.32 r_0 =\frac{w_0}{h_0}=\frac{0.32}{1}=0.32 r0​=h0​w0​​=10.32​=0.32,说明计算公式正确。之后我们会将 s = 0.57 , r = 0.58 s=0.57,r=0.58 s=0.57,r=0.58设置为代码参数,进一步验证代码的正确性。

1.4 小结

  • 1.锚框的宽高计算公式:
    w 0 = w W = s H r W w_0 = \frac{w}{W} = s\sqrt{\frac{Hr}{W}} w0​=Ww​=sWHr​ ​ h 0 = h H = s W H r h_0 = \frac{h}{H} = s\sqrt{\frac{W}{Hr}} h0​=Hh​=sHrW​ ​
  • 2.归一化后的锚框宽高比不为r,而是 r 0 = H r W r_0=\frac{Hr}{W} r0​=WHr​。

2 代码详解

代码部分主要分为4块。

  • 1:调包并导入数据;
  • 2:生成多个锚框的代码;
  • 3:编写展示锚框代码;
  • 4:数据验证代码正确性
    我尽量在每个关键步骤都写上注释。

2.1 看一下数据

import torch
from d2l import torch as d2l
import matplotlib.pyplot as plt
d2l.set_figsize()
img = d2l.plt.imread(r"./torch_data/test_imgs/cat_dogs.jpg")
d2l.plt.imshow(img)
data = torch.tensor(img)
#看一下输入图片的形状
data.shape
#jpg图片是[h(高),w(宽),c(通道数)]格式

2.2 生成多个锚框(重点)

根据输入图片以及多个不同缩放比和宽高比,在同一个像素下生成多个锚框。此代码较沐神给出的代码做出了一些更改,主要更改的内容在w和h的计算公式以及一些标号的解释。希望大家能看的明白!

def multibox_prior(data,sizes,ratios):"""生成以每个像素为中心具有不同形状的锚框data:[height,width,channels];sizes:list;ratios:listoutput:[1,height*width*(len(sizes)+len(ratios)-1),4]"""#输入图像的高和宽in_height,in_width = data.shape[:2]#使用设备加速,缩放比和宽高比个数device,num_sizes,num_ratios = data.device,len(sizes),len(ratios)#一个像素生成的锚框的个数boxes_per_pixel = num_sizes+num_ratios-1#将数据放到同一个设备上size_tensor = torch.tensor(sizes,device=device)ratio_tensor = torch.tensor(ratios,device=device)#每个像素是1*1的正方形,则中心点的坐标是(0.5,0.5),因为中心点要设置(0.5,0.5)的偏移offset_h,offset_w = 0.5,0.5#归一化系数,将图像的宽高归一化到0-1之间step_h = 1/in_heightstep_w = 1/in_width#生成所有锚框的中心点坐标,并将数值归一化到0-1center_h = (torch.arange(in_height,device=device)+offset_h)*step_hcenter_w = (torch.arange(in_width,device=device)+offset_w)*step_w#网格化中心点坐标shift_y,shift_x = torch.meshgrid(center_h,center_w)#reshape成一维,shift_y和shift_x坐标一一对应shift_y,shift_x = shift_y.reshape(-1),shift_x.reshape(-1)#每个像素生成的锚框的宽和高,因为图片归一化了,将锚框高宽缩小到和图片一样的格式#计算公式:w_0 = s*√(r)*√(H/W)  h_0 = s/(√(r)*√(H/W))#norm=√(H/W),这个就是个标号,方便计算 norm = torch.sqrt(torch.tensor(in_height)/torch.tensor(in_width)) #只考虑包含s1或r1的组合,因此S*r1 与s1*R合并即为n+m-1个锚框w_0 = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),size_tensor[0] * torch.sqrt(ratio_tensor[1:])))*normh_0 = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),size_tensor[0] / torch.sqrt(ratio_tensor[1:])))/norm#除以2来获得半高和半宽,转置是生成(锚框个数)*(4个位置数据)的格式anchor_manipulations = torch.stack((-w_0, -h_0, w_0, h_0)).T.repeat(in_height * in_width, 1) / 2# 每个中心点都将有“boxes_per_pixel”个锚框,# 所以生成含所有锚框中心的网格,重复了“boxes_per_pixel”次out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],dim=1).repeat_interleave(boxes_per_pixel, dim=0)output = out_grid + anchor_manipulationsreturn output.unsqueeze(0)

2.3 在图像上绘制多个锚框

构建show_bboxes()函数,用来展示多个锚框。此处代码不必深度理解,只是个工具。

#@save
def show_bboxes(axes, bboxes, labels=None, colors=None):"""显示所有边界框"""def _make_list(obj, default_values=None):if obj is None:obj = default_valueselif not isinstance(obj, (list, tuple)):obj = [obj]return objlabels = _make_list(labels)colors = _make_list(colors, ['b', 'g', 'r', 'm', 'c'])for i, bbox in enumerate(bboxes):color = colors[i % len(colors)]rect = d2l.bbox_to_rect(bbox.detach().numpy(), color)axes.add_patch(rect)if labels and len(labels) > i:text_color = 'k' if color == 'w' else 'w'axes.text(rect.xy[0], rect.xy[1], labels[i],va='center', ha='center', fontsize=9, color=text_color,bbox=dict(facecolor=color, lw=0))

2.4 图片验证锚框宽高计算

根据1.3部分的内容,设置(s1,r1)=(0.57,0.58),且中心点为(250,445),利用(s1,r1)代入代码生成对应图像,验证生成的锚框图像是否框住了喵喵,并且是否与1.3设计的锚框形状相同。

H,W = data.shape[:2]
#s1=0.57 r1=0.58
Y = multibox_prior(data,sizes = [0.57],ratios=[0.58])
#一共生成生成500*889*(1+1-1)=444500个锚框,锚框,4是位置信息[xmin,ymin,xmax,ymax]
print(Y.shape)
#锚框分割(H,W,1,4)由于s=1,r=1,每个像素点生成1个锚框,每个锚框有4个位置信息
boxes = Y.reshape(H,W,1,4)
#此处查看中心点(250,445)(s1,r1)=(0.57,0.58)建立的锚框
boxes[250,445,:,:]


利用show_bboxs()函数,查看该锚框的生成情况。

d2l.set_figsize()
bbox_scale = torch.tensor((W, H, W, H))
fig = d2l.plt.imshow(img)
show_bboxes(fig.axes, boxes[250, 445, :, :] * bbox_scale,['s=0.57, r=0.58'])


由上图可知,该锚框很好的圈住了喵喵,且与设计的形状基本相同,可以认为锚框的计算公式和代码正确。

【目标检测算法-锚框公式推导及代码详解】相关推荐

  1. 目标检测:CenterNet论文解读及代码详解

    论文思想 当前anchor-based目标检测方法可分one-stage.two-stage两种.one-stage模型利用anchor机制得到大量的框,之后直接加入回归.分类分支对框进行分类与微调. ...

  2. Transformer | DETR目标检测中的位置编码position_encoding代码详解

    本文主要描述的是DETR论文中的position_encoding,详细DETR论文解析可参考 论文篇 | 2020-Facebook-DETR :利用Transformers端到端的目标检测=> ...

  3. 免疫算法(IA)MatLab代码详解

    CSDN编辑器里面没有MATLAB选项,所以我为了注释更清楚,用的是//,大家不要被误解了呀,算法看代码就好了 1 免疫算法的精髓 生物免疫系统:动态性免疫.自适应免疫 免疫算法-保证信息的无害性.有 ...

  4. 【目标检测】IoU(交并比)详解及代码实现

    1. IOU概述 IoU的全称为交并比(Intersection over Union),是目标检测中使用的一个概念,IoU计算的是"预测的边框"和"真实的边框" ...

  5. CNN目标检测(一):Faster RCNN详解

    ↑↑↑↑目录在这里↑↑↑↑↑ Faster RCNN github : https://github.com/rbgirshick/py-faster-rcnn Faster RCNN paper : ...

  6. [转]CNN目标检测(一):Faster RCNN详解

    https://blog.csdn.net/a8039974/article/details/77592389 Faster RCNN github : https://github.com/rbgi ...

  7. 独家总结 | KNN算法Python实现(附代码详解及注释)

    ↑ 点击上方[计算机视觉联盟]关注我们 上一篇已经介绍KNN算法的基本原理,这篇就不再赘述(公式太多,读不懂? 一文带你领略KNN近邻算法~简单易懂) 纸上得来终觉浅,仅仅懂了原理还不够,要用代码实践 ...

  8. 目标检测特殊层:ROI Align层详解

    ROI Align 是在Mask-RCNN这篇论文里提出的一种区域特征聚集方式, 很好地解决了ROI Pooling操作中两次量化造成的区域不匹配(mis-alignment)的问题.实验显示,在检测 ...

  9. 【目标检测-YOLO】YOLOv5-v6.0-网络架构详解(第二篇)

    参考:YOLOv5-5.0v-yaml 解析及模型构建(第二篇)_星魂非梦的博客-CSDN博客 前文:YOLOv5-v6.0-yolov5s网络架构详解(第一篇)_星魂非梦的博客-CSDN博客_yol ...

最新文章

  1. Conv1D和Conv2D的区别
  2. 同事把实数作为 HashMap 的key,领导发飙了...
  3. linux操作系统应急方案,服务器操作系统应急预案
  4. jenkins 自带环境变量
  5. [转]CentOS设置服务开机自动启动
  6. 扩展 HashMap
  7. 转:Delphi中destroy, free, freeAndNil, release用法和区别
  8. [转]How to Improve Entity Framework Add Performance?
  9. j2ee高并发时使用全局变量需要注意的问题
  10. 爬虫 知识点 总结。
  11. KORG Polysix for mac(四VCO单声道/多声道合成器)
  12. Hard problem CodeForces - 706C
  13. 使用谷歌学术镜像查找英文论文、英文论文阅读
  14. 上海大学计算机专业就业薪资,人均月薪过万?985、211、普通大学毕业生薪资水平大起底!和你想的不一样……...
  15. 【COS】函数使用技巧
  16. Golang内存逃逸
  17. 致童年,那些年我们逝去的岁月
  18. 【待办】三国杀单挑测试脚本
  19. 服务网关配置:Zuul
  20. android Wifi自动连接

热门文章

  1. CSDN 创始人蒋涛对话北大谢涛:AI 正在变革软件工程
  2. 区块链+用户生态 网易星球 VS 公信宝
  3. 卫星通信,给手机市场带来了什么?
  4. 使用免费RPA软件系统 构件自己的自动化流程 安装配置教程
  5. 大数据审计的发展_科技赋能下大数据审计的实施路径与发展趋势
  6. mongodb 字符串 截取_字符串截取
  7. android实现自定义相机以及图片的水印
  8. 支付宝花呗分期 错误ALIN10046
  9. 无处可逃:罗兴亚人的困境恶化 | 经济学人早报精选20210826
  10. 用深度学习算法预测未来股票走势