0.5像素对齐的问题
1. 问题提出
在进行图像缩放时,偶尔会看到一些比较奇怪的代码,其中有一个就是0.5像素中心对齐的问题,例如在OpenCV线性插值的代码中有类似如下操作(非源码,只是举例):
// 实际代码
int x=(i+0.5)*m/a-0.5;
int y=(j+0.5)*n/b-0.5;
// 公式计算
int x=i*m/a
int y=j*n/b
2. 原因分析
为什么要先加0.5又减去0.5呢?之前一直认为只是简单的取整操作,后来多次遇到,于是深入分析了一下,才发现原因:
在进行双线性插值的时候,通常情况下图像的原点都选在了左上角,即左上角像素的左上角,但实际访问的时候,((0,0))却代表了第一个像素的值。那么对像素访问的可以按照如下方式来理解。当访问像素((i,j))的时候,实际上获取的是以((i,j))为左上角坐标原点的一个像素的值,即实际取值点与对应坐标点有一定偏差。平常使用的时候没问题,但是当进行图像缩放的时候,便会出现一些差异,例如:
把一个(5 imes 5)图像缩放到(3 imes3)大小,那么我们看像素对应关系,只看第一行:
(I_(x,y))
[I_{3 imes3}(0,0) = I_{5 imes5} (0,0)\I_{3 imes3}(1,0) = I_{5 imes5} (frac{5}{3},0)
\I_{3 imes3}(2,0) = I_{5 imes5} (frac{10}{3},0)
]
由于(I_{3 imes3} ,I_{5 imes5})的一个像素的大小是相同的,坐标表示的像素左上角的起始位置,那么可以得到如下示意图:
可以看到,按照这种情况,两张图并不是中心对齐的,实际会片左上角。那么如何解决这个问题呢:
[x'= (x+0.5)*s-0.5\y' =(y+0.5)*s-0.5
]
即在计算缩放坐标前先加上((0.5,0.5))取中心点坐标,再乘以变换系数,然后再变换回左上角坐标,即减去((0.5,0.5)).
[I_{3 imes3}(0,0) = I_{5 imes5} (frac{1}{3},0)\I_{3 imes3}(1,0) = I_{5 imes5} (2,0)\I_{3 imes3}(2,0) = I_{5 imes5} (frac{11}{3},0)
]
其基本原理就是先获取像素中心的坐标,再对该坐标进行缩放,之后再获取变换后像素左上角位置坐标。