Last active
February 23, 2016 00:44
Download and stitch together images from the Himawari8 satellite and create a movie from them. https://en.wikipedia.org/wiki/Himawari_8
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
#!/usr/bin/env python | |
# Easy Combine output movies | |
# ls -tr himawari8_*.mp4 | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy FullMovie.mp4 | |
# Requirements | |
# brew install libtiff libjpeg webp little-cms2 ffmpeg | |
# pip install Pillow | |
import datetime | |
import json | |
import urllib2 | |
import io | |
import cStringIO | |
import sys | |
import math | |
import argparse | |
from PIL import Image | |
from PIL import ImageFont | |
from PIL import ImageDraw | |
from subprocess import call | |
# Parameters | |
latestInfoUri = "http://himawari8-dl.nict.go.jp/himawari8/img/D531106/latest.json" | |
width = 550 | |
numblocks = 4 #can be 4, 8, 16, 20 | |
def urlForTime(urlTime): | |
timeString = urlTime.strftime('%Y/%m/%d/%H%M%S') | |
level = "%sd" % numblocks | |
url = "http://himawari8-dl.nict.go.jp/himawari8/img/D531106/%s/%s/%s" % (level, width, timeString) | |
return url | |
def getLatestURL(): | |
response = json.load(urllib2.urlopen(latestInfoUri)) | |
latest = datetime.datetime.strptime(response['date'], '%Y-%m-%d %H:%M:%S'); | |
return urlForTime(latest) | |
def downloadImagesFromURL(url): | |
images = [[0 for x in range(numblocks)] for x in range(numblocks)] | |
for y in range(0, numblocks): | |
for x in range(0, numblocks): | |
imageName = "%s_%s.png" % (x, y) | |
tileURL = "%s_%s" % (url, imageName) | |
print "\t%s" % tileURL | |
data = urllib2.urlopen(tileURL).read() | |
file = cStringIO.StringIO(data) | |
image = Image.open(file) | |
images[x][y] = image | |
return images | |
def stitchImages(images, path, name, dateString): | |
fullImage = Image.new("RGB", (numblocks * width, numblocks * width)); | |
for y in range(0, numblocks): | |
for x in range(0, numblocks): | |
img = images[x][y] | |
w, h = img.size | |
fullImage.paste(img, (x * w, y * h)) | |
draw = ImageDraw.Draw(fullImage) | |
font = ImageFont.truetype("/Library/Fonts/AvenirNextLTW04-Thin.ttf", 48) | |
# font = ImageFont.load_default().font | |
draw.text((5, (width * numblocks - 60)),dateString,(255,255,255),font=font) | |
fullImage.save("%s/%s.png" % (path, name)) | |
def timeStamps(startTime): | |
times = [] | |
# timestamp = startTime - datetime.timedelta(minutes=startTime.minute % 10, seconds=startTime.second, microseconds=startTime.microsecond) | |
timestamp = startTime.replace(hour=14, minute=50, second=0, microsecond=0) | |
# timestamp = timestamp - datetime.timedelta(days=1) | |
times.append(timestamp) | |
for i in range(0, 143): | |
timestamp = timestamp - datetime.timedelta(minutes=10) | |
times.append(timestamp) | |
return times | |
def yesterdaysTimestamps(): | |
times = [] | |
timestamp = datetime.datetime.now().replace(hour=14, minute=50, second=0, microsecond=0) | |
timestamp = timestamp - datetime.timedelta(days=1) | |
times.append(timestamp) | |
for i in range(0, 143): | |
timestamp = timestamp - datetime.timedelta(minutes=10) | |
times.append(timestamp) | |
return times | |
def generateMovie(dateString, baseImageName, outputDir): | |
movieName = "himawari8_%s.mp4" % dateString | |
print "Generating movie: %s" % movieName | |
ffmpegImageFilter = "%s_%%d.png" % baseImageName | |
ffmpegOutputFile = "%s%s" % (outputDir, movieName) | |
print ffmpegImageFilter | |
print ffmpegOutputFile | |
call(['ffmpeg', '-f', 'image2', '-framerate', '15', '-i', ffmpegImageFilter, '-vcodec', 'mpeg4', '-y', ffmpegOutputFile]) | |
# http://stackoverflow.com/questions/1927660/compare-two-images-the-python-linux-way | |
def allTilesMatch(images): | |
rms = 0.0 | |
h1 = images[0][0].histogram() | |
for x in range(0, len(images)): | |
for y in range(0, len(images[x])): | |
h2 = images[x][y].histogram() | |
if (len(h1) == len(h2)): | |
diff_squares = [(h1[i] - h2[i]) ** 2 for i in xrange(len(h1))]; rms = math.sqrt(sum(diff_squares) / len(h1)); | |
rms += math.sqrt(sum(diff_squares) / len(h1)) | |
else: | |
rms += 1 | |
return rms < 1 | |
def outputHeader(): | |
print "Generating movie of himawari8 images" | |
print "Block Count: %s" % numblocks | |
print "Tile Size : %sx%s" % (width, width) | |
print "Full Size : %sx%s" % (width * numblocks, width * numblocks) | |
print "----------------------------------------" | |
def main(startTime, currentIndex, outputDir): | |
outputHeader() | |
startTimestamp = datetime.datetime.strptime(startTime, '%Y-%m-%d') | |
timestamps = timeStamps(startTimestamp) | |
# timestamps = yesterdaysTimestamps() | |
startTimeString = startTimestamp.strftime('%Y%m%d%H%M%S') | |
baseName = 'Image' | |
movieDateString = timestamps[-1].strftime('%Y-%m-%d') | |
for (index, timestamp) in enumerate(reversed(timestamps)): | |
if (index >= currentIndex): | |
start = datetime.datetime.now() | |
imageName = '%s_%d' % (baseName, currentIndex) | |
print 'Processing %s' % (imageName) | |
sys.stdout.flush() | |
url = urlForTime(timestamp) | |
images = downloadImagesFromURL(url) | |
if allTilesMatch(images): | |
print "------------------------------------------" | |
print "----- No Image Found! -----" | |
print "----- Moving to next time frame and -----" | |
print "----- fetching image into same index -----" | |
print "------------------------------------------" | |
continue | |
dateString = timestamp.strftime('%Y-%m-%d %H:%M:%S') | |
stitchImages(images, outputDir, imageName, dateString) | |
done = datetime.datetime.now() | |
print "\t----- %s -----" % (done - start) | |
currentIndex += 1 | |
generateMovie(movieDateString, baseName, outputDir) | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-l", "--length", nargs=1, type=int, help="number of images to use (defaults to 144 i.e. 24 hours)", default=[144]) | |
parser.add_argument("-d", "--day", help="day to get images for (defaults to most recent)", action="store", default=datetime.datetime.now().replace(hour=14, minute=50, second=0, microsecond=0).strftime('%Y-%m-%d')) | |
parser.add_argument("-i", "--index", nargs=1, type=int, help="starting index, for resuming failed run. (in-progress)", default=[0]) | |
# parser.add_argument("-n", "--numblocks", nargs=1, type=int, choices=[4,8,16,20], help="number of blocks larger takes longer (default: 4)", default=[4]) | |
# parser.add_argument("-w", "--width", nargs=1, type=int, help="width of individual tiles (numblocks * width = final movie width) (default: 550)", default=[550]) | |
parser.add_argument("outputDir", help="directory to place images and movie") | |
args = parser.parse_args() | |
# width = args.width[0] | |
# numblocks = args.numblocks[0] | |
outputDir = args.outputDir | |
if outputDir.endswith('/') == False: | |
outputDir += '/' | |
if (args.day == datetime.datetime.now().replace(hour=14, minute=50, second=0, microsecond=0).strftime('%Y-%m-%d')): | |
timestamp = datetime.datetime.strptime(args.day, '%Y-%m-%d') | |
timestamp = timestamp - datetime.timedelta(days=1) | |
args.day = timestamp.strftime('%Y-%m-%d') | |
else: | |
timestamp = datetime.datetime.strptime(args.day, '%Y-%m-%d') | |
timestamp = timestamp + datetime.timedelta(days=1) | |
args.day = timestamp.strftime('%Y-%m-%d') | |
main(args.day, args.index[0], outputDir) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment