Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Code snippet showing how to create an equirectangular cloud image from University of Wisconsin-Madison Space Science and Engineering Center web mercator tiles, see https://ithoughthecamewithyou.com/post/improving-the-accuracy-of-the-new-catfood-earth-clouds-layer for more information
string cloudsDownloadPath = HostingEnvironment.MapPath(CloudsDownloadName);
string cloudsTransformedPath = HostingEnvironment.MapPath(CloudsTransformedName);
string cloudsWarpedPath = HostingEnvironment.MapPath(CloudsWarpedName);
string cloudsFinalPath = HostingEnvironment.MapPath(AxdCloudsHandler.CloudsPath);
string gdalFolder = HostingEnvironment.MapPath(GdalFolder);
string gdalTranslatePath = HostingEnvironment.MapPath(GdalTranslate);
string gdalWarpPath = HostingEnvironment.MapPath(GdalWarp);
// download the most recent tiles
using (Bitmap cloudImage = new Bitmap(CloudsTileDimension * CloudsTileCount, CloudsTileDimension * CloudsTileCount, PixelFormat.Format32bppArgb))
{
using (Graphics g = Graphics.FromImage(cloudImage))
{
g.CompositingMode = CompositingMode.SourceCopy;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (WebClient webClient = new WebClient())
{
for (int col = 0; col < CloudsTileCount; col++)
{
for (int row = 0; row < CloudsTileCount; row++)
{
using (Stream tileStream = webClient.OpenRead($"http://realearth.ssec.wisc.edu/products/globalir/4/{col}/{row}.png"))
{
// for future expansion, might be better to project onto a cylinder...
using (Bitmap tile = new Bitmap(tileStream))
{
int x = col * CloudsTileDimension;
int y = row * CloudsTileDimension;
g.DrawImage(tile, x, y);
}
}
}
}
}
}
cloudImage.Save(cloudsDownloadPath, ImageFormat.Png);
}
// add dimensions to image
ProcessStartInfo psiTranslate = new ProcessStartInfo();
psiTranslate.Arguments = $"-a_srs EPSG:3857 -a_ullr -20037508 20037508 20037508 -20037508 -r lanczos {cloudsDownloadPath} {cloudsTransformedPath}";
psiTranslate.CreateNoWindow = true;
psiTranslate.UseShellExecute = false;
psiTranslate.FileName = gdalTranslatePath;
psiTranslate.LoadUserProfile = false;
psiTranslate.WorkingDirectory = gdalFolder;
Process pTranslate = Process.Start(psiTranslate);
pTranslate.WaitForExit();
// warp image
ProcessStartInfo psiWarp = new ProcessStartInfo();
psiWarp.Arguments = $"-s_srs EPSG:3857 -t_srs EPSG:4326 -r lanczos -wo SOURCE_EXTRA=1000 -overwrite -te -180 -88.99999 180 88.99999 -te_srs EPSG:4326 {cloudsTransformedPath} {cloudsWarpedPath}";
psiWarp.CreateNoWindow = true;
psiWarp.UseShellExecute = false;
psiWarp.FileName = gdalWarpPath;
psiWarp.LoadUserProfile = false;
psiWarp.WorkingDirectory = gdalFolder;
Process pWarp = Process.Start(psiWarp);
pWarp.WaitForExit();
// drop lighter pixels and flip
using (Image warped = Image.FromFile(cloudsWarpedPath))
{
using (Bitmap final = new Bitmap(CloudsFinalWidth, CloudsFinalHeight, PixelFormat.Format32bppArgb))
{
using (Graphics g = Graphics.FromImage(final))
{
g.CompositingMode = CompositingMode.SourceCopy;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.FillRectangle(Brushes.Black, 0, 0, CloudsFinalWidth, CloudsFinalHeight);
g.DrawImage(warped,
new Rectangle(0, 0, CloudsFinalWidth, CloudsFinalHeight),
0, 0, warped.Width, warped.Height,
GraphicsUnit.Pixel);
// need to fill in missing area at top and bottom
FlipClouds(final, g, true);
FlipClouds(final, g, false);
}
for (int x = 0; x < final.Width; x++)
{
for (int y = 0; y < final.Height; y++)
{
Color c = final.GetPixel(x, y);
final.SetPixel(x, y, Color.FromArgb(
(int)Math.Max(c.R - ((255.0 - c.R) * CloudsPixelFactor), 0),
(int)Math.Max(c.G - ((255.0 - c.G) * CloudsPixelFactor), 0),
(int)Math.Max(c.B - ((255.0 - c.B) * CloudsPixelFactor), 0)
));
}
}
lock (AxdCloudsHandler.CloudsUpdateLock)
{
final.Save(cloudsFinalPath, ImageFormat.Jpeg);
}
}
}
// delete intermediate
if (File.Exists(cloudsWarpedPath)) { File.Delete(cloudsWarpedPath); }
if (File.Exists(cloudsTransformedPath)) { File.Delete(cloudsTransformedPath); }
if (File.Exists(cloudsDownloadPath)) { File.Delete(cloudsDownloadPath); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.