【上采样问题】双线性插值的几何中心点重合与align_corners

回顾双线性插值上采样

双线性插值是分别在两个方向计算了共3次单线性插值,如图所示,先在x方向求2次单线性插值,获得R1(x, y1)、R2(x, y2)两个临时点,再在y方向计算1次单线性插值得出P(x, y)(实际上调换2次轴的方向先y后x也是一样的结果)。

优化问题:中心对齐

把3×3 的插值到4×4, 可能会有两种对齐方法。

在这里插入图片描述

对于图A:

  • 这张图是左上角为坐标系原点的情况,我们可以发现最左边x=0的点都会有概率直接复制到目标图像中(至少原点肯定是这样)

对于图B:

  • 这张图是右上角为坐标系原点的情况,我们可以发现最右面的点都会有概率直接复制到目标图像中(至少原点肯定是这样)

因此:采用不用的坐标系产生的结果是不一样的,而且无论我们采用什么坐标系,最左侧和最右侧(最上侧和最下侧)的点是不“公平的”,这是第一个问题。

把3×3 的插值到5×5:
在这里插入图片描述
上图:

  • 左侧是原图像(33),右侧是目标图像(55),原图像的几何中心点是(1, 1),目标图像的几何中心点是(2, 2),根据对应关系,目标图像的几何中心点对应的原图像的位置是(1.2, 1.2)
  • 目标图像的原点(0, 0)点和原始图像的原点是重合的,但是目标图像的几何中心点相对于原始图像的几何中心点偏右下,那么整体图像的位置会发生偏移,1个像素点跟相邻像素点的值的渐变或者突变形成图像颜色的渐变或者边界,所以参与计算的点相对都往右下偏移会产生相对的位置信息损失。这是第二个问题。

确定周围最近的四个点解决方案

几何中心点重合

在这里插入图片描述

中心点对齐的缩放在卷积网络结构设计中的注意事项

https://blog.csdn.net/xiaojiajia007/article/details/100150726

  • OpenCV缩放图片是基于中心点对齐的,
  • Pytorch中 mode=‘bilinear’, align_corners=False 与OpenCV中的保持一致,
  • Pytorch中 mode=‘bilinear’, align_corners=True 与TensorFlow中的align_corners=True的条件下保持一致。

tf的resize_bilinear并未中心对齐,坐标计算方式为

align_corners=False:

srcX=dstX* (srcWidth/dstWidth) ,
srcY = dstY * (srcHeight/dstHeight)

align_corners=True:

srcX=dstX* (srcWidth-1/dstWidth-1) ,
srcY = dstY * (srcHeight-1/dstHeight-1)

优化问题: align_corners 的原理

align_corners = True时,像素被视为网格的格子上的点,拐角处的像素对齐.可知是点之间是等间距的
align_corners = False时, 像素被视为网格的交叉线上的点, 拐角处的点依然是原图像的拐角像素,但是差值的点间却按照上图的取法取,导致点与点之间是不等距的

在这里插入图片描述

我们默认以红色表示原图,蓝色表示 bilinear 上采样两倍后的图片。

在这里插入图片描述

首先介绍 align_corners=False,首先观察绿色框内的像素,我们会发现它们严格遵守了 bilinear 的定义。

  • 而对于角上的四个点,其像素值保持了原图的值。
  • 边上的点则根据角点的值,进行了 bilinear 插值。

所以,我们从全局来看,align_corners=False 内部和边缘处采用了比较不同的规则。

align_corners=True 里,像素值位于网格上:

  • 会发现, 3 ∗ 3 3*3 33的图像上采两倍后,变成了 5 ∗ 5 5*5 55
  • 更广泛地来讲,对于输入尺寸是 ( 2 x + 1 ) ∗ ( 2 x + 1 ) (2x+1) * (2x+1) (2x+1)(2x+1) 的图片,其经过 align_corners=True 的上采样后,尺寸变为 ( 4 x + 1 ) ∗ ( 4 x + 1 ) (4x+1) * (4x+1) (4x+1)(4x+1)

align_corners=True 对语义分割的中要求

对于语义分割任务等,我们最优的选择是 align_corners=True 以及输入尺寸的倍数加 1。

align_corners=True 配合 n ∗ x + 1 n*x+1 nx+1 的尺寸,可以相对于 aling_corners=False 配合 n ∗ x n*x nx 的尺寸,减少内插的数目,并且避免外插。

从数值上来说,无论 True 还是 False,对于中间的像素,插值计算都是没有问题的。但是 False 的情况会对边角不友好。对于目标检测,鉴于少有物体中心出现在边角,所以影响不大;而 False 带来的整数倍上下采样,又方便了坐标值的计算。但是对于语义分割,边角像素也要纳入 mIoU 的计算,会对最终精度造成明显的影响 (0.5 in mIoU)。

如上,我们讨论了上采样的选择。那么,我们对图像处理时,理想情况下,下采样也应该选择对应的方式。既然上采样 align_corners=True,下采样也理应 align_corners。

  • cv2、PIL的插值都是 align_corners=False;OpenCV还进行了很多速度上的优化,比如用整形计算代替浮点数计算。
  • MXNet 默认 True。
  • 而 pytorch 和 tensorflow 都是可选。

为了保持和下采样时的操作对应一致,笔者建议大家进行密集输出任务的图像预处理时 (尤其是 resize 操作),放弃官方的 transform (PIL 实现) 以及 cv2 的实现,转而使用 pytorch 自己实现一份。

综上,我们分析了 align_corners 的原理,解释了输入尺寸设置为奇数的原因。并且笔者根据分析,推荐使用 pytorch 实现预处理中的 resize。

参考:https://zhuanlan.zhihu.com/p/87572724

可以明显的看到align_corners=True的时候,角点是对齐状态。而align_cornels=False的时候,角点并没有对齐。

用代码去描述上述的区别为

# align_corners = False
# x_ori is the coordinate in original image
# x_up is the coordinate in the upsampled image
x_ori = (x_up + 0.5) / factor - 0.5

# align_corners = True
# h_ori is the height in original image
# h_up is the height in the upsampled image
stride = (h_ori - 1) / (h_up - 1)
x_ori_list = []
# append the first coordinate
x_ori_list.append(0)
for i in range(1, h_up - 1):
    x_ori_list.append(0 + i * stride)
# append the last coordinate
x_ori_list.append(h_ori - 1)

参考自:
https://discuss.pytorch.org/t/what-we-should-use-align-corners-false/22663/6
https://zhuanlan.zhihu.com/p/87572724

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hali_Botebie

文中错误请不吝指正!!!!!!

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

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

打赏作者

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

抵扣说明:

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

余额充值