Pixelart的抗锯齿算法

时间:2019-05-21 01:07:58

标签: java algorithm pixel antialiasing downsampling

我有一个图像,或者说因缺乏更好的单词而缺少Pixelart,尺寸非常小。实际上,它只是一个大小约为new int[150][10]的数字数组。我在此数组上绘制直线和曲线,大部分是在黑色背景上绘制一种颜色。这意味着稍后可以控制LED灯条。因此,现在我正在寻找一种对我绘制的直线,曲线和形状进行抗锯齿的方法。我只想输入我的数组,就像这样:

int[][] antiAlias(int[][] image) {
    int[][] result = new int[image.length][image[0].length];

    // do magic here

    return result;
}

我偶然发现了Wu的抗锯齿,但据我所知,它仅用于绘制线条。如果有人能给我提示我应该寻找哪种算法,我将不胜感激。

我还读到,抗锯齿效果可以通过下采样来实现。因为对我来说,以更高的分辨率在阵列中创建直线和曲线不会有问题,所以这也可以是一种选择。但是我不知道如何执行降采样,而且我在互联网上可以找到的所有内容始终可以与Image-对象和库一起使用,这当然是没有选择的,因为我没有使用实际的图片。 我想要一个这样的下采样功能:

// scale should be power of 2 (I guess??)
int[][] downsample(int[][] image, int scale) {
    int[][] result = new int[image.length / 2][image[0].length / 2];

    // do magic here

    if (scale > 2) return downsample(result, scale / 2);
    return result;
}

同样,如果有人对我有一个好主意,我可以研究哪种算法,我将非常感谢。

1 个答案:

答案 0 :(得分:0)

正如注释中所建议的,我研究了双线性插值。这就是我想出的。仅当结果尺寸恰好是原始尺寸的一半时,该算法才适用于缩小比例。因为在缩小过程中会损失很多亮度,所以我再次使所有像素变亮。仍然需要一个更好的解决方案,但现在可以使用。

int[][] bilinearDownscale(int[][] original, int scale, boolean brighten) {
    int[][] result = new int[original.length / 2][original[0].length / 2];

    // the four pixels from which we derive our downscaled pixel
    // i = 0 -> red, i = 1 -> green, i = 2 -> blue
    int a[] = new int[3];
    int b[] = new int[3];
    int c[] = new int[3];
    int d[] = new int[3];
    for (int x = 0; x < result.length; x++) {
        for (int y = 0; y < result[0].length; y++) {

            // get the individual color values of the old pixels
            a[0] = (original[x * 2][y * 2]) >> 16 & 0xFF;
            b[0] = (original[x * 2 + 1][y * 2]) >> 16 & 0xFF;
            c[0] = (original[x * 2][y * 2 + 1]) >> 16 & 0xFF;
            d[0] = (original[x * 2 + 1][y * 2 + 1]) >> 16 & 0xFF;

            a[1] = (original[x * 2][y * 2]) >> 8 & 0xFF;
            b[1] = (original[x * 2 + 1][y * 2]) >> 8 & 0xFF;
            c[1] = (original[x * 2][y * 2 + 1]) >> 8 & 0xFF;
            d[1] = (original[x * 2 + 1][y * 2 + 1]) >> 8 & 0xFF;

            a[2] = original[x * 2][y * 2] & 0xFF;
            b[2] = original[x * 2 + 1][y * 2] & 0xFF;
            c[2] = original[x * 2][y * 2 + 1] & 0xFF;
            d[2] = original[x * 2 + 1][y * 2 + 1] & 0xFF;

            // get the individually interpolated color values
            int red = (int) (0.25 * (a[0] + b[0] + c[0] + d[0]));
            int green = (int) (0.25 * (a[1] + b[1] + c[1] + d[1]));
            int blue = (int) (0.25 * (a[2] + b[2] + c[2] + d[2]));

            // apply saturation if so desired
            if (brighten) {
                float hsb[] = Color.RGBtoHSB(red, green, blue, null);
                hsb[2] = -((hsb[2] - 1) * (hsb[2] - 1)) + 1;

                // compute the new color value
                result[x][y] = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
            } else {

                // compute the new color value
                result[x][y] = (red << 16) | (green << 8) | blue;
            }
        }
    }

    // yay recursion
    if (scale > 2) {
        return bilinearDownscale(result, scale / 2, brighten);
    }
    return result;
}