java - 双线性插值异常

标签 java image-processing interpolation linear-interpolation

我编写了一个函数,它采用图像的子像素来进行放大,并且子像素是通过双线性插值生成的,但我遇到了一些奇怪的伪影。

这是我的代码:

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 倍的结果: original image

upscaled image

如您所见,出现了奇怪的裸奔现象。我确实在平均之前特意对颜色进行了平方,然后取结果的平方根,但这里似乎有些不对劲。有什么见解吗?

PS:我知道已经存在可以执行此操作的函数。这是一项教育 Activity 。我试图通过自己的实践来理解这个过程。

最佳答案

您看到的条纹伪影是由线性插值方案引起的。您的实现是正确的(除了平方之外,这是不必要的并且会导致图像的较暗区域中的条纹更强)。这就是我在正确的线性插值(16x 而不是 OP 中的 20x,我犯了错误)中看到的结果,但没有平方(注意深蓝色部分中的条纹较少):

linear interpolated image

如果你想消除条纹,请使用更好的插值方案,例如三次样条插值:

cubic spline interpolated image

关于java - 双线性插值异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54844310/

相关文章:

Java:使用反射调用方法时如何获得完整的失败跟踪?

java - 为什么不使用枚举?

c# - 计算量大导致栈溢出错误

javascript - 确定 Canvas 插值的步骤数

math - 超过两点的 Slerp

java - 如何翻译 ARCore 和 Sceneform 中的对象?

java - onClickListener 没有被第二次调用 Android

java - 在 Scala 中开发图像处理 DSL - 建议库

python - 使用 OpenCV 的 Python 中的最小过滤器

python - 用其前后值之间的线性插值替换 numpy 数组中的零