Pixelart 的抗锯齿算法

Anti-Aliasing Algorithm for Pixelart

我有一个图像,或者 Pixelart,因为没有更好的词,非常小。它实际上只是一个大约这个大小的数字数组:new int[150][10]。我在这个数组上画直线和曲线,主要是在黑色背景上画一种颜色。它旨在稍后控制 LED-Strip。所以现在我正在寻找一种方法来消除我绘制的线条、曲线和形状的锯齿。我只想输入我的数组,有点像这样:

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;
}

同样,如果有人对我有什么好的建议,我可以研究什么样的算法,我将不胜感激。

我查看了双线性插值,正如评论中所建议的那样。这就是我想出的。当结果维度恰好是原始维度的一半时,该算法仅适用于降尺度。因为在缩小过程中丢失了很多亮度,所以我再次调亮所有像素。仍然需要一个更好的解决方案,但它现在有效。

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;
}