图像缩放——像素对齐
1. 引言
图像缩放存在于各种图像处理应用中,如图像金字塔、固定输入的卷积层、图像分割中的上采样等。本文将详细分析下图像缩放过程中像素对齐的问题:图像缩放往往是由各种图像插值方法实现的,插值点的坐标是通过将目标图像像素坐标(或叫索引)映射回源图像坐标系中计算得出(该坐标可能是浮点数,也被称为亚像素),目标图像各像素点的像素值则通过源图像中对应的插值点邻近的像素点(如最近邻插值需要最近的像素点,双线性插值则需要四个邻近像素点)来计算,插值点的位置是否精准将直接影响图像插值的精度。
本文将结合图片案例和常用图像处理库中的相关函数,以 3 × 3 → 5 × 5 3×3→5×5 3×3→5×5的图像缩放(上采样)为例,介绍几种像素对齐的方式。
2. 像素对齐方式
2.1 原点坐标对齐
原点坐标对齐的方式即为不做任何处理直接将目标图像像素坐标(或索引)缩放到源图像坐标系中。当 3 × 3 3×3 3×3的源图像上采样得到 5 × 5 5×5 5×5的目标图像,两个图像的像素点在源图像坐标系下的位置如图(a)所示,其中蓝色圆点为源图像像素点,红色菱形点为在源图像坐标系中目标图像像素点对应的插值点,可以看到两个图像的像素点在左上角原点 ( 0 , 0 ) (0,0) (0,0)处(注意图像像素坐标值是以0为原点, x x x轴的正半轴方向是水平向右, y y y轴的正半轴方向是垂直向下)是对齐的。由于此方式只在原点对齐并以其为基准,故这里称其为原点坐标对齐方式。
原点坐标对齐方式中像素点坐标缩放的公式也很好理解,由于目标图像是由源图像缩放得到的,它们之间是成比例的,故它们的像素坐标也是成比例的。以
(
s
r
c
_
x
,
s
r
c
_
y
)
(src\_x,src\_y)
(src_x,src_y)表示目标图像像素点在源图像坐标系下的坐标值(可能是浮点数),
(
d
s
t
_
x
,
d
s
t
_
y
)
(dst\_x,dst\_y)
(dst_x,dst_y)则表示目标图像像素点在目标图像坐标系下的坐标值(离散的整数),
(
s
r
c
_
h
,
s
r
c
_
w
)
(src\_h,src\_w)
(src_h,src_w)和
(
d
s
t
_
h
,
d
s
t
_
w
)
(dst\_h,dst\_w)
(dst_h,dst_w)分别表示源图像和目标图像的尺寸(高宽),则有:
s
r
c
_
x
d
s
t
_
x
=
s
r
c
_
w
d
s
t
_
w
⇒
s
r
c
_
x
=
s
r
c
_
w
d
s
t
_
w
∗
d
s
t
_
x
s
r
c
_
y
d
s
t
_
y
=
s
r
c
_
h
d
s
t
_
h
⇒
s
r
c
_
y
=
s
r
c
_
h
d
s
t
_
h
∗
d
s
t
_
y
\frac{src\_x}{dst\_x} = \frac{src\_w}{dst\_w} \space \Rightarrow \space src\_x = \frac{src\_w}{dst\_w} * dst\_x \\ \frac{src\_y}{dst\_y} = \frac{src\_h}{dst\_h} \space \Rightarrow \space src\_y = \frac{src\_h}{dst\_h} * dst\_y
dst_xsrc_x=dst_wsrc_w ⇒ src_x=dst_wsrc_w∗dst_xdst_ysrc_y=dst_hsrc_h ⇒ src_y=dst_hsrc_h∗dst_y
从上式可以看出,根据目标图像像素点在目标图像坐标系下的坐标值
d
s
t
_
x
dst\_x
dst_x和缩放系数
s
r
c
_
w
/
d
s
t
_
w
{src\_w}/{dst\_w}
src_w/dst_w即可计算出目标图像像素点在源图像坐标系下的坐标值
s
r
c
_
x
src\_x
src_x,即插值点的坐标值。
2.2 角点坐标对齐
从图(a)知道在上采样中原点坐标对齐方式只对齐了左上角原点,目标图像像素点位置可能在源图像之外,出现这种现象的原因是缩放系数不准确:以图像的宽为例(高同理),实际上图像的宽是图像水平方向上像素点的个数,但在数值坐标系中,图像像素点坐标值的是非负整数,其取值范围为
[
0
,
s
r
c
_
w
−
1
]
[0,src\_w - 1]
[0,src_w−1]或
[
0
,
d
s
t
_
w
−
1
]
[0,dst\_w - 1]
[0,dst_w−1],坐标系中图像实际的宽(图像左右角点的长度,高维图像上下角点的长度)应是
s
r
c
_
w
−
1
src\_w - 1
src_w−1或
d
s
t
_
w
−
1
dst\_w- 1
dst_w−1,因此原点坐标对齐方式中使用缩放系数
s
r
c
_
w
/
d
s
t
_
w
{src\_w}/{dst\_w}
src_w/dst_w或
s
r
c
_
h
/
d
s
t
_
h
{src\_h}/{dst\_h}
src_h/dst_h会使计算出的坐标值偏大,准确的缩放系数应为
(
s
r
c
_
w
−
1
)
/
(
d
s
t
_
w
−
1
)
(src\_w - 1) / (dst\_w - 1)
(src_w−1)/(dst_w−1)或
(
s
r
c
_
h
−
1
)
/
(
d
s
t
_
h
−
1
)
(src\_h- 1 )/(dst\_h-1)
(src_h−1)/(dst_h−1),此时可得缩放关系式为:
s
r
c
_
x
d
s
t
_
x
=
s
r
c
_
w
−
1
d
s
t
_
w
−
1
⇒
s
r
c
_
x
=
s
r
c
_
w
−
1
d
s
t
_
w
−
1
∗
d
s
t
_
x
s
r
c
_
y
d
s
t
_
y
=
s
r
c
_
h
−
1
d
s
t
_
h
−
1
⇒
s
r
c
_
y
=
s
r
c
_
h
−
1
d
s
t
_
h
−
1
∗
d
s
t
_
y
\frac{src\_x}{dst\_x} = \frac{src\_w - 1}{dst\_w - 1} \space \Rightarrow \space src\_x = \frac{src\_w - 1}{dst\_w - 1} * dst\_x \\ \frac{src\_y}{dst\_y} = \frac{src\_h - 1}{dst\_h - 1} \space \Rightarrow \space src\_y = \frac{src\_h - 1}{dst\_h - 1} * dst\_y
dst_xsrc_x=dst_w−1src_w−1 ⇒ src_x=dst_w−1src_w−1∗dst_xdst_ysrc_y=dst_h−1src_h−1 ⇒ src_y=dst_h−1src_h−1∗dst_y
根据上式计算得到的结果如图(b)所示,此时可以看到,在源图像坐标系下,目标图像的四个角的像素点与源图像的四个角的像素点是一一对齐的,目标图像像素点均在源图像内。
换个角度理解,其实也可以由原点坐标对齐的结果进一步得出角点坐标对齐的结果,即将通过原点坐标对齐方式得到的结果先归一化,再放大至源图像坐标范围内:
m
a
x
(
s
r
c
_
x
)
=
s
r
c
_
w
d
s
t
_
w
∗
(
d
s
t
_
w
−
1
)
⇒
s
r
c
_
x
=
s
r
c
_
w
d
s
t
_
w
∗
d
s
t
_
x
s
r
c
_
w
d
s
t
_
w
∗
(
d
s
t
_
w
−
1
)
∗
(
s
r
c
_
w
−
1
)
=
s
r
c
_
w
−
1
d
s
t
_
w
−
1
∗
d
s
t
_
x
m
a
x
(
s
r
c
_
y
)
=
s
r
c
_
h
d
s
t
_
h
∗
(
d
s
t
_
h
−
1
)
⇒
s
r
c
_
y
=
s
r
c
_
h
d
s
t
_
h
∗
d
s
t
_
y
s
r
c
_
h
d
s
t
_
h
∗
(
d
s
t
_
h
−
1
)
∗
(
s
r
c
_
h
−
1
)
=
s
r
c
_
h
−
1
d
s
t
_
h
−
1
∗
d
s
t
_
y
max(src\_x) = \frac{src\_w}{dst\_w} * (dst\_w - 1) \space \Rightarrow \space src\_x = \frac{\frac{src\_w}{dst\_w} * dst\_x}{\frac{src\_w}{dst\_w} * (dst\_w - 1)} * (src\_w - 1) = \frac{src\_w - 1}{dst\_w - 1} * dst\_x \\ max(src\_y) = \frac{src\_h}{dst\_h} * (dst\_h - 1) \space \Rightarrow \space src\_y = \frac{\frac{src\_h}{dst\_h} * dst\_y}{\frac{src\_h}{dst\_h} * (dst\_h - 1)} * (src\_h - 1) = \frac{src\_h - 1}{dst\_h - 1} * dst\_y
max(src_x)=dst_wsrc_w∗(dst_w−1) ⇒ src_x=dst_wsrc_w∗(dst_w−1)dst_wsrc_w∗dst_x∗(src_w−1)=dst_w−1src_w−1∗dst_xmax(src_y)=dst_hsrc_h∗(dst_h−1) ⇒ src_y=dst_hsrc_h∗(dst_h−1)dst_hsrc_h∗dst_y∗(src_h−1)=dst_h−1src_h−1∗dst_y
2.3 图像中心对齐
下面将介绍图像中心对齐的方式,顾名思义,此方式的目的就是在源图像坐标系下使目标图像与源图像的中心点对齐。原点坐标对齐的方式是以左上角的原点作为基准计算各像素点的坐标值的,目标图像与源图像虽然在左上角是重合的,但由于尺寸不一,整体重心偏左上,是不对称的,从图(a)就可看出在源图像右边界和底边界外仍然有目标图像像素点,这些像素点的处理会对目标图像右边界处和底边界处像素的计算有较大的影响。图像中心对齐方式的计算思路也很简单:将像素点看作是一个单位正方形区域,以该区域的中心点作为其坐标,例如原点
(
0
,
0
)
(0, 0)
(0,0)表示的区域如图(c)中的阴影部分所示,该设置下原点像素区域的中心坐标应为
(
0.5
,
0.5
)
(0.5,0.5)
(0.5,0.5),以此类推,对任意目标像素坐标
(
d
s
t
_
x
,
d
s
t
_
y
)
(dst\_x,dst\_y)
(dst_x,dst_y),其以区域表示的像素中心坐标应为
(
d
s
t
_
x
+
0.5
,
d
s
t
_
y
+
0.5
)
(dst\_x+0.5,dst\_y+0.5)
(dst_x+0.5,dst_y+0.5),图像中心对齐方式的思想就是要想使两个图像几何中心对齐,那就需要使像素区域中心点对齐(中心点坐标成缩放比例),则可得到该目标像素对应在源图像上的像素中心坐标为
(
(
d
s
t
_
x
+
0.5
)
∗
s
r
c
_
w
d
s
t
_
w
,
(
d
s
t
_
y
+
0.5
)
∗
s
r
c
_
h
d
s
t
_
h
)
((dst\_x+0.5)*\frac{src\_w}{dst\_w},(dst\_y + 0.5)*\frac{src\_h}{dst\_h})
((dst_x+0.5)∗dst_wsrc_w,(dst_y+0.5)∗dst_hsrc_h),最后得到其在源图像坐标系下以点表示的实际像素坐标为
(
(
d
s
t
_
x
+
0.5
)
∗
s
r
c
_
w
d
s
t
_
w
−
0.5
,
(
d
s
t
_
y
+
0.5
)
∗
s
r
c
_
h
d
s
t
_
h
−
0.5
)
((dst\_x+0.5)*\frac{src\_w}{dst\_w}-0.5,(dst\_y + 0.5)*\frac{src\_h}{dst\_h}-0.5)
((dst_x+0.5)∗dst_wsrc_w−0.5,(dst_y+0.5)∗dst_hsrc_h−0.5)。整体的缩放关系可表示如下:
s
r
c
_
x
+
0.5
d
s
t
_
x
+
0.5
=
s
r
c
_
w
d
s
t
_
w
⇒
s
r
c
_
x
=
s
r
c
_
w
d
s
t
_
w
∗
(
d
s
t
_
x
+
0.5
)
−
0.5
s
r
c
_
y
+
0.5
d
s
t
_
y
+
0.5
=
s
r
c
_
h
d
s
t
_
h
⇒
s
r
c
_
y
=
s
r
c
_
h
d
s
t
_
h
∗
(
d
s
t
_
y
+
0.5
)
−
0.5
\frac{src\_x + 0.5}{dst\_x + 0.5} = \frac{src\_w}{dst\_w} \space \Rightarrow \space src\_x = \frac{src\_w}{dst\_w} * (dst\_x + 0.5) - 0.5 \\ \frac{src\_y + 0.5}{dst\_y + 0.5} = \frac{src\_h}{dst\_h} \space \Rightarrow \space src\_y = \frac{src\_h}{dst\_h} * (dst\_y + 0.5) - 0.5
dst_x+0.5src_x+0.5=dst_wsrc_w ⇒ src_x=dst_wsrc_w∗(dst_x+0.5)−0.5dst_y+0.5src_y+0.5=dst_hsrc_h ⇒ src_y=dst_hsrc_h∗(dst_y+0.5)−0.5
上式计算的结果如图(c)所示,可明显看出两个图像在中心点处对齐,整体也是对称的,源图像各个边界外具有等量的目标图像像素点,这些像素点到边界的距离较原点坐标对齐方式减少了,在各个边界处是均匀的。插值前可能需要将这些像素裁剪至源图像区域内,裁剪后的结果如图(d)所示,当然也可以不裁剪,例如OpenCV库里是通过边界模式(如border_mode=cv2.BORDER_REFLECTION)来处理边界外的像素点。
关于图像中心对齐方式中的缩放关系式,还有另外一种理解角度[参考自此]:首先将上面的缩放关系式进一步推导为下面的形式,可以认为此时的公式是原点坐标对齐缩放关系式(
s
r
c
_
x
=
s
r
c
_
w
d
s
t
_
w
∗
d
s
t
_
x
src\_x = \frac{src\_w}{dst\_w} * dst\_x
src_x=dst_wsrc_w∗dst_x)加上了一个偏移控制项(
0.5
∗
(
s
r
c
_
w
d
s
t
_
w
−
1
)
0.5 * (\frac{src\_w}{dst\_w} - 1)
0.5∗(dst_wsrc_w−1)),对于图像上采样,缩放系数
s
r
c
_
w
d
s
t
_
w
\frac{src\_w}{dst\_w}
dst_wsrc_w或
s
r
c
_
h
d
s
t
_
h
\frac{src\_h}{dst\_h}
dst_hsrc_h将会是小于1的,从而可得到偏移控制项是小于0的,所以计算得出的插值点坐标将会向左上偏移,对比图(a)和图(c)即可清晰地看出,目标图像像素点在源图像坐标系下的位置往左上偏移从而达到图像中心对齐;对于图像下采样,偏移控制项则会是正值,从而目标图像会往右下偏移,以控制图像中心对齐。
s
r
c
_
x
=
s
r
c
_
w
d
s
t
_
w
∗
(
d
s
t
_
x
+
0.5
)
−
0.5
⇒
s
r
c
_
x
=
s
r
c
_
w
d
s
t
_
w
∗
d
s
t
_
x
+
0.5
∗
(
s
r
c
_
w
d
s
t
_
w
−
1
)
s
r
c
_
y
=
s
r
c
_
h
d
s
t
_
h
∗
(
d
s
t
_
y
+
0.5
)
−
0.5
⇒
s
r
c
_
y
=
s
r
c
_
h
d
s
t
_
h
∗
d
s
t
_
y
+
0.5
∗
(
s
r
c
_
h
d
s
t
_
h
−
1
)
src\_x = \frac{src\_w}{dst\_w} * (dst\_x + 0.5) - 0.5 \space \Rightarrow \space src\_x = \frac{src\_w}{dst\_w} * dst\_x + 0.5 * (\frac{src\_w}{dst\_w} - 1) \\ src\_y = \frac{src\_h}{dst\_h} * (dst\_y + 0.5) - 0.5 \space \Rightarrow \space src\_y = \frac{src\_h}{dst\_h} * dst\_y + 0.5 * (\frac{src\_h}{dst\_h} - 1)
src_x=dst_wsrc_w∗(dst_x+0.5)−0.5 ⇒ src_x=dst_wsrc_w∗dst_x+0.5∗(dst_wsrc_w−1)src_y=dst_hsrc_h∗(dst_y+0.5)−0.5 ⇒ src_y=dst_hsrc_h∗dst_y+0.5∗(dst_hsrc_h−1)
3. 主流图像处理库使用的像素对齐方式
图像处理库 | 函数 | 像素对齐方式 | 备注 |
---|---|---|---|
OpenCV | cv2.resize | 图像中心对齐 | 边界模式应该是默认为 border_mode=cv2.BORDER_REFLECTION |
cv2.warpAffine | 原点坐标对齐 | 可设置边界模式(border_mode)参数 | |
PIL | resize | 原点坐标对齐 | |
Scikit-image | 图像中心对齐 | ||
Pytorch | torch.nn.Upsample(align_corners=False) | 图像中心对齐 | 主要通过align_corners参数控制对齐方式 |
torch.nn.Upsample(align_corners=True) | 角点坐标对齐 | ||
TensorFlow | tf.image.resize_bilinear(align_corners=False) | 原点坐标对齐 | 主要通过align_corners参数控制对齐方式 |
tf.image.resize_bilinear(align_corners=True) | 角点坐标对齐 |