Last active
December 5, 2019 18:14
-
-
Save FZambia/ca83c61beac90a15b4d6 to your computer and use it in GitHub Desktop.
Download Earth images from Himawari-8 satellite
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
// This script downloads Earth images from Himawari-8 satellite. | |
// | |
// After all images saved you can run this to generate video with ffmpeg: | |
// | |
// ffmpeg -framerate 20 -pattern_type glob -i '*.png' -c:v libx264 -pix_fmt yuv420p video.mp4 | |
// ffmpeg -i video.mp4 -i Morning_Mood_by_Grieg.mp3 -vcodec copy -acodec copy -shortest audiovideo.mp4 | |
// ffmpeg -i audiovideo.mp4 -vf pad="ih*16/9:ih:(ow-iw)/2:(oh-ih)/2" output.mp4 | |
// | |
// Most of code here from https://github.com/avinashbot/himawari | |
package main | |
import ( | |
"bytes" | |
"fmt" | |
"image" | |
"image/draw" | |
"image/png" | |
"log" | |
"net/http" | |
"os" | |
"path/filepath" | |
"sync" | |
"time" | |
_ "image/png" // Decode PNG images from imagePath | |
) | |
const ( | |
rootFolder = "/tmp/earth" | |
startDate = "2016-01-23 00:00:00" | |
every = time.Duration(10 * time.Minute) | |
depth = 2 | |
imagePath = "http://himawari8.nict.go.jp/img/D531106/%dd/550/%s_%d_%d.png" | |
imageFormat = "2006/01/02/150405" | |
saveFormat = "20060102-150405" | |
) | |
// joinGrid the matrix of image pointers into one massive image. | |
func joinGrid(mat [][]image.Image, width, height int) image.Image { | |
dst := image.NewNRGBA(image.Rect(0, 0, width, height)) | |
var wg sync.WaitGroup | |
for i := range mat { | |
for j := range mat[i] { | |
if mat[i][j] == nil { | |
break | |
} | |
wg.Add(1) | |
go func(i, j int) { | |
defer wg.Done() | |
// Modification is performed pixel-by-pixel, so async | |
// should be fine, theoretically. | |
src := mat[i][j] | |
sdx, sdy := src.Bounds().Dx(), src.Bounds().Dy() | |
rect := image.Rect( | |
i*sdx, j*sdy, i*sdx+sdx, j*sdy+sdy, | |
) | |
draw.Draw(dst, rect, src, image.ZP, draw.Src) | |
}(i, j) | |
} | |
} | |
wg.Wait() | |
return dst | |
} | |
// Create the background at a given path. | |
func createFile(img image.Image, absPath string) error { | |
// Create the directory if it doesn't exist. | |
if err := os.MkdirAll(filepath.Dir(absPath), 0777); err != nil { | |
return err | |
} | |
// Get the handle to the file. | |
file, err := os.Create(absPath) | |
if err != nil { | |
return err | |
} | |
defer file.Close() | |
// Write the image to the file. | |
return png.Encode(file, img) | |
} | |
// gridAt returns the image at a certain row and column. | |
func gridAt(t *time.Time, depth, row, col int) (image.Image, error) { | |
// Construct the url. | |
buf := new(bytes.Buffer) | |
fmt.Fprintf(buf, imagePath, depth, t.Format(imageFormat), row, col) | |
url := buf.String() | |
// Get the image from the url. | |
res, err := http.Get(url) | |
if err != nil { | |
return nil, err | |
} | |
defer res.Body.Close() | |
// Create an image from the response. | |
img, _, err := image.Decode(res.Body) | |
return img, err | |
} | |
func saveGrid(m [][]image.Image, filename string) error { | |
// Join the pieces and set the background image. | |
// A depth=20 crashed my computer around this part, so watch out. | |
var img image.Image | |
img = joinGrid(m, 550*depth, 550*depth) | |
return createFile(img, filename) | |
} | |
func imageGrid(t *time.Time) ([][]image.Image, error) { | |
// Make the image grid. | |
m := make([][]image.Image, depth) | |
for i := range m { | |
m[i] = make([]image.Image, depth) | |
} | |
// Download images in parallel. | |
var wg sync.WaitGroup | |
var err error | |
for i := 0; i < depth; i++ { | |
for j := 0; j < depth; j++ { | |
wg.Add(1) | |
go func(i, j int) { | |
defer wg.Done() | |
m[i][j], err = gridAt(t, depth, i, j) | |
}(i, j) | |
} | |
} | |
wg.Wait() | |
if err != nil { | |
return m, err | |
} | |
return m, nil | |
} | |
func imageFileName(t *time.Time) string { | |
dir := fmt.Sprintf("earth-%s", t.Format("2006-01-02")) | |
path := filepath.Join(rootFolder, dir) | |
os.Mkdir(path, 0777) | |
return filepath.Join(path, fmt.Sprintf("earth-%s.png", t.Format(saveFormat))) | |
} | |
func download(t *time.Time) error { | |
filename := imageFileName(t) | |
if _, err := os.Stat(filename); err == nil { | |
log.Println("Image already exists, try next") | |
return nil | |
} | |
log.Println("Start downloading image grid") | |
startTime := time.Now() | |
grid, err := imageGrid(t) | |
if err != nil { | |
return err | |
} | |
log.Printf("Downloading images took %s", time.Now().Sub(startTime)) | |
err = saveGrid(grid, filename) | |
if err != nil { | |
return err | |
} | |
log.Printf("Succesfully downloaded and saved to %s", filename) | |
return nil | |
} | |
func main() { | |
t, err := time.Parse("2006-01-02 15:04:05", startDate) | |
if err != nil { | |
log.Fatalln(err) | |
} | |
for { | |
err := download(&t) | |
if err != nil { | |
log.Fatalln(err) | |
} | |
t = t.Add(every) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Video example: https://www.youtube.com/watch?v=WunH8bPPhP8