双线性插值异常
Bilinear interpolation anomaly
我写了一个函数,它获取图像的子像素以进行放大,并且子像素是通过双线性插值生成的,但是我遇到了一些奇怪的伪像。
这是我的代码:
public static int getSubPixel(BufferedImage bi, double x, double y) {
float[] topleft = new Color(bi.getRGB((int) Math.floor(x), (int) Math.floor(y))).getColorComponents(null);
float[] topright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), (int) Math.floor(y))).getColorComponents(null);
float[] bottomleft = new Color(bi.getRGB((int) Math.floor(x), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
float[] bottomright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
for (int i = 0; i < 3; i++) {
topleft[i] *= topleft[i];
topright[i] *= topright[i];
bottomleft[i] *= bottomleft[i];
bottomright[i] *= bottomright[i];
}
double decX = x % 1;
double decY = y % 1;
double inv_DecX = 1 - decX;
double inv_DecY = 1 - decY;
float red = (float) Math.sqrt((topleft[0] * inv_DecX + topright[0] * decX) * inv_DecY + (bottomleft[0] * inv_DecX + bottomright[0] * decX) * decY);
float green = (float) Math.sqrt((topleft[1] * inv_DecX + topright[1] * decX) * inv_DecY + (bottomleft[1] * inv_DecX + bottomright[1] * decX) * decY);
float blue = (float) Math.sqrt((topleft[2] * inv_DecX + topright[2] * decX) * inv_DecY + (bottomleft[2] * inv_DecX + bottomright[2] * decX) * decY);
return new Color(red, green, blue).getRGB();
}
这是将 16x16 图像放大 20 倍的结果:
如您所见,发生了奇怪的裸奔。我确实在平均之前特意对颜色进行平方,然后取结果的平方根,但这里似乎有些不对劲。有什么见解吗?
PS:我知道已经存在执行此操作的功能。这是一个教育练习。我试图通过自己做来理解这个过程。
您看到的条纹伪影是由线性插值方案引起的。您的实施是正确的(除了平方,这是不必要的并且会导致条纹在图像的较暗区域更强)。这是我看到的正确线性插值(16x 而不是 OP 中的 20x,我搞砸了)但没有平方(注意深蓝色部分的条纹较少):
如果你想去掉条纹,使用更好的插值方案,比如三次样条插值:
我写了一个函数,它获取图像的子像素以进行放大,并且子像素是通过双线性插值生成的,但是我遇到了一些奇怪的伪像。
这是我的代码:
public static int getSubPixel(BufferedImage bi, double x, double y) {
float[] topleft = new Color(bi.getRGB((int) Math.floor(x), (int) Math.floor(y))).getColorComponents(null);
float[] topright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), (int) Math.floor(y))).getColorComponents(null);
float[] bottomleft = new Color(bi.getRGB((int) Math.floor(x), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
float[] bottomright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
for (int i = 0; i < 3; i++) {
topleft[i] *= topleft[i];
topright[i] *= topright[i];
bottomleft[i] *= bottomleft[i];
bottomright[i] *= bottomright[i];
}
double decX = x % 1;
double decY = y % 1;
double inv_DecX = 1 - decX;
double inv_DecY = 1 - decY;
float red = (float) Math.sqrt((topleft[0] * inv_DecX + topright[0] * decX) * inv_DecY + (bottomleft[0] * inv_DecX + bottomright[0] * decX) * decY);
float green = (float) Math.sqrt((topleft[1] * inv_DecX + topright[1] * decX) * inv_DecY + (bottomleft[1] * inv_DecX + bottomright[1] * decX) * decY);
float blue = (float) Math.sqrt((topleft[2] * inv_DecX + topright[2] * decX) * inv_DecY + (bottomleft[2] * inv_DecX + bottomright[2] * decX) * decY);
return new Color(red, green, blue).getRGB();
}
这是将 16x16 图像放大 20 倍的结果:
如您所见,发生了奇怪的裸奔。我确实在平均之前特意对颜色进行平方,然后取结果的平方根,但这里似乎有些不对劲。有什么见解吗?
PS:我知道已经存在执行此操作的功能。这是一个教育练习。我试图通过自己做来理解这个过程。
您看到的条纹伪影是由线性插值方案引起的。您的实施是正确的(除了平方,这是不必要的并且会导致条纹在图像的较暗区域更强)。这是我看到的正确线性插值(16x 而不是 OP 中的 20x,我搞砸了)但没有平方(注意深蓝色部分的条纹较少):
如果你想去掉条纹,使用更好的插值方案,比如三次样条插值: