Following up on:
https://forum.arctic-sea-ice.net/index.php/topic,2591.msg214848.html#msg214848 . Not sure if this is the best thread for this, since I actually just use EZGif's website to make the GIFs once I've created the images, but it can always be moved if appropriate...
Repeating the summary from the thread above:
I do it using the imageJ API (Java code), basically by: for each day, reading in the 5 preceding days' images, converting each pixel color to a concentration value based on the Bremen key, taking the median for each pixel, then creating a new image. (Actually, the algorithm is easily changed -- 5 day median is quite conservative.)
The code is a bit of a hack, so I'll just post some snippets:
0. Make a key to convert colors to concentrations. The key was made by using the ImageJ GUI to manually pick indices corresponding to each color in the key of one particular image. (ImageJ LUT objects store pixel values as a 1d array; indices refer to that array.)
int[] concBuckets = {10, 20, 30, 40, 50, 60, 70, 80, 85, 90, 95, 99,100};
int[] indices = {14, 84, 92,104,110,105, 80,100,124,170, 79,177,174};
for (int i=0; i<concBuckets.length; i++) {
this.rgbToConc.put(
this.keyImage.getProcessor().getLut().getRGB(indices), concBuckets);
}
For each day do all of the following steps:
for (int n=0; n < this.nDays; n++) { ... }
1. Download the needed number of preceding images (e.g. five, if making a trailing 5-day median) from their URLs or get from cache if already downloaded. URLs are similar to (substitute the dates):
-
https://seaice.uni-bremen.de/data/amsr2/asi_daygrid_swath/n6250/2017/jul/Arctic/asi-AMSR2-n6250-20170731-v5_nic.png ImagePlus image = null;
String filename = this.getFilename(date, bremenVersion);
File file = new File(this.cacheDir + filename);
if (file.exists()) {
System.out.println("Loading image from file: " + this.cacheDir + filename);
image = new ImagePlus(this.cacheDir + filename);
} else {
String url = this.getUrl(date, filename);
System.out.println("Downloading image from web: " + url);
image = new ImagePlus(url);
}
2. For each preceding image, convert the colors to concentrations using the key.
int[] conc = new int[this.len];
LUT lut = ip.getLut();
byte[] pixels = (byte[]) ip.getPixels();
for (int y=0; y < ip.getHeight(); y++) {
for (int x=0; x < ip.getWidth(); x++) {
int i = x + y * ip.getWidth();
int rgb = lut.getRGB(pixels);
if (this.rgbToConc.containsKey(rgb)){
conc = Integer.parseInt(this.rgbToConc.get(rgb).toString());
} else {
conc = Integer.MAX_VALUE;
}
}
}
3. Use this set of concentrations to calculate the output values; e.g. for median (i.e. quartile = 2):
for (int i=0; i<this.len; i++) {
int filteredC = this.concentrations.get(0);
int[] values = new int[this.concentrations.size()];
for (int z=0; z<values.length; ++z) {
values[z] = this.concentrations.get(z);
}
Arrays.sort(values);
if (values.length % 2 == 0) {
throw new RuntimeException("Can't use quartile for even number of ice concentrations.");
} else {
int q1 = values.length/4; // for values.length == 5, q1 == 1 (floor of 1.25)
filteredC = values[q1*quartile];
}
this.filteredConcs = filteredC;
}
4. Finally, convert the concentrations back into RGB color values and use that as the pixel array to generate a new image.
5. Now I have a set of images, each being the (e.g.) 5-day trailing median. I just use EZGif online to convert them to an animation. To use a different algorithm, just change step 3.