双线性插值

我得到了这个通过双线性插值来缩放图像的代码。我知道这有效但我无法弄清楚如果近似像素值是边缘(通过边缘,我的意思是它在最后一行或最后一列)像素输入图像然后我可以我gt坐标(x + 1,y + 1)的像素,这应该导致数组索引超出范围错误但没有出现这样的错误为什么? 代码是:

public int[] resizeBilinearGray(int[] pixels, int w, int h, int w2, int h2) { int[] temp = new int[w2*h2] ; int A, B, C, D, x, y, index, gray ; float x_ratio = ((float)(w-1))/w2 ; float y_ratio = ((float)(h-1))/h2 ; float x_diff, y_diff, ya, yb ; int offset = 0 ; for (int i=0;i<h2;i++) { for (int j=0;j<w2;j++) { x = (int)(x_ratio * j) ; y = (int)(y_ratio * i) ; x_diff = (x_ratio * j) - x ; y_diff = (y_ratio * i) - y ; index = y*w+x ; // range is 0 to 255 thus bitwise AND with 0xff A = pixels[index] & 0xff ; B = pixels[index+1] & 0xff ; C = pixels[index+w] & 0xff ; D = pixels[index+w+1] & 0xff ; // Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh gray = (int)( A*(1-x_diff)*(1-y_diff) + B*(x_diff)*(1-y_diff) + C*(y_diff)*(1-x_diff) + D*(x_diff*y_diff) ) ; temp[offset++] = gray ; } } return temp ; } 

原因是x_ratioy_ratio计算不正确。

考虑最后一行的最后一个像素:

 i=h2, j=w2 

然后:

 x = x_ratio * j = (w-1)/w2 * (w2-1) = (w-1) * (w2-1)/w2 <= w-1 y = y_ratio * i = (h-1)/h2 * (h2-1) = (h-1) * (h2-1)/h2 <= h-1 index = y*w+x <= (h-1)*w + (w-1) < w*h 

所以索引总是小于pixels数组的大小。


但请注意,这是一个非常脏的黑客,这将导致不准确的结果,尤其是对于小图像。

你应该按如下方式计算宽度/高度比:

 float x_ratio = ((float)w)/w2; float y_ratio = ((float)h)/h2; 

并创建一个将坐标转换为数组索引的函数 - 让我们将其命名为coord2index 。 此函数将超出范围坐标考虑在内并实现所谓的边界选项 ,该选项 模拟图像边界外的像素。

边界的常见选项是:

  • 对称 - 图像边界外的像素通过镜像reflection边界处的图像来计算。 在这种情况下,这可能是最好的可能性。

  • 复制 - 假设图像边界外的像素等于边界处的最近像素。 这是最简单的方法。

  • 圆形 - 图像几乎在所有方向上周期性地重复。 用于一些先进的图像处理算法; 不适合图像大小调整。

我猜这个技巧是在x_ratio = (float)(w-1))/w2 ,它计算比例就好像原始图像比实际图像小一个像素。 但是我不确定这是否是万无一失的(我不是这样的 – 想想例如w = w2 h = h2的情况应该给出完全相同的图像)。 我真的不喜欢这种方法。