I have an Image, or Pixelart for lack of better word, of very small size. It is actually just an array of numbers of around this size: new int[150][10]
. I draw lines and curves on this array, mostly one colour on a black background. It is meant to control an LED-Strip later on. So now I am searching for a method to antialias the lines, curves and shapes I draw. I just want to input my array, kind of like this:
int[][] antiAlias(int[][] image) {
int[][] result = new int[image.length][image[0].length];
// do magic here
return result;
}
I have stumbled across Wu's antialiasing, but as far as I can tell it's only for drawing lines. I would really appreciate if someone could give me a hint as to what kind of algorithm I should look for.
I also read that the antialias-effect can be achieved with downsampling. As it would be no problem for me to create the lines and curves in an array with higher resolution, this could also be an option. But I don't have any idea how to perform downsampling, and everything I can find on the internet about it always works with Image
- Objects and uses libraries, which is of course no option since I am not using an actual image.
I would like a downsampling function like this:
// 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;
}
Again, if anyone has a good idea for me what kind of algorithms I could look into, I would very much appreciate it.
I looked at bilinear interpolation, just as suggested in the comments. This is what I came up with. The algorithm works only for downscaling when the results dimensions are exactly the half of the original. Because a lot of brightness gets lost during the downscaling process, I brighten all pixels up again. Still need a better solution for that, but it works for now.
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;
}