Skip to content

Instantly share code, notes, and snippets.

@FZambia
Last active December 5, 2019 18:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save FZambia/ca83c61beac90a15b4d6 to your computer and use it in GitHub Desktop.
Save FZambia/ca83c61beac90a15b4d6 to your computer and use it in GitHub Desktop.
Download Earth images from Himawari-8 satellite
// 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)
}
}
@FZambia
Copy link
Author

FZambia commented Feb 8, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment