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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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